From 5d91dbb6676bbae79b3a308b0bb13d8bd5696077 Mon Sep 17 00:00:00 2001 From: Ian Keane Date: Mon, 20 Jan 2020 14:13:08 -0500 Subject: [PATCH] sbcl stuff --- README.md | 1 + quicklisp.lisp | 1757 ++++ sbcl/.quicklisp/asdf.lisp | 4516 ++++++++++ sbcl/.quicklisp/client-info.sexp | 28 + .../archives/alexandria-20191227-git.tgz | Bin 0 -> 53842 bytes .../dists/quicklisp/archives/slime-v2.24.tgz | Bin 0 -> 813432 bytes .../archives/split-sequence-v2.0.0.tgz | Bin 0 -> 10329 bytes .../trivial-gray-streams-20181018-git.tgz | Bin 0 -> 8024 bytes .../quicklisp/archives/usocket-0.8.3.tgz | Bin 0 -> 85851 bytes .../quicklisp/archives/vom-20160825-git.tgz | Bin 0 -> 4286 bytes .../dists/quicklisp/archives/yason-v0.7.8.tgz | Bin 0 -> 27918 bytes sbcl/.quicklisp/dists/quicklisp/distinfo.txt | 7 + sbcl/.quicklisp/dists/quicklisp/enabled.txt | 0 .../installed/releases/alexandria.txt | 1 + .../quicklisp/installed/releases/slime.txt | 1 + .../installed/releases/split-sequence.txt | 1 + .../releases/trivial-gray-streams.txt | 1 + .../quicklisp/installed/releases/usocket.txt | 1 + .../quicklisp/installed/releases/vom.txt | 1 + .../quicklisp/installed/releases/yason.txt | 1 + .../installed/systems/alexandria-tests.txt | 1 + .../installed/systems/alexandria.txt | 1 + .../installed/systems/split-sequence.txt | 1 + .../quicklisp/installed/systems/swank.txt | 1 + .../systems/trivial-gray-streams-test.txt | 1 + .../systems/trivial-gray-streams.txt | 1 + .../installed/systems/usocket-server.txt | 1 + .../installed/systems/usocket-test.txt | 1 + .../quicklisp/installed/systems/usocket.txt | 1 + .../dists/quicklisp/installed/systems/vom.txt | 1 + .../quicklisp/installed/systems/yason.txt | 1 + .../.quicklisp/dists/quicklisp/preference.txt | 1 + sbcl/.quicklisp/dists/quicklisp/releases.cdb | Bin 0 -> 515221 bytes sbcl/.quicklisp/dists/quicklisp/releases.txt | 1831 ++++ .../software/alexandria-20191227-git/.boring | 13 + .../alexandria-20191227-git/.gitignore | 4 + .../software/alexandria-20191227-git/AUTHORS | 9 + .../software/alexandria-20191227-git/LICENCE | 37 + .../software/alexandria-20191227-git/README | 52 + .../alexandria-tests.asd | 11 + .../alexandria-20191227-git/alexandria.asd | 62 + .../alexandria-20191227-git/arrays.lisp | 18 + .../alexandria-20191227-git/binding.lisp | 90 + .../alexandria-20191227-git/conditions.lisp | 91 + .../alexandria-20191227-git/control-flow.lisp | 106 + .../alexandria-20191227-git/definitions.lisp | 37 + .../alexandria-20191227-git/doc/.gitignore | 3 + .../alexandria-20191227-git/doc/Makefile | 28 + .../doc/alexandria.texinfo | 277 + .../doc/docstrings.lisp | 881 ++ .../alexandria-20191227-git/features.lisp | 14 + .../alexandria-20191227-git/functions.lisp | 161 + .../alexandria-20191227-git/hash-tables.lisp | 101 + .../software/alexandria-20191227-git/io.lisp | 172 + .../alexandria-20191227-git/lists.lisp | 367 + .../alexandria-20191227-git/macros.lisp | 370 + .../alexandria-20191227-git/numbers.lisp | 295 + .../alexandria-20191227-git/package.lisp | 243 + .../alexandria-20191227-git/sequences.lisp | 555 ++ .../alexandria-20191227-git/strings.lisp | 6 + .../alexandria-20191227-git/symbols.lisp | 65 + .../alexandria-20191227-git/tests.lisp | 2047 +++++ .../alexandria-20191227-git/types.lisp | 137 + .../quicklisp/software/slime-v2.24/.gitref | 1 + .../software/slime-v2.24/.travis.yml | 41 + .../software/slime-v2.24/CONTRIBUTING.md | 153 + .../quicklisp/software/slime-v2.24/Makefile | 113 + .../dists/quicklisp/software/slime-v2.24/NEWS | 609 ++ .../quicklisp/software/slime-v2.24/PROBLEMS | 94 + .../quicklisp/software/slime-v2.24/README.md | 78 + .../software/slime-v2.24/contrib/Makefile | 92 + .../software/slime-v2.24/contrib/README.md | 14 + .../software/slime-v2.24/contrib/bridge.el | 472 + .../slime-v2.24/contrib/inferior-slime.el | 133 + .../slime-v2.24/contrib/slime-asdf.el | 313 + .../slime-v2.24/contrib/slime-autodoc.el | 216 + .../slime-v2.24/contrib/slime-banner.el | 35 + .../contrib/slime-buffer-streams.el | 36 + .../slime-v2.24/contrib/slime-c-p-c.el | 305 + .../slime-v2.24/contrib/slime-cl-indent.el | 1821 ++++ .../slime-v2.24/contrib/slime-clipboard.el | 172 + .../contrib/slime-compiler-notes-tree.el | 184 + .../contrib/slime-editing-commands.el | 183 + .../contrib/slime-enclosing-context.el | 226 + .../contrib/slime-fancy-inspector.el | 42 + .../slime-v2.24/contrib/slime-fancy-trace.el | 68 + .../slime-v2.24/contrib/slime-fancy.el | 38 + .../contrib/slime-fontifying-fu.el | 231 + .../slime-v2.24/contrib/slime-fuzzy.el | 604 ++ .../contrib/slime-highlight-edits.el | 81 + .../slime-v2.24/contrib/slime-hyperdoc.el | 48 + .../slime-v2.24/contrib/slime-indentation.el | 31 + .../contrib/slime-listener-hooks.el | 11 + .../slime-v2.24/contrib/slime-macrostep.el | 129 + .../slime-v2.24/contrib/slime-mdot-fu.el | 31 + .../slime-v2.24/contrib/slime-media.el | 46 + .../slime-v2.24/contrib/slime-mrepl.el | 150 + .../slime-v2.24/contrib/slime-package-fu.el | 320 + .../slime-v2.24/contrib/slime-parse.el | 358 + .../contrib/slime-presentation-streams.el | 18 + .../contrib/slime-presentations.el | 872 ++ .../slime-v2.24/contrib/slime-quicklisp.el | 51 + .../slime-v2.24/contrib/slime-references.el | 156 + .../slime-v2.24/contrib/slime-repl.el | 1770 ++++ .../slime-v2.24/contrib/slime-sbcl-exts.el | 34 + .../slime-v2.24/contrib/slime-scheme.el | 40 + .../slime-v2.24/contrib/slime-scratch.el | 48 + .../slime-v2.24/contrib/slime-snapshot.el | 34 + .../slime-v2.24/contrib/slime-sprof.el | 224 + .../slime-v2.24/contrib/slime-trace-dialog.el | 837 ++ .../slime-v2.24/contrib/slime-tramp.el | 121 + .../contrib/slime-typeout-frame.el | 92 + .../slime-v2.24/contrib/slime-xref-browser.el | 99 + .../slime-v2.24/contrib/swank-arglists.lisp | 1620 ++++ .../slime-v2.24/contrib/swank-asdf.lisp | 541 ++ .../contrib/swank-buffer-streams.lisp | 39 + .../slime-v2.24/contrib/swank-c-p-c.lisp | 298 + .../slime-v2.24/contrib/swank-clipboard.lisp | 71 + .../contrib/swank-fancy-inspector.lisp | 1006 +++ .../slime-v2.24/contrib/swank-fuzzy.lisp | 706 ++ .../slime-v2.24/contrib/swank-goo.goo | 995 +++ .../slime-v2.24/contrib/swank-hyperdoc.lisp | 18 + .../slime-v2.24/contrib/swank-ikarus.ss | 86 + .../contrib/swank-indentation.lisp | 140 + .../software/slime-v2.24/contrib/swank-jolt.k | 998 +++ .../slime-v2.24/contrib/swank-kawa.scm | 2504 ++++++ .../slime-v2.24/contrib/swank-larceny.scm | 176 + .../contrib/swank-listener-hooks.lisp | 91 + .../slime-v2.24/contrib/swank-macrostep.lisp | 227 + .../slime-v2.24/contrib/swank-media.lisp | 25 + .../slime-v2.24/contrib/swank-mit-scheme.scm | 870 ++ .../slime-v2.24/contrib/swank-mlworks.sml | 348 + .../slime-v2.24/contrib/swank-mrepl.lisp | 162 + .../slime-v2.24/contrib/swank-package-fu.lisp | 65 + .../contrib/swank-presentation-streams.lisp | 334 + .../contrib/swank-presentations.lisp | 246 + .../slime-v2.24/contrib/swank-quicklisp.lisp | 17 + .../slime-v2.24/contrib/swank-r6rs.scm | 416 + .../slime-v2.24/contrib/swank-repl.lisp | 441 + .../slime-v2.24/contrib/swank-sbcl-exts.lisp | 67 + .../slime-v2.24/contrib/swank-snapshot.lisp | 67 + .../slime-v2.24/contrib/swank-sprof.lisp | 154 + .../contrib/swank-trace-dialog.lisp | 264 + .../slime-v2.24/contrib/swank-util.lisp | 63 + .../software/slime-v2.24/contrib/swank.rb | 385 + .../contrib/test/slime-autodoc-tests.el | 199 + .../contrib/test/slime-c-p-c-tests.el | 140 + .../contrib/test/slime-cl-indent-test.txt | 1006 +++ .../test/slime-enclosing-context-tests.el | 46 + .../contrib/test/slime-fontifying-fu-tests.el | 120 + .../contrib/test/slime-indentation-tests.el | 81 + .../contrib/test/slime-macrostep-tests.el | 287 + .../contrib/test/slime-mdot-fu-tests.el | 43 + .../contrib/test/slime-parse-tests.el | 63 + .../contrib/test/slime-presentations-tests.el | 61 + .../contrib/test/slime-repl-tests.el | 343 + .../software/slime-v2.24/doc/.cvsignore | 21 + .../software/slime-v2.24/doc/Makefile | 116 + .../slime-v2.24/doc/contributors.texi | 67 + .../slime-v2.24/doc/slime-refcard.pdf | Bin 0 -> 41845 bytes .../slime-v2.24/doc/slime-refcard.tex | 123 + .../software/slime-v2.24/doc/slime-small.eps | 995 +++ .../software/slime-v2.24/doc/slime-small.pdf | Bin 0 -> 7407 bytes .../software/slime-v2.24/doc/slime.css | 22 + .../software/slime-v2.24/doc/slime.texi | 3544 ++++++++ .../slime-v2.24/doc/texinfo-tabulate.awk | 21 + .../software/slime-v2.24/lib/.nosearch | 1 + .../software/slime-v2.24/lib/cl-lib.el | 410 + .../software/slime-v2.24/lib/ert-x.el | 2544 ++++++ .../quicklisp/software/slime-v2.24/lib/ert.el | 2544 ++++++ .../software/slime-v2.24/lib/hyperspec.el | 2511 ++++++ .../software/slime-v2.24/lib/macrostep.el | 1122 +++ .../software/slime-v2.24/metering.lisp | 1213 +++ .../software/slime-v2.24/nregex.lisp | 523 ++ .../software/slime-v2.24/packages.lisp | 202 + .../slime-v2.24/sbcl-pprint-patch.lisp | 332 + .../software/slime-v2.24/slime-autoloads.el | 51 + .../software/slime-v2.24/slime-tests.el | 1459 ++++ .../quicklisp/software/slime-v2.24/slime.el | 7659 +++++++++++++++++ .../software/slime-v2.24/start-swank.lisp | 20 + .../software/slime-v2.24/swank-loader.lisp | 376 + .../quicklisp/software/slime-v2.24/swank.asd | 37 + .../quicklisp/software/slime-v2.24/swank.lisp | 3795 ++++++++ .../software/slime-v2.24/swank/abcl.lisp | 847 ++ .../software/slime-v2.24/swank/allegro.lisp | 1070 +++ .../software/slime-v2.24/swank/backend.lisp | 1579 ++++ .../software/slime-v2.24/swank/ccl.lisp | 868 ++ .../software/slime-v2.24/swank/clasp.lisp | 809 ++ .../software/slime-v2.24/swank/clisp.lisp | 930 ++ .../software/slime-v2.24/swank/cmucl.lisp | 2470 ++++++ .../software/slime-v2.24/swank/corman.lisp | 583 ++ .../software/slime-v2.24/swank/ecl.lisp | 1098 +++ .../software/slime-v2.24/swank/gray.lisp | 207 + .../software/slime-v2.24/swank/lispworks.lisp | 1020 +++ .../software/slime-v2.24/swank/match.lisp | 242 + .../software/slime-v2.24/swank/mezzano.lisp | 730 ++ .../software/slime-v2.24/swank/mkcl.lisp | 933 ++ .../software/slime-v2.24/swank/rpc.lisp | 162 + .../software/slime-v2.24/swank/sbcl.lisp | 2025 +++++ .../software/slime-v2.24/swank/scl.lisp | 1726 ++++ .../slime-v2.24/swank/source-file-cache.lisp | 136 + .../slime-v2.24/swank/source-path-parser.lisp | 239 + .../quicklisp/software/slime-v2.24/xref.lisp | 2906 +++++++ .../software/split-sequence-v2.0.0/LICENSE | 21 + .../software/split-sequence-v2.0.0/README.md | 109 + .../software/split-sequence-v2.0.0/api.lisp | 79 + .../split-sequence-v2.0.0/documentation.lisp | 41 + .../extended-sequence.lisp | 100 + .../software/split-sequence-v2.0.0/list.lisp | 116 + .../original-message.txt | 150 + .../split-sequence-v2.0.0/package.lisp | 37 + .../split-sequence-v2.0.0/split-sequence.asd | 28 + .../software/split-sequence-v2.0.0/tests.lisp | 268 + .../split-sequence-v2.0.0/vector.lisp | 94 + .../split-sequence-v2.0.0/version.sexp | 2 + .../trivial-gray-streams-20181018-git/COPYING | 22 + .../Makefile | 3 + .../trivial-gray-streams-20181018-git/README | 40 + .../build.xcvb | 7 + .../package.lisp | 77 + .../streams.lisp | 292 + .../test/package.lisp | 6 + .../test/run-on-many-lisps.lisp | 66 + .../test/test-framework.lisp | 60 + .../test/test.lisp | 213 + .../trivial-gray-streams-test.asd | 10 + .../trivial-gray-streams.asd | 10 + .../software/usocket-0.8.3/.gitignore | 1 + .../quicklisp/software/usocket-0.8.3/CHANGES | 211 + .../software/usocket-0.8.3/CONTRIBUTORS | 47 + .../quicklisp/software/usocket-0.8.3/LICENSE | 25 + .../software/usocket-0.8.3/README.md | 148 + .../quicklisp/software/usocket-0.8.3/TODO | 5 + .../software/usocket-0.8.3/backend/.gitignore | 1 + .../software/usocket-0.8.3/backend/abcl.lisp | 436 + .../usocket-0.8.3/backend/allegro.lisp | 228 + .../software/usocket-0.8.3/backend/clasp.lisp | 158 + .../software/usocket-0.8.3/backend/clisp.lisp | 715 ++ .../usocket-0.8.3/backend/clozure.lisp | 73 + .../software/usocket-0.8.3/backend/cmucl.lisp | 298 + .../software/usocket-0.8.3/backend/ecl.lisp | 152 + .../usocket-0.8.3/backend/genera.lisp | 264 + .../software/usocket-0.8.3/backend/iolib.lisp | 290 + .../usocket-0.8.3/backend/lispworks.lisp | 1001 +++ .../software/usocket-0.8.3/backend/mcl.lisp | 271 + .../usocket-0.8.3/backend/mezzano.lisp | 99 + .../software/usocket-0.8.3/backend/mocl.lisp | 155 + .../usocket-0.8.3/backend/openmcl.lisp | 268 + .../software/usocket-0.8.3/backend/sbcl.lisp | 935 ++ .../software/usocket-0.8.3/backend/scl.lisp | 266 + .../software/usocket-0.8.3/condition.lisp | 237 + .../software/usocket-0.8.3/doc/intro.dita | 10 + .../software/usocket-0.8.3/doc/reference.dita | 11 + .../usocket-0.8.3/doc/usocket.ditamap | 11 + .../usocket-0.8.3/notes/abcl-socket.txt | 18 + .../notes/active-sockets-apis.txt | 75 + .../usocket-0.8.3/notes/address-apis.txt | 73 + .../usocket-0.8.3/notes/allegro-socket.txt | 46 + .../software/usocket-0.8.3/notes/backends.txt | 60 + .../usocket-0.8.3/notes/clisp-sockets.txt | 38 + .../usocket-0.8.3/notes/cmucl-sockets.txt | 69 + .../software/usocket-0.8.3/notes/design.txt | 136 + .../software/usocket-0.8.3/notes/errors.txt | 20 + .../usocket-0.8.3/notes/lw-sockets.txt | 41 + .../usocket-0.8.3/notes/openmcl-sockets.txt | 27 + .../usocket-0.8.3/notes/sb-bsd-sockets.txt | 114 + .../usocket-0.8.3/notes/usock-sockets.txt | 28 + .../software/usocket-0.8.3/option.lisp | 353 + .../software/usocket-0.8.3/package.lisp | 126 + .../software/usocket-0.8.3/server.lisp | 112 + .../software/usocket-0.8.3/test/package.lisp | 11 + .../usocket-0.8.3/test/test-condition.lisp | 28 + .../usocket-0.8.3/test/test-datagram.lisp | 124 + .../usocket-0.8.3/test/test-usocket.lisp | 179 + .../usocket-0.8.3/test/udp-one-shot.lisp | 86 + .../usocket-0.8.3/test/wait-for-input.lisp | 140 + .../software/usocket-0.8.3/usocket-server.asd | 14 + .../software/usocket-0.8.3/usocket-test.asd | 23 + .../software/usocket-0.8.3/usocket.asd | 58 + .../software/usocket-0.8.3/usocket.lisp | 727 ++ .../vendor/OpenTransportUDP.lisp | 146 + .../software/usocket-0.8.3/vendor/kqueue.lisp | 506 ++ .../software/usocket-0.8.3/version.sexp | 1 + .../software/vom-20160825-git/LICENSE | 19 + .../software/vom-20160825-git/README.md | 82 + .../software/vom-20160825-git/vom.asd | 6 + .../software/vom-20160825-git/vom.lisp | 204 + .../software/yason-v0.7.8/.gitignore | 1 + .../software/yason-v0.7.8/.pre-release.sh | 1 + .../quicklisp/software/yason-v0.7.8/CHANGELOG | 28 + .../quicklisp/software/yason-v0.7.8/LICENSE | 30 + .../quicklisp/software/yason-v0.7.8/README.md | 13 + .../software/yason-v0.7.8/clixdoc.xsl | 411 + .../quicklisp/software/yason-v0.7.8/doc.xml | 748 ++ .../software/yason-v0.7.8/encode.lisp | 388 + .../software/yason-v0.7.8/index.html | 764 ++ .../software/yason-v0.7.8/package.lisp | 50 + .../software/yason-v0.7.8/parse.lisp | 258 + .../software/yason-v0.7.8/render-doc.sh | 5 + .../quicklisp/software/yason-v0.7.8/test.lisp | 116 + .../quicklisp/software/yason-v0.7.8/yason.asd | 33 + sbcl/.quicklisp/dists/quicklisp/systems.cdb | Bin 0 -> 497817 bytes sbcl/.quicklisp/dists/quicklisp/systems.txt | 4335 ++++++++++ .../local-projects/system-index.txt | 0 .../.quicklisp/quicklisp/bundle-template.lisp | 161 + sbcl/.quicklisp/quicklisp/bundle.lisp | 362 + sbcl/.quicklisp/quicklisp/cdb.lisp | 356 + sbcl/.quicklisp/quicklisp/client-info.lisp | 262 + sbcl/.quicklisp/quicklisp/client-update.lisp | 106 + sbcl/.quicklisp/quicklisp/client.lisp | 131 + sbcl/.quicklisp/quicklisp/config.lisp | 40 + sbcl/.quicklisp/quicklisp/deflate.lisp | 785 ++ sbcl/.quicklisp/quicklisp/dist-update.lisp | 164 + sbcl/.quicklisp/quicklisp/dist.lisp | 1168 +++ sbcl/.quicklisp/quicklisp/fetch-gzipped.lisp | 29 + sbcl/.quicklisp/quicklisp/http.lisp | 859 ++ sbcl/.quicklisp/quicklisp/impl-util.lisp | 340 + sbcl/.quicklisp/quicklisp/impl.lisp | 301 + sbcl/.quicklisp/quicklisp/local-projects.lisp | 138 + sbcl/.quicklisp/quicklisp/minitar.lisp | 192 + sbcl/.quicklisp/quicklisp/misc.lisp | 19 + sbcl/.quicklisp/quicklisp/network.lisp | 137 + sbcl/.quicklisp/quicklisp/package.lisp | 340 + sbcl/.quicklisp/quicklisp/progress.lisp | 156 + sbcl/.quicklisp/quicklisp/quicklisp.asd | 36 + sbcl/.quicklisp/quicklisp/setup.lisp | 249 + sbcl/.quicklisp/quicklisp/utils.lisp | 124 + sbcl/.quicklisp/quicklisp/version.txt | 1 + sbcl/.quicklisp/setup.lisp | 135 + sbcl/.quicklisp/tmp/install-dist-distinfo.txt | 7 + sbcl/.quicklisp/tmp/quicklisp.tar | Bin 0 -> 256000 bytes sbcl/.quicklisp/tmp/release-install.tar | Bin 0 -> 20480 bytes sbcl/.sbclrc | 8 + sbcl/quicklisp.lisp | 1757 ++++ vim/.vimrc | 3 +- 335 files changed, 119806 insertions(+), 1 deletion(-) create mode 100644 quicklisp.lisp create mode 100644 sbcl/.quicklisp/asdf.lisp create mode 100644 sbcl/.quicklisp/client-info.sexp create mode 100644 sbcl/.quicklisp/dists/quicklisp/archives/alexandria-20191227-git.tgz create mode 100644 sbcl/.quicklisp/dists/quicklisp/archives/slime-v2.24.tgz create mode 100644 sbcl/.quicklisp/dists/quicklisp/archives/split-sequence-v2.0.0.tgz create mode 100644 sbcl/.quicklisp/dists/quicklisp/archives/trivial-gray-streams-20181018-git.tgz create mode 100644 sbcl/.quicklisp/dists/quicklisp/archives/usocket-0.8.3.tgz create mode 100644 sbcl/.quicklisp/dists/quicklisp/archives/vom-20160825-git.tgz create mode 100644 sbcl/.quicklisp/dists/quicklisp/archives/yason-v0.7.8.tgz create mode 100644 sbcl/.quicklisp/dists/quicklisp/distinfo.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/enabled.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/installed/releases/alexandria.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/installed/releases/slime.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/installed/releases/split-sequence.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/installed/releases/trivial-gray-streams.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/installed/releases/usocket.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/installed/releases/vom.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/installed/releases/yason.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/installed/systems/alexandria-tests.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/installed/systems/alexandria.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/installed/systems/split-sequence.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/installed/systems/swank.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/installed/systems/trivial-gray-streams-test.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/installed/systems/trivial-gray-streams.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/installed/systems/usocket-server.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/installed/systems/usocket-test.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/installed/systems/usocket.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/installed/systems/vom.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/installed/systems/yason.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/preference.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/releases.cdb create mode 100644 sbcl/.quicklisp/dists/quicklisp/releases.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/.boring create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/.gitignore create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/AUTHORS create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/LICENCE create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/README create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/alexandria-tests.asd create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/alexandria.asd create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/arrays.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/binding.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/conditions.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/control-flow.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/definitions.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/doc/.gitignore create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/doc/Makefile create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/doc/alexandria.texinfo create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/doc/docstrings.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/features.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/functions.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/hash-tables.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/io.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/lists.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/macros.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/numbers.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/package.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/sequences.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/strings.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/symbols.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/tests.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/types.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/.gitref create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/.travis.yml create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/CONTRIBUTING.md create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/Makefile create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/NEWS create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/PROBLEMS create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/README.md create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/Makefile create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/README.md create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/bridge.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/inferior-slime.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-asdf.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-autodoc.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-banner.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-buffer-streams.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-c-p-c.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-cl-indent.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-clipboard.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-compiler-notes-tree.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-editing-commands.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-enclosing-context.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-fancy-inspector.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-fancy-trace.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-fancy.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-fontifying-fu.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-fuzzy.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-highlight-edits.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-hyperdoc.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-indentation.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-listener-hooks.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-macrostep.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-mdot-fu.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-media.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-mrepl.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-package-fu.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-parse.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-presentation-streams.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-presentations.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-quicklisp.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-references.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-repl.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-sbcl-exts.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-scheme.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-scratch.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-snapshot.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-sprof.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-trace-dialog.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-tramp.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-typeout-frame.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-xref-browser.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-arglists.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-asdf.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-buffer-streams.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-c-p-c.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-clipboard.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-fancy-inspector.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-fuzzy.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-goo.goo create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-hyperdoc.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-ikarus.ss create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-indentation.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-jolt.k create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-kawa.scm create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-larceny.scm create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-listener-hooks.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-macrostep.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-media.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-mit-scheme.scm create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-mlworks.sml create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-mrepl.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-package-fu.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-presentation-streams.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-presentations.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-quicklisp.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-r6rs.scm create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-repl.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-sbcl-exts.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-snapshot.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-sprof.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-trace-dialog.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-util.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank.rb create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-autodoc-tests.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-c-p-c-tests.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-cl-indent-test.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-enclosing-context-tests.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-fontifying-fu-tests.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-indentation-tests.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-macrostep-tests.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-mdot-fu-tests.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-parse-tests.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-presentations-tests.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-repl-tests.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/doc/.cvsignore create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/doc/Makefile create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/doc/contributors.texi create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/doc/slime-refcard.pdf create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/doc/slime-refcard.tex create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/doc/slime-small.eps create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/doc/slime-small.pdf create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/doc/slime.css create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/doc/slime.texi create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/doc/texinfo-tabulate.awk create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/lib/.nosearch create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/lib/cl-lib.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/lib/ert-x.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/lib/ert.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/lib/hyperspec.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/lib/macrostep.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/metering.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/nregex.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/packages.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/sbcl-pprint-patch.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/slime-autoloads.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/slime-tests.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/slime.el create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/start-swank.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank-loader.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank.asd create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/abcl.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/allegro.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/backend.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/ccl.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/clasp.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/clisp.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/cmucl.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/corman.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/ecl.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/gray.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/lispworks.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/match.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/mezzano.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/mkcl.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/rpc.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/sbcl.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/scl.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/source-file-cache.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/source-path-parser.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/xref.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/LICENSE create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/README.md create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/api.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/documentation.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/extended-sequence.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/list.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/original-message.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/package.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/split-sequence.asd create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/tests.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/vector.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/version.sexp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/COPYING create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/Makefile create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/README create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/build.xcvb create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/package.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/streams.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/test/package.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/test/run-on-many-lisps.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/test/test-framework.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/test/test.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/trivial-gray-streams-test.asd create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/trivial-gray-streams.asd create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/.gitignore create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/CHANGES create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/CONTRIBUTORS create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/LICENSE create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/README.md create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/TODO create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/.gitignore create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/abcl.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/allegro.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/clasp.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/clisp.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/clozure.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/cmucl.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/ecl.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/genera.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/iolib.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/lispworks.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/mcl.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/mezzano.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/mocl.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/openmcl.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/sbcl.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/scl.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/condition.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/doc/intro.dita create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/doc/reference.dita create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/doc/usocket.ditamap create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/abcl-socket.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/active-sockets-apis.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/address-apis.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/allegro-socket.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/backends.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/clisp-sockets.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/cmucl-sockets.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/design.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/errors.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/lw-sockets.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/openmcl-sockets.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/sb-bsd-sockets.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/usock-sockets.txt create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/option.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/package.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/server.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/test/package.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/test/test-condition.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/test/test-datagram.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/test/test-usocket.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/test/udp-one-shot.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/test/wait-for-input.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/usocket-server.asd create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/usocket-test.asd create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/usocket.asd create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/usocket.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/vendor/OpenTransportUDP.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/vendor/kqueue.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/version.sexp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/vom-20160825-git/LICENSE create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/vom-20160825-git/README.md create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/vom-20160825-git/vom.asd create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/vom-20160825-git/vom.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/.gitignore create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/.pre-release.sh create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/CHANGELOG create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/LICENSE create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/README.md create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/clixdoc.xsl create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/doc.xml create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/encode.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/index.html create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/package.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/parse.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/render-doc.sh create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/test.lisp create mode 100644 sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/yason.asd create mode 100644 sbcl/.quicklisp/dists/quicklisp/systems.cdb create mode 100644 sbcl/.quicklisp/dists/quicklisp/systems.txt create mode 100644 sbcl/.quicklisp/local-projects/system-index.txt create mode 100644 sbcl/.quicklisp/quicklisp/bundle-template.lisp create mode 100644 sbcl/.quicklisp/quicklisp/bundle.lisp create mode 100644 sbcl/.quicklisp/quicklisp/cdb.lisp create mode 100644 sbcl/.quicklisp/quicklisp/client-info.lisp create mode 100644 sbcl/.quicklisp/quicklisp/client-update.lisp create mode 100644 sbcl/.quicklisp/quicklisp/client.lisp create mode 100644 sbcl/.quicklisp/quicklisp/config.lisp create mode 100644 sbcl/.quicklisp/quicklisp/deflate.lisp create mode 100644 sbcl/.quicklisp/quicklisp/dist-update.lisp create mode 100644 sbcl/.quicklisp/quicklisp/dist.lisp create mode 100644 sbcl/.quicklisp/quicklisp/fetch-gzipped.lisp create mode 100644 sbcl/.quicklisp/quicklisp/http.lisp create mode 100644 sbcl/.quicklisp/quicklisp/impl-util.lisp create mode 100644 sbcl/.quicklisp/quicklisp/impl.lisp create mode 100644 sbcl/.quicklisp/quicklisp/local-projects.lisp create mode 100644 sbcl/.quicklisp/quicklisp/minitar.lisp create mode 100644 sbcl/.quicklisp/quicklisp/misc.lisp create mode 100644 sbcl/.quicklisp/quicklisp/network.lisp create mode 100644 sbcl/.quicklisp/quicklisp/package.lisp create mode 100644 sbcl/.quicklisp/quicklisp/progress.lisp create mode 100644 sbcl/.quicklisp/quicklisp/quicklisp.asd create mode 100644 sbcl/.quicklisp/quicklisp/setup.lisp create mode 100644 sbcl/.quicklisp/quicklisp/utils.lisp create mode 100644 sbcl/.quicklisp/quicklisp/version.txt create mode 100644 sbcl/.quicklisp/setup.lisp create mode 100644 sbcl/.quicklisp/tmp/install-dist-distinfo.txt create mode 100644 sbcl/.quicklisp/tmp/quicklisp.tar create mode 100644 sbcl/.quicklisp/tmp/release-install.tar create mode 100644 sbcl/.sbclrc create mode 100644 sbcl/quicklisp.lisp diff --git a/README.md b/README.md index e69de29..e47cd58 100644 --- a/README.md +++ b/README.md @@ -0,0 +1 @@ +TODO: Figure out sbcl/quicklisp auto install diff --git a/quicklisp.lisp b/quicklisp.lisp new file mode 100644 index 0000000..6cda472 --- /dev/null +++ b/quicklisp.lisp @@ -0,0 +1,1757 @@ +;;;; +;;;; This is quicklisp.lisp, the quickstart file for Quicklisp. To use +;;;; it, start Lisp, then (load "quicklisp.lisp") +;;;; +;;;; Quicklisp is beta software and comes with no warranty of any kind. +;;;; +;;;; For more information about the Quicklisp beta, see: +;;;; +;;;; http://www.quicklisp.org/beta/ +;;;; +;;;; If you have any questions or comments about Quicklisp, please +;;;; contact: +;;;; +;;;; Zach Beane +;;;; + +(cl:in-package #:cl-user) +(cl:defpackage #:qlqs-user + (:use #:cl)) +(cl:in-package #:qlqs-user) + +(defpackage #:qlqs-info + (:export #:*version*)) + +(defvar qlqs-info:*version* "2015-01-28") + +(defpackage #:qlqs-impl + (:use #:cl) + (:export #:*implementation*) + (:export #:definterface + #:defimplementation) + (:export #:lisp + #:abcl + #:allegro + #:ccl + #:clasp + #:clisp + #:cmucl + #:cormanlisp + #:ecl + #:gcl + #:lispworks + #:mkcl + #:scl + #:sbcl)) + +(defpackage #:qlqs-impl-util + (:use #:cl #:qlqs-impl) + (:export #:call-with-quiet-compilation)) + +(defpackage #:qlqs-network + (:use #:cl #:qlqs-impl) + (:export #:open-connection + #:write-octets + #:read-octets + #:close-connection + #:with-connection)) + +(defpackage #:qlqs-progress + (:use #:cl) + (:export #:make-progress-bar + #:start-display + #:update-progress + #:finish-display)) + +(defpackage #:qlqs-http + (:use #:cl #:qlqs-network #:qlqs-progress) + (:export #:fetch + #:*proxy-url* + #:*maximum-redirects* + #:*default-url-defaults*)) + +(defpackage #:qlqs-minitar + (:use #:cl) + (:export #:unpack-tarball)) + +(defpackage #:quicklisp-quickstart + (:use #:cl #:qlqs-impl #:qlqs-impl-util #:qlqs-http #:qlqs-minitar) + (:export #:install + #:help + #:*proxy-url* + #:*asdf-url* + #:*quicklisp-tar-url* + #:*setup-url* + #:*help-message* + #:*after-load-message* + #:*after-initial-setup-message*)) + + +;;; +;;; Defining implementation-specific packages and functionality +;;; + +(in-package #:qlqs-impl) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defun error-unimplemented (&rest args) + (declare (ignore args)) + (error "Not implemented"))) + +(defmacro neuter-package (name) + `(eval-when (:compile-toplevel :load-toplevel :execute) + (let ((definition (fdefinition 'error-unimplemented))) + (do-external-symbols (symbol ,(string name)) + (unless (fboundp symbol) + (setf (fdefinition symbol) definition)))))) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defun feature-expression-passes-p (expression) + (cond ((keywordp expression) + (member expression *features*)) + ((consp expression) + (case (first expression) + (or + (some 'feature-expression-passes-p (rest expression))) + (and + (every 'feature-expression-passes-p (rest expression))))) + (t (error "Unrecognized feature expression -- ~S" expression))))) + + +(defmacro define-implementation-package (feature package-name &rest options) + (let* ((output-options '((:use) + (:export #:lisp))) + (prep (cdr (assoc :prep options))) + (class-option (cdr (assoc :class options))) + (class (first class-option)) + (superclasses (rest class-option)) + (import-options '()) + (effectivep (feature-expression-passes-p feature))) + (dolist (option options) + (ecase (first option) + ((:prep :class)) + ((:import-from + :import) + (push option import-options)) + ((:export + :shadow + :intern + :documentation) + (push option output-options)) + ((:reexport-from) + (push (cons :export (cddr option)) output-options) + (push (cons :import-from (cdr option)) import-options)))) + `(eval-when (:compile-toplevel :load-toplevel :execute) + ,@(when effectivep + prep) + (defclass ,class ,superclasses ()) + (defpackage ,package-name ,@output-options + ,@(when effectivep + import-options)) + ,@(when effectivep + `((setf *implementation* (make-instance ',class)))) + ,@(unless effectivep + `((neuter-package ,package-name)))))) + +(defmacro definterface (name lambda-list &body options) + (let* ((forbidden (intersection lambda-list lambda-list-keywords)) + (gf-options (remove :implementation options :key #'first)) + (implementations (set-difference options gf-options))) + (when forbidden + (error "~S not allowed in definterface lambda list" forbidden)) + (flet ((method-option (class body) + `(:method ((*implementation* ,class) ,@lambda-list) + ,@body))) + (let ((generic-name (intern (format nil "%~A" name)))) + `(eval-when (:compile-toplevel :load-toplevel :execute) + (defgeneric ,generic-name (lisp ,@lambda-list) + ,@gf-options + ,@(mapcar (lambda (implementation) + (destructuring-bind (class &rest body) + (rest implementation) + (method-option class body))) + implementations)) + (defun ,name ,lambda-list + (,generic-name *implementation* ,@lambda-list))))))) + +(defmacro defimplementation (name-and-options + lambda-list &body body) + (destructuring-bind (name &key (for t) qualifier) + (if (consp name-and-options) + name-and-options + (list name-and-options)) + (unless for + (error "You must specify an implementation name.")) + (let ((generic-name (find-symbol (format nil "%~A" name)))) + (unless (and generic-name + (fboundp generic-name)) + (error "~S does not name an implementation function" name)) + `(defmethod ,generic-name + ,@(when qualifier (list qualifier)) + ,(list* `(*implementation* ,for) lambda-list) ,@body)))) + + +;;; Bootstrap implementations + +(defvar *implementation* nil) +(defclass lisp () ()) + + +;;; Allegro Common Lisp + +(define-implementation-package :allegro #:qlqs-allegro + (:documentation + "Allegro Common Lisp - http://www.franz.com/products/allegrocl/") + (:class allegro) + (:reexport-from #:socket + #:make-socket) + (:reexport-from #:excl + #:read-vector)) + + +;;; Armed Bear Common Lisp + +(define-implementation-package :abcl #:qlqs-abcl + (:documentation + "Armed Bear Common Lisp - http://common-lisp.net/project/armedbear/") + (:class abcl) + (:reexport-from #:system + #:make-socket + #:get-socket-stream)) + +;;; Clozure CL + +(define-implementation-package :ccl #:qlqs-ccl + (:documentation + "Clozure Common Lisp - http://www.clozure.com/clozurecl.html") + (:class ccl) + (:reexport-from #:ccl + #:make-socket)) + + +;;; CLASP + +(define-implementation-package :clasp #:qlqs-clasp + (:documentation "CLASP - http://github.com/drmeister/clasp") + (:class clasp) + (:prep + (require 'sockets)) + (:intern #:host-network-address) + (:reexport-from #:sb-bsd-sockets + #:get-host-by-name + #:host-ent-address + #:socket-connect + #:socket-make-stream + #:inet-socket)) + + +;;; GNU CLISP + +(define-implementation-package :clisp #:qlqs-clisp + (:documentation "GNU CLISP - http://clisp.cons.org/") + (:class clisp) + (:reexport-from #:socket + #:socket-connect) + (:reexport-from #:ext + #:read-byte-sequence)) + + +;;; CMUCL + +(define-implementation-package :cmu #:qlqs-cmucl + (:documentation "CMU Common Lisp - http://www.cons.org/cmucl/") + (:class cmucl) + (:reexport-from #:ext + #:*gc-verbose*) + (:reexport-from #:system + #:make-fd-stream) + (:reexport-from #:extensions + #:connect-to-inet-socket)) + +(defvar qlqs-cmucl:*gc-verbose* nil) + + +;;; Scieneer CL + +(define-implementation-package :scl #:qlqs-scl + (:documentation "Scieneer Common Lisp - http://www.scieneer.com/scl/") + (:class scl) + (:reexport-from #:system + #:make-fd-stream) + (:reexport-from #:extensions + #:connect-to-inet-socket)) + +;;; ECL + +(define-implementation-package :ecl #:qlqs-ecl + (:documentation "ECL - http://ecls.sourceforge.net/") + (:class ecl) + (:prep + (require 'sockets)) + (:intern #:host-network-address) + (:reexport-from #:sb-bsd-sockets + #:get-host-by-name + #:host-ent-address + #:socket-connect + #:socket-make-stream + #:inet-socket)) + + +;;; LispWorks + +(define-implementation-package :lispworks #:qlqs-lispworks + (:documentation "LispWorks - http://www.lispworks.com/") + (:class lispworks) + (:prep + (require "comm")) + (:reexport-from #:comm + #:open-tcp-stream + #:get-host-entry)) + + +;;; SBCL + +(define-implementation-package :sbcl #:qlqs-sbcl + (:class sbcl) + (:documentation + "Steel Bank Common Lisp - http://www.sbcl.org/") + (:prep + (require 'sb-bsd-sockets)) + (:intern #:host-network-address) + (:reexport-from #:sb-ext + #:compiler-note) + (:reexport-from #:sb-bsd-sockets + #:get-host-by-name + #:inet-socket + #:host-ent-address + #:socket-connect + #:socket-make-stream)) + +;;; MKCL + +(define-implementation-package :mkcl #:qlqs-mkcl + (:class mkcl) + (:documentation + "ManKai Common Lisp - http://common-lisp.net/project/mkcl/") + (:prep + (require 'sockets)) + (:intern #:host-network-address) + (:reexport-from #:sb-bsd-sockets + #:get-host-by-name + #:inet-socket + #:host-ent-address + #:socket-connect + #:socket-make-stream)) + +;;; +;;; Utility function +;;; + +(in-package #:qlqs-impl-util) + +(definterface call-with-quiet-compilation (fun) + (:implementation t + (let ((*load-verbose* nil) + (*compile-verbose* nil) + (*load-print* nil) + (*compile-print* nil)) + (handler-bind ((warning #'muffle-warning)) + (funcall fun))))) + +(defimplementation (call-with-quiet-compilation :for sbcl :qualifier :around) + (fun) + (declare (ignorable fun)) + (handler-bind ((qlqs-sbcl:compiler-note #'muffle-warning)) + (call-next-method))) + +(defimplementation (call-with-quiet-compilation :for cmucl :qualifier :around) + (fun) + (declare (ignorable fun)) + (let ((qlqs-cmucl:*gc-verbose* nil)) + (call-next-method))) + + +;;; +;;; Low-level networking implementations +;;; + +(in-package #:qlqs-network) + +(definterface host-address (host) + (:implementation t + host) + (:implementation mkcl + (qlqs-mkcl:host-ent-address (qlqs-mkcl:get-host-by-name host))) + (:implementation sbcl + (qlqs-sbcl:host-ent-address (qlqs-sbcl:get-host-by-name host)))) + +(definterface open-connection (host port) + (:implementation t + (declare (ignorable host port)) + (error "Sorry, quicklisp in implementation ~S is not supported yet." + (lisp-implementation-type))) + (:implementation allegro + (qlqs-allegro:make-socket :remote-host host + :remote-port port)) + (:implementation abcl + (let ((socket (qlqs-abcl:make-socket host port))) + (qlqs-abcl:get-socket-stream socket :element-type '(unsigned-byte 8)))) + (:implementation ccl + (qlqs-ccl:make-socket :remote-host host + :remote-port port)) + (:implementation clasp + (let* ((endpoint (qlqs-clasp:host-ent-address + (qlqs-clasp:get-host-by-name host))) + (socket (make-instance 'qlqs-clasp:inet-socket + :protocol :tcp + :type :stream))) + (qlqs-clasp:socket-connect socket endpoint port) + (qlqs-clasp:socket-make-stream socket + :element-type '(unsigned-byte 8) + :input t + :output t + :buffering :full))) + (:implementation clisp + (qlqs-clisp:socket-connect port host :element-type '(unsigned-byte 8))) + (:implementation cmucl + (let ((fd (qlqs-cmucl:connect-to-inet-socket host port))) + (qlqs-cmucl:make-fd-stream fd + :element-type '(unsigned-byte 8) + :binary-stream-p t + :input t + :output t))) + (:implementation scl + (let ((fd (qlqs-scl:connect-to-inet-socket host port))) + (qlqs-scl:make-fd-stream fd + :element-type '(unsigned-byte 8) + :input t + :output t))) + (:implementation ecl + (let* ((endpoint (qlqs-ecl:host-ent-address + (qlqs-ecl:get-host-by-name host))) + (socket (make-instance 'qlqs-ecl:inet-socket + :protocol :tcp + :type :stream))) + (qlqs-ecl:socket-connect socket endpoint port) + (qlqs-ecl:socket-make-stream socket + :element-type '(unsigned-byte 8) + :input t + :output t + :buffering :full))) + (:implementation lispworks + (qlqs-lispworks:open-tcp-stream host port + :direction :io + :errorp t + :read-timeout nil + :element-type '(unsigned-byte 8) + :timeout 5)) + (:implementation mkcl + (let* ((endpoint (qlqs-mkcl:host-ent-address + (qlqs-mkcl:get-host-by-name host))) + (socket (make-instance 'qlqs-mkcl:inet-socket + :protocol :tcp + :type :stream))) + (qlqs-mkcl:socket-connect socket endpoint port) + (qlqs-mkcl:socket-make-stream socket + :element-type '(unsigned-byte 8) + :input t + :output t + :buffering :full))) + (:implementation sbcl + (let* ((endpoint (qlqs-sbcl:host-ent-address + (qlqs-sbcl:get-host-by-name host))) + (socket (make-instance 'qlqs-sbcl:inet-socket + :protocol :tcp + :type :stream))) + (qlqs-sbcl:socket-connect socket endpoint port) + (qlqs-sbcl:socket-make-stream socket + :element-type '(unsigned-byte 8) + :input t + :output t + :buffering :full)))) + +(definterface read-octets (buffer connection) + (:implementation t + (read-sequence buffer connection)) + (:implementation allegro + (qlqs-allegro:read-vector buffer connection)) + (:implementation clisp + (qlqs-clisp:read-byte-sequence buffer connection + :no-hang nil + :interactive t))) + +(definterface write-octets (buffer connection) + (:implementation t + (write-sequence buffer connection) + (finish-output connection))) + +(definterface close-connection (connection) + (:implementation t + (ignore-errors (close connection)))) + +(definterface call-with-connection (host port fun) + (:implementation t + (let (connection) + (unwind-protect + (progn + (setf connection (open-connection host port)) + (funcall fun connection)) + (when connection + (close connection)))))) + +(defmacro with-connection ((connection host port) &body body) + `(call-with-connection ,host ,port (lambda (,connection) ,@body))) + + +;;; +;;; A text progress bar +;;; + +(in-package #:qlqs-progress) + +(defclass progress-bar () + ((start-time + :initarg :start-time + :accessor start-time) + (end-time + :initarg :end-time + :accessor end-time) + (progress-character + :initarg :progress-character + :accessor progress-character) + (character-count + :initarg :character-count + :accessor character-count + :documentation "How many characters wide is the progress bar?") + (characters-so-far + :initarg :characters-so-far + :accessor characters-so-far) + (update-interval + :initarg :update-interval + :accessor update-interval + :documentation "Update the progress bar display after this many + internal-time units.") + (last-update-time + :initarg :last-update-time + :accessor last-update-time + :documentation "The display was last updated at this time.") + (total + :initarg :total + :accessor total + :documentation "The total number of units tracked by this progress bar.") + (progress + :initarg :progress + :accessor progress + :documentation "How far in the progress are we?") + (pending + :initarg :pending + :accessor pending + :documentation "How many raw units should be tracked in the next + display update?")) + (:default-initargs + :progress-character #\= + :character-count 50 + :characters-so-far 0 + :update-interval (floor internal-time-units-per-second 4) + :last-update-time 0 + :total 0 + :progress 0 + :pending 0)) + +(defgeneric start-display (progress-bar)) +(defgeneric update-progress (progress-bar unit-count)) +(defgeneric update-display (progress-bar)) +(defgeneric finish-display (progress-bar)) +(defgeneric elapsed-time (progress-bar)) +(defgeneric units-per-second (progress-bar)) + +(defmethod start-display (progress-bar) + (setf (last-update-time progress-bar) (get-internal-real-time)) + (setf (start-time progress-bar) (get-internal-real-time)) + (fresh-line) + (finish-output)) + +(defmethod update-display (progress-bar) + (incf (progress progress-bar) (pending progress-bar)) + (setf (pending progress-bar) 0) + (setf (last-update-time progress-bar) (get-internal-real-time)) + (let* ((showable (floor (character-count progress-bar) + (/ (total progress-bar) (progress progress-bar)))) + (needed (- showable (characters-so-far progress-bar)))) + (setf (characters-so-far progress-bar) showable) + (dotimes (i needed) + (write-char (progress-character progress-bar))) + (finish-output))) + +(defmethod update-progress (progress-bar unit-count) + (incf (pending progress-bar) unit-count) + (let ((now (get-internal-real-time))) + (when (< (update-interval progress-bar) + (- now (last-update-time progress-bar))) + (update-display progress-bar)))) + +(defmethod finish-display (progress-bar) + (update-display progress-bar) + (setf (end-time progress-bar) (get-internal-real-time)) + (terpri) + (format t "~:D bytes in ~$ seconds (~$KB/sec)" + (total progress-bar) + (elapsed-time progress-bar) + (/ (units-per-second progress-bar) 1024)) + (finish-output)) + +(defmethod elapsed-time (progress-bar) + (/ (- (end-time progress-bar) (start-time progress-bar)) + internal-time-units-per-second)) + +(defmethod units-per-second (progress-bar) + (if (plusp (elapsed-time progress-bar)) + (/ (total progress-bar) (elapsed-time progress-bar)) + 0)) + +(defun kb/sec (progress-bar) + (/ (units-per-second progress-bar) 1024)) + + + +(defparameter *uncertain-progress-chars* "?") + +(defclass uncertain-size-progress-bar (progress-bar) + ((progress-char-index + :initarg :progress-char-index + :accessor progress-char-index) + (units-per-char + :initarg :units-per-char + :accessor units-per-char)) + (:default-initargs + :total 0 + :progress-char-index 0 + :units-per-char (floor (expt 1024 2) 50))) + +(defmethod update-progress :after ((progress-bar uncertain-size-progress-bar) + unit-count) + (incf (total progress-bar) unit-count)) + +(defmethod progress-character ((progress-bar uncertain-size-progress-bar)) + (let ((index (progress-char-index progress-bar))) + (prog1 + (char *uncertain-progress-chars* index) + (setf (progress-char-index progress-bar) + (mod (1+ index) (length *uncertain-progress-chars*)))))) + +(defmethod update-display ((progress-bar uncertain-size-progress-bar)) + (setf (last-update-time progress-bar) (get-internal-real-time)) + (multiple-value-bind (chars pend) + (floor (pending progress-bar) (units-per-char progress-bar)) + (setf (pending progress-bar) pend) + (dotimes (i chars) + (write-char (progress-character progress-bar)) + (incf (characters-so-far progress-bar)) + (when (<= (character-count progress-bar) + (characters-so-far progress-bar)) + (terpri) + (setf (characters-so-far progress-bar) 0) + (finish-output))) + (finish-output))) + +(defun make-progress-bar (total) + (if (or (not total) (zerop total)) + (make-instance 'uncertain-size-progress-bar) + (make-instance 'progress-bar :total total))) + +;;; +;;; A simple HTTP client +;;; + +(in-package #:qlqs-http) + +;;; Octet data + +(deftype octet () + '(unsigned-byte 8)) + +(defun make-octet-vector (size) + (make-array size :element-type 'octet + :initial-element 0)) + +(defun octet-vector (&rest octets) + (make-array (length octets) :element-type 'octet + :initial-contents octets)) + +;;; ASCII characters as integers + +(defun acode (char) + (cond ((eql char :cr) + 13) + ((eql char :lf) + 10) + (t + (let ((code (char-code char))) + (if (<= 0 code 127) + code + (error "Character ~S is not in the ASCII character set" + char)))))) + +(defvar *whitespace* + (list (acode #\Space) (acode #\Tab) (acode :cr) (acode :lf))) + +(defun whitep (code) + (member code *whitespace*)) + +(defun ascii-vector (string) + (let ((vector (make-octet-vector (length string)))) + (loop for char across string + for code = (char-code char) + for i from 0 + if (< 127 code) do + (error "Invalid character for ASCII -- ~A" char) + else + do (setf (aref vector i) code)) + vector)) + +(defun ascii-subseq (vector start end) + "Return a subseq of octet-specialized VECTOR as a string." + (let ((string (make-string (- end start)))) + (loop for i from 0 + for j from start below end + do (setf (char string i) (code-char (aref vector j)))) + string)) + +(defun ascii-downcase (code) + (if (<= 65 code 90) + (+ code 32) + code)) + +(defun ascii-equal (a b) + (eql (ascii-downcase a) (ascii-downcase b))) + +(defmacro acase (value &body cases) + (flet ((convert-case-keys (keys) + (mapcar (lambda (key) + (etypecase key + (integer key) + (character (char-code key)) + (symbol + (ecase key + (:cr 13) + (:lf 10) + ((t) t))))) + (if (consp keys) keys (list keys))))) + `(case ,value + ,@(mapcar (lambda (case) + (destructuring-bind (keys &rest body) + case + `(,(if (eql keys t) + t + (convert-case-keys keys)) + ,@body))) + cases)))) + +;;; Pattern matching (for finding headers) + +(defclass matcher () + ((pattern + :initarg :pattern + :reader pattern) + (pos + :initform 0 + :accessor match-pos) + (matchedp + :initform nil + :accessor matchedp))) + +(defun reset-match (matcher) + (setf (match-pos matcher) 0 + (matchedp matcher) nil)) + +(define-condition match-failure (error) ()) + +(defun match (matcher input &key (start 0) end error) + (let ((i start) + (end (or end (length input))) + (match-end (length (pattern matcher)))) + (with-slots (pattern pos) + matcher + (loop + (cond ((= pos match-end) + (let ((match-start (- i pos))) + (setf pos 0) + (setf (matchedp matcher) t) + (return (values match-start (+ match-start match-end))))) + ((= i end) + (return nil)) + ((= (aref pattern pos) + (aref input i)) + (incf i) + (incf pos)) + (t + (if error + (error 'match-failure) + (if (zerop pos) + (incf i) + (setf pos 0))))))))) + +(defun ascii-matcher (string) + (make-instance 'matcher + :pattern (ascii-vector string))) + +(defun octet-matcher (&rest octets) + (make-instance 'matcher + :pattern (apply 'octet-vector octets))) + +(defun acode-matcher (&rest codes) + (make-instance 'matcher + :pattern (make-array (length codes) + :element-type 'octet + :initial-contents + (mapcar 'acode codes)))) + + +;;; "Connection Buffers" are a kind of callback-driven, +;;; pattern-matching chunky stream. Callbacks can be called for a +;;; certain number of octets or until one or more patterns are seen in +;;; the input. cbufs automatically refill themselves from a +;;; connection as needed. + +(defvar *cbuf-buffer-size* 8192) + +(define-condition end-of-data (error) ()) + +(defclass cbuf () + ((data + :initarg :data + :accessor data) + (connection + :initarg :connection + :accessor connection) + (start + :initarg :start + :accessor start) + (end + :initarg :end + :accessor end) + (eofp + :initarg :eofp + :accessor eofp)) + (:default-initargs + :data (make-octet-vector *cbuf-buffer-size*) + :connection nil + :start 0 + :end 0 + :eofp nil) + (:documentation "A CBUF is a connection buffer that keeps track of + incoming data from a connection. Several functions make it easy to + treat a CBUF as a kind of chunky, callback-driven stream.")) + +(define-condition cbuf-progress () + ((size + :initarg :size + :accessor cbuf-progress-size + :initform 0))) + +(defun call-processor (fun cbuf start end) + (signal 'cbuf-progress :size (- end start)) + (funcall fun (data cbuf) start end)) + +(defun make-cbuf (connection) + (make-instance 'cbuf :connection connection)) + +(defun make-stream-writer (stream) + "Create a callback for writing data to STREAM." + (lambda (data start end) + (write-sequence data stream :start start :end end))) + +(defgeneric size (cbuf) + (:method ((cbuf cbuf)) + (- (end cbuf) (start cbuf)))) + +(defgeneric emptyp (cbuf) + (:method ((cbuf cbuf)) + (zerop (size cbuf)))) + +(defgeneric refill (cbuf) + (:method ((cbuf cbuf)) + (when (eofp cbuf) + (error 'end-of-data)) + (setf (start cbuf) 0) + (setf (end cbuf) + (read-octets (data cbuf) + (connection cbuf))) + (cond ((emptyp cbuf) + (setf (eofp cbuf) t) + (error 'end-of-data)) + (t (size cbuf))))) + +(defun process-all (fun cbuf) + (unless (emptyp cbuf) + (call-processor fun cbuf (start cbuf) (end cbuf)))) + +(defun multi-cmatch (matchers cbuf) + (let (start end) + (dolist (matcher matchers (values start end)) + (multiple-value-bind (s e) + (match matcher (data cbuf) + :start (start cbuf) + :end (end cbuf)) + (when (and s (or (null start) (< s start))) + (setf start s + end e)))))) + +(defun cmatch (matcher cbuf) + (if (consp matcher) + (multi-cmatch matcher cbuf) + (match matcher (data cbuf) :start (start cbuf) :end (end cbuf)))) + +(defun call-until-end (fun cbuf) + (handler-case + (loop + (process-all fun cbuf) + (refill cbuf)) + (end-of-data () + (return-from call-until-end)))) + +(defun show-cbuf (context cbuf) + (format t "cbuf: ~A ~D - ~D~%" context (start cbuf) (end cbuf))) + +(defun call-for-n-octets (n fun cbuf) + (let ((remaining n)) + (loop + (when (<= remaining (size cbuf)) + (let ((end (+ (start cbuf) remaining))) + (call-processor fun cbuf (start cbuf) end) + (setf (start cbuf) end) + (return))) + (process-all fun cbuf) + (decf remaining (size cbuf)) + (refill cbuf)))) + +(defun call-until-matching (matcher fun cbuf) + (loop + (multiple-value-bind (start end) + (cmatch matcher cbuf) + (when start + (call-processor fun cbuf (start cbuf) end) + (setf (start cbuf) end) + (return))) + (process-all fun cbuf) + (refill cbuf))) + +(defun ignore-data (data start end) + (declare (ignore data start end))) + +(defun skip-until-matching (matcher cbuf) + (call-until-matching matcher 'ignore-data cbuf)) + + +;;; Creating HTTP requests as octet buffers + +(defclass octet-sink () + ((storage + :initarg :storage + :accessor storage)) + (:default-initargs + :storage (make-array 1024 :element-type 'octet + :fill-pointer 0 + :adjustable t)) + (:documentation "A simple stream-like target for collecting + octets.")) + +(defun add-octet (octet sink) + (vector-push-extend octet (storage sink))) + +(defun add-octets (octets sink &key (start 0) end) + (setf end (or end (length octets))) + (loop for i from start below end + do (add-octet (aref octets i) sink))) + +(defun add-string (string sink) + (loop for char across string + for code = (char-code char) + do (add-octet code sink))) + +(defun add-strings (sink &rest strings) + (mapc (lambda (string) (add-string string sink)) strings)) + +(defun add-newline (sink) + (add-octet 13 sink) + (add-octet 10 sink)) + +(defun sink-buffer (sink) + (subseq (storage sink) 0)) + +(defvar *proxy-url* nil) + +(defun full-proxy-path (host port path) + (format nil "~:[http~;https~]://~A~:[:~D~;~*~]~A" + (= port 443) + host + (or (= port 80) + (= port 443)) + port + path)) + +(defun make-request-buffer (host port path &key (method "GET")) + (setf method (string method)) + (when *proxy-url* + (setf path (full-proxy-path host port path))) + (let ((sink (make-instance 'octet-sink))) + (flet ((add-line (&rest strings) + (apply #'add-strings sink strings) + (add-newline sink))) + (add-line method " " path " HTTP/1.1") + (add-line "Host: " host (if (= port 80) "" + (format nil ":~D" port))) + (add-line "Connection: close") + ;; FIXME: get this version string from somewhere else. + (add-line "User-Agent: quicklisp-bootstrap/" + qlqs-info:*version*) + (add-newline sink) + (sink-buffer sink)))) + +(defun sink-until-matching (matcher cbuf) + (let ((sink (make-instance 'octet-sink))) + (call-until-matching + matcher + (lambda (buffer start end) + (add-octets buffer sink :start start :end end)) + cbuf) + (sink-buffer sink))) + + +;;; HTTP headers + +(defclass header () + ((data + :initarg :data + :accessor data) + (status + :initarg :status + :accessor status) + (name-starts + :initarg :name-starts + :accessor name-starts) + (name-ends + :initarg :name-ends + :accessor name-ends) + (value-starts + :initarg :value-starts + :accessor value-starts) + (value-ends + :initarg :value-ends + :accessor value-ends))) + +(defmethod print-object ((header header) stream) + (print-unreadable-object (header stream :type t) + (prin1 (status header) stream))) + +(defun matches-at (pattern target pos) + (= (mismatch pattern target :start2 pos) (length pattern))) + +(defun header-value-indexes (field-name header) + (loop with data = (data header) + with pattern = (ascii-vector (string-downcase field-name)) + for start across (name-starts header) + for i from 0 + when (matches-at pattern data start) + return (values (aref (value-starts header) i) + (aref (value-ends header) i)))) + +(defun ascii-header-value (field-name header) + (multiple-value-bind (start end) + (header-value-indexes field-name header) + (when start + (ascii-subseq (data header) start end)))) + +(defun all-field-names (header) + (map 'list + (lambda (start end) + (ascii-subseq (data header) start end)) + (name-starts header) + (name-ends header))) + +(defun headers-alist (header) + (mapcar (lambda (name) + (cons name (ascii-header-value name header))) + (all-field-names header))) + +(defmethod describe-object :after ((header header) stream) + (format stream "~&Decoded headers:~% ~S~%" (headers-alist header))) + +(defun content-length (header) + (let ((field-value (ascii-header-value "content-length" header))) + (when field-value + (let ((value (ignore-errors (parse-integer field-value)))) + (or value + (error "Content-Length header field value is not a number -- ~A" + field-value)))))) + +(defun chunkedp (header) + (string= (ascii-header-value "transfer-encoding" header) "chunked")) + +(defun location (header) + (ascii-header-value "location" header)) + +(defun status-code (vector) + (let* ((space (position (acode #\Space) vector)) + (c1 (- (aref vector (incf space)) 48)) + (c2 (- (aref vector (incf space)) 48)) + (c3 (- (aref vector (incf space)) 48))) + (+ (* c1 100) + (* c2 10) + (* c3 1)))) + +(defun force-downcase-field-names (header) + (loop with data = (data header) + for start across (name-starts header) + for end across (name-ends header) + do (loop for i from start below end + for code = (aref data i) + do (setf (aref data i) (ascii-downcase code))))) + +(defun skip-white-forward (pos vector) + (position-if-not 'whitep vector :start pos)) + +(defun skip-white-backward (pos vector) + (let ((nonwhite (position-if-not 'whitep vector :end pos :from-end t))) + (if nonwhite + (1+ nonwhite) + pos))) + +(defun contract-field-value-indexes (header) + "Header field values exclude leading and trailing whitespace; adjust +the indexes in the header accordingly." + (loop with starts = (value-starts header) + with ends = (value-ends header) + with data = (data header) + for i from 0 + for start across starts + for end across ends + do + (setf (aref starts i) (skip-white-forward start data)) + (setf (aref ends i) (skip-white-backward end data)))) + +(defun next-line-pos (vector) + (let ((pos 0)) + (labels ((finish (&optional (i pos)) + (return-from next-line-pos i)) + (after-cr (code) + (acase code + (:lf (finish pos)) + (t (finish (1- pos))))) + (pending (code) + (acase code + (:cr #'after-cr) + (:lf (finish pos)) + (t #'pending)))) + (let ((state #'pending)) + (loop + (setf state (funcall state (aref vector pos))) + (incf pos)))))) + +(defun make-hvector () + (make-array 16 :fill-pointer 0 :adjustable t)) + +(defun process-header (vector) + "Create a HEADER instance from the octet data in VECTOR." + (let* ((name-starts (make-hvector)) + (name-ends (make-hvector)) + (value-starts (make-hvector)) + (value-ends (make-hvector)) + (header (make-instance 'header + :data vector + :status 999 + :name-starts name-starts + :name-ends name-ends + :value-starts value-starts + :value-ends value-ends)) + (mark nil) + (pos (next-line-pos vector))) + (unless pos + (error "Unable to process HTTP header")) + (setf (status header) (status-code vector)) + (labels ((save (value vector) + (vector-push-extend value vector)) + (mark () + (setf mark pos)) + (clear-mark () + (setf mark nil)) + (finish () + (if mark + (save mark value-ends) + (save pos value-ends)) + (force-downcase-field-names header) + (contract-field-value-indexes header) + (return-from process-header header)) + (in-new-line (code) + (acase code + ((#\Tab #\Space) (setf mark nil) #'in-value) + (t + (when mark + (save mark value-ends)) + (clear-mark) + (save pos name-starts) + (in-name code)))) + (after-cr (code) + (acase code + (:lf #'in-new-line) + (t (in-new-line code)))) + (pending-value (code) + (acase code + ((#\Tab #\Space) #'pending-value) + (:cr #'after-cr) + (:lf #'in-new-line) + (t (save pos value-starts) #'in-value))) + (in-name (code) + (acase code + (#\: + (save pos name-ends) + (save (1+ pos) value-starts) + #'in-value) + ((:cr :lf) + (finish)) + ((#\Tab #\Space) + (error "Unexpected whitespace in header field name")) + (t + (unless (<= 0 code 127) + (error "Unexpected non-ASCII header field name")) + #'in-name))) + (in-value (code) + (acase code + (:lf (mark) #'in-new-line) + (:cr (mark) #'after-cr) + (t #'in-value)))) + (let ((state #'in-new-line)) + (loop + (incf pos) + (when (<= (length vector) pos) + (error "No header found in response")) + (setf state (funcall state (aref vector pos)))))))) + + +;;; HTTP URL parsing + +(defclass url () + ((hostname + :initarg :hostname + :accessor hostname + :initform nil) + (port + :initarg :port + :accessor port + :initform 80) + (path + :initarg :path + :accessor path + :initform "/"))) + +(defun parse-urlstring (urlstring) + (setf urlstring (string-trim " " urlstring)) + (let* ((pos (mismatch urlstring "http://" :test 'char-equal)) + (mark pos) + (url (make-instance 'url))) + (labels ((save () + (subseq urlstring mark pos)) + (mark () + (setf mark pos)) + (finish () + (return-from parse-urlstring url)) + (hostname-char-p (char) + (position char "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_." + :test 'char-equal)) + (at-start (char) + (case char + (#\/ + (setf (port url) nil) + (mark) + #'in-path) + (t + #'in-host))) + (in-host (char) + (case char + ((#\/ :end) + (setf (hostname url) (save)) + (mark) + #'in-path) + (#\: + (setf (hostname url) (save)) + (mark) + #'in-port) + (t + (unless (hostname-char-p char) + (error "~S is not a valid URL" urlstring)) + #'in-host))) + (in-port (char) + (case char + ((#\/ :end) + (setf (port url) + (parse-integer urlstring + :start (1+ mark) + :end pos)) + (mark) + #'in-path) + (t + (unless (digit-char-p char) + (error "Bad port in URL ~S" urlstring)) + #'in-port))) + (in-path (char) + (case char + ((#\# :end) + (setf (path url) (save)) + (finish))) + #'in-path)) + (let ((state #'at-start)) + (loop + (when (<= (length urlstring) pos) + (funcall state :end) + (finish)) + (setf state (funcall state (aref urlstring pos))) + (incf pos)))))) + +(defun url (thing) + (if (stringp thing) + (parse-urlstring thing) + thing)) + +(defgeneric request-buffer (method url) + (:method (method url) + (setf url (url url)) + (make-request-buffer (hostname url) (port url) (path url) + :method method))) + +(defun urlstring (url) + (format nil "~@[http://~A~]~@[:~D~]~A" + (hostname url) + (and (/= 80 (port url)) (port url)) + (path url))) + +(defmethod print-object ((url url) stream) + (print-unreadable-object (url stream :type t) + (prin1 (urlstring url) stream))) + +(defun merge-urls (url1 url2) + (setf url1 (url url1)) + (setf url2 (url url2)) + (make-instance 'url + :hostname (or (hostname url1) + (hostname url2)) + :port (or (port url1) + (port url2)) + :path (or (path url1) + (path url2)))) + + +;;; Requesting an URL and saving it to a file + +(defparameter *maximum-redirects* 10) +(defvar *default-url-defaults* (url "http://src.quicklisp.org/")) + +(defun read-http-header (cbuf) + (let ((header-data (sink-until-matching (list (acode-matcher :lf :lf) + (acode-matcher :cr :cr) + (acode-matcher :cr :lf :cr :lf)) + cbuf))) + (process-header header-data))) + +(defun read-chunk-header (cbuf) + (let* ((header-data (sink-until-matching (acode-matcher :cr :lf) cbuf)) + (end (or (position (acode :cr) header-data) + (position (acode #\;) header-data)))) + (values (parse-integer (ascii-subseq header-data 0 end) :radix 16)))) + +(defun save-chunk-response (stream cbuf) + "For a chunked response, read all chunks and write them to STREAM." + (let ((fun (make-stream-writer stream)) + (matcher (acode-matcher :cr :lf))) + (loop + (let ((chunk-size (read-chunk-header cbuf))) + (when (zerop chunk-size) + (return)) + (call-for-n-octets chunk-size fun cbuf) + (skip-until-matching matcher cbuf))))) + +(defun save-response (file header cbuf) + (with-open-file (stream file + :direction :output + :if-exists :supersede + :element-type 'octet) + (let ((content-length (content-length header))) + (cond ((chunkedp header) + (save-chunk-response stream cbuf)) + (content-length + (call-for-n-octets content-length + (make-stream-writer stream) + cbuf)) + (t + (call-until-end (make-stream-writer stream) cbuf)))))) + +(defun call-with-progress-bar (size fun) + (let ((progress-bar (make-progress-bar size))) + (start-display progress-bar) + (flet ((update (condition) + (update-progress progress-bar + (cbuf-progress-size condition)))) + (handler-bind ((cbuf-progress #'update)) + (funcall fun))) + (finish-display progress-bar))) + +(defun fetch (url file &key (follow-redirects t) quietly + (maximum-redirects *maximum-redirects*)) + "Request URL and write the body of the response to FILE." + (setf url (merge-urls url *default-url-defaults*)) + (setf file (merge-pathnames file)) + (let ((redirect-count 0) + (original-url url) + (connect-url (or (url *proxy-url*) url)) + (stream (if quietly + (make-broadcast-stream) + *trace-output*))) + (loop + (when (<= maximum-redirects redirect-count) + (error "Too many redirects for ~A" original-url)) + (with-connection (connection (hostname connect-url) (port connect-url)) + (let ((cbuf (make-instance 'cbuf :connection connection)) + (request (request-buffer "GET" url))) + (write-octets request connection) + (let ((header (read-http-header cbuf))) + (loop while (= (status header) 100) + do (setf header (read-http-header cbuf))) + (cond ((= (status header) 200) + (let ((size (content-length header))) + (format stream "~&; Fetching ~A~%" url) + (if (and (numberp size) + (plusp size)) + (format stream "; ~$KB~%" (/ size 1024)) + (format stream "; Unknown size~%")) + (if quietly + (save-response file header cbuf) + (call-with-progress-bar (content-length header) + (lambda () + (save-response file header cbuf)))))) + ((not (<= 300 (status header) 399)) + (error "Unexpected status for ~A: ~A" + url (status header)))) + (if (and follow-redirects (<= 300 (status header) 399)) + (let ((new-urlstring (ascii-header-value "location" header))) + (when (not new-urlstring) + (error "Redirect code ~D received, but no Location: header" + (status header))) + (incf redirect-count) + (setf url (merge-urls new-urlstring + url)) + (format stream "~&; Redirecting to ~A~%" url)) + (return (values header (and file (probe-file file))))))))))) + + +;;; A primitive tar unpacker + +(in-package #:qlqs-minitar) + +(defun make-block-buffer () + (make-array 512 :element-type '(unsigned-byte 8) :initial-element 0)) + +(defun skip-n-blocks (n stream) + (let ((block (make-block-buffer))) + (dotimes (i n) + (read-sequence block stream)))) + +(defun ascii-subseq (vector start end) + (let ((string (make-string (- end start)))) + (loop for i from 0 + for j from start below end + do (setf (char string i) (code-char (aref vector j)))) + string)) + +(defun block-asciiz-string (block start length) + (let* ((end (+ start length)) + (eos (or (position 0 block :start start :end end) + end))) + (ascii-subseq block start eos))) + +(defun prefix (header) + (when (plusp (aref header 345)) + (block-asciiz-string header 345 155))) + +(defun name (header) + (block-asciiz-string header 0 100)) + +(defun payload-size (header) + (values (parse-integer (block-asciiz-string header 124 12) :radix 8))) + +(defun nth-block (n file) + (with-open-file (stream file :element-type '(unsigned-byte 8)) + (let ((block (make-block-buffer))) + (skip-n-blocks (1- n) stream) + (read-sequence block stream) + block))) + +(defun payload-type (code) + (case code + (0 :file) + (48 :file) + (53 :directory) + (t :unsupported))) + +(defun full-path (header) + (let ((prefix (prefix header)) + (name (name header))) + (if prefix + (format nil "~A/~A" prefix name) + name))) + +(defun save-file (file size stream) + (multiple-value-bind (full-blocks partial) + (truncate size 512) + (ensure-directories-exist file) + (with-open-file (outstream file + :direction :output + :if-exists :supersede + :element-type '(unsigned-byte 8)) + (let ((block (make-block-buffer))) + (dotimes (i full-blocks) + (read-sequence block stream) + (write-sequence block outstream)) + (when (plusp partial) + (read-sequence block stream) + (write-sequence block outstream :end partial)))))) + +(defun unpack-tarball (tarfile &key (directory *default-pathname-defaults*)) + (let ((block (make-block-buffer))) + (with-open-file (stream tarfile :element-type '(unsigned-byte 8)) + (loop + (let ((size (read-sequence block stream))) + (when (zerop size) + (return)) + (unless (= size 512) + (error "Bad size on tarfile")) + (when (every #'zerop block) + (return)) + (let* ((payload-code (aref block 156)) + (payload-type (payload-type payload-code)) + (tar-path (full-path block)) + (full-path (merge-pathnames tar-path directory)) + (payload-size (payload-size block))) + (case payload-type + (:file + (save-file full-path payload-size stream)) + (:directory + (ensure-directories-exist full-path)) + (t + (warn "Unknown tar block payload code -- ~D" payload-code) + (skip-n-blocks (ceiling (payload-size block) 512) stream))))))))) + +(defun contents (tarfile) + (let ((block (make-block-buffer)) + (result '())) + (with-open-file (stream tarfile :element-type '(unsigned-byte 8)) + (loop + (let ((size (read-sequence block stream))) + (when (zerop size) + (return (nreverse result))) + (unless (= size 512) + (error "Bad size on tarfile")) + (when (every #'zerop block) + (return (nreverse result))) + (let* ((payload-type (payload-type (aref block 156))) + (tar-path (full-path block)) + (payload-size (payload-size block))) + (skip-n-blocks (ceiling payload-size 512) stream) + (case payload-type + (:file + (push tar-path result)) + (:directory + (push tar-path result))))))))) + + +;;; +;;; The actual bootstrapping work +;;; + +(in-package #:quicklisp-quickstart) + +(defvar *home* + (merge-pathnames (make-pathname :directory '(:relative "quicklisp")) + (user-homedir-pathname))) + +(defun qmerge (pathname) + (merge-pathnames pathname *home*)) + +(defun renaming-fetch (url file) + (let ((tmpfile (qmerge "tmp/fetch.dat"))) + (fetch url tmpfile) + (rename-file tmpfile file))) + +(defvar *quickstart-parameters* nil + "This plist is populated with parameters that may carry over to the + initial configuration of the client, e.g. :proxy-url + or :initial-dist-url") + +(defvar *quicklisp-hostname* "beta.quicklisp.org") + +(defvar *client-info-url* + (format nil "http://~A/client/quicklisp.sexp" + *quicklisp-hostname*)) + +(defclass client-info () + ((setup-url + :reader setup-url + :initarg :setup-url) + (asdf-url + :reader asdf-url + :initarg :asdf-url) + (client-tar-url + :reader client-tar-url + :initarg :client-tar-url) + (version + :reader version + :initarg :version) + (plist + :reader plist + :initarg :plist) + (source-file + :reader source-file + :initarg :source-file))) + +(defmethod print-object ((client-info client-info) stream) + (print-unreadable-object (client-info stream :type t) + (prin1 (version client-info) stream))) + +(defun safely-read (stream) + (let ((*read-eval* nil)) + (read stream))) + +(defun fetch-client-info-plist (url) + "Fetch and return the client info data at URL." + (let ((local-client-info-file (qmerge "tmp/client-info.sexp"))) + (ensure-directories-exist local-client-info-file) + (renaming-fetch url local-client-info-file) + (with-open-file (stream local-client-info-file) + (list* :source-file local-client-info-file + (safely-read stream))))) + +(defun fetch-client-info (url) + (let ((plist (fetch-client-info-plist url))) + (destructuring-bind (&key setup asdf client-tar version + source-file + &allow-other-keys) + plist + (unless (and setup asdf client-tar version) + (error "Invalid data from client info URL -- ~A" url)) + (make-instance 'client-info + :setup-url (getf setup :url) + :asdf-url (getf asdf :url) + :client-tar-url (getf client-tar :url) + :version version + :plist plist + :source-file source-file)))) + +(defun client-info-url-from-version (version) + (format nil "http://~A/client/~A/client-info.sexp" + *quicklisp-hostname* + version)) + +(defun distinfo-url-from-version (version) + (format nil "http://~A/dist/~A/distinfo.txt" + *quicklisp-hostname* + version)) + +(defvar *help-message* + (format nil "~&~% ==== quicklisp quickstart install help ====~%~% ~ + quicklisp-quickstart:install can take the following ~ + optional arguments:~%~% ~ + :path \"/path/to/installation/\"~%~% ~ + :proxy \"http://your.proxy:port/\"~%~% ~ + :client-url ~%~% ~ + :client-version ~%~% ~ + :dist-url ~%~% ~ + :dist-version ~%~%")) + +(defvar *after-load-message* + (format nil "~&~% ==== quicklisp quickstart ~A loaded ====~%~% ~ + To continue with installation, evaluate: (quicklisp-quickstart:install)~%~% ~ + For installation options, evaluate: (quicklisp-quickstart:help)~%~%" + qlqs-info:*version*)) + +(defvar *after-initial-setup-message* + (with-output-to-string (*standard-output*) + (format t "~&~% ==== quicklisp installed ====~%~%") + (format t " To load a system, use: (ql:quickload \"system-name\")~%~%") + (format t " To find systems, use: (ql:system-apropos \"term\")~%~%") + (format t " To load Quicklisp every time you start Lisp, use: (ql:add-to-init-file)~%~%") + (format t " For more information, see http://www.quicklisp.org/beta/~%~%"))) + +(defun initial-install (&key (client-url *client-info-url*) dist-url) + (setf *quickstart-parameters* + (list :proxy-url *proxy-url* + :initial-dist-url dist-url)) + (ensure-directories-exist (qmerge "tmp/")) + (let ((client-info (fetch-client-info client-url)) + (tmptar (qmerge "tmp/quicklisp.tar")) + (setup (qmerge "setup.lisp")) + (asdf (qmerge "asdf.lisp"))) + (renaming-fetch (client-tar-url client-info) tmptar) + (unpack-tarball tmptar :directory (qmerge "./")) + (renaming-fetch (setup-url client-info) setup) + (renaming-fetch (asdf-url client-info) asdf) + (rename-file (source-file client-info) (qmerge "client-info.sexp")) + (load setup :verbose nil :print nil) + (write-string *after-initial-setup-message*) + (finish-output))) + +(defun help () + (write-string *help-message*) + t) + +(defun non-empty-file-namestring (pathname) + (let ((string (file-namestring pathname))) + (unless (or (null string) + (equal string "")) + string))) + +(defun install (&key ((:path *home*) *home*) + ((:proxy *proxy-url*) *proxy-url*) + client-url + client-version + dist-url + dist-version) + (setf *home* (merge-pathnames *home* (truename *default-pathname-defaults*))) + (let ((name (non-empty-file-namestring *home*))) + (when name + (warn "Making ~A part of the install pathname directory" + name) + ;; This corrects a pathname like "/foo/bar" to "/foo/bar/" and + ;; "foo" to "foo/" + (setf *home* + (make-pathname :defaults *home* + :directory (append (pathname-directory *home*) + (list name)))))) + (let ((setup-file (qmerge "setup.lisp"))) + (when (probe-file setup-file) + (multiple-value-bind (result proceed) + (with-simple-restart (load-setup "Load ~S" setup-file) + (error "Quicklisp has already been installed. Load ~S instead." + setup-file)) + (declare (ignore result)) + (when proceed + (return-from install (load setup-file)))))) + (if (find-package '#:ql) + (progn + (write-line "!!! Quicklisp has already been set up. !!!") + (write-string *after-initial-setup-message*) + t) + (call-with-quiet-compilation + (lambda () + (let ((client-url (or client-url + (and client-version + (client-info-url-from-version client-version)) + *client-info-url*)) + ;; It's ok for dist-url to be nil; there's a default in + ;; the client + (dist-url (or dist-url + (and dist-version + (distinfo-url-from-version dist-version))))) + (initial-install :client-url client-url + :dist-url dist-url)))))) + +(write-string *after-load-message*) + +;;; End of quicklisp.lisp diff --git a/sbcl/.quicklisp/asdf.lisp b/sbcl/.quicklisp/asdf.lisp new file mode 100644 index 0000000..283ad86 --- /dev/null +++ b/sbcl/.quicklisp/asdf.lisp @@ -0,0 +1,4516 @@ +;;; -*- mode: Common-Lisp; Base: 10 ; Syntax: ANSI-Common-Lisp ; coding: utf-8 -*- +;;; This is ASDF 2.26: Another System Definition Facility. +;;; +;;; Feedback, bug reports, and patches are all welcome: +;;; please mail to . +;;; Note first that the canonical source for ASDF is presently +;;; . +;;; +;;; If you obtained this copy from anywhere else, and you experience +;;; trouble using it, or find bugs, you may want to check at the +;;; location above for a more recent version (and for documentation +;;; and test files, if your copy came without them) before reporting +;;; bugs. There are usually two "supported" revisions - the git master +;;; branch is the latest development version, whereas the git release +;;; branch may be slightly older but is considered `stable' + +;;; -- LICENSE START +;;; (This is the MIT / X Consortium license as taken from +;;; http://www.opensource.org/licenses/mit-license.html on or about +;;; Monday; July 13, 2009) +;;; +;;; Copyright (c) 2001-2012 Daniel Barlow and contributors +;;; +;;; Permission is hereby granted, free of charge, to any person obtaining +;;; a copy of this software and associated documentation files (the +;;; "Software"), to deal in the Software without restriction, including +;;; without limitation the rights to use, copy, modify, merge, publish, +;;; distribute, sublicense, and/or sell copies of the Software, and to +;;; permit persons to whom the Software is furnished to do so, subject to +;;; the following conditions: +;;; +;;; The above copyright notice and this permission notice shall be +;;; included in all copies or substantial portions of the Software. +;;; +;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +;;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +;;; LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +;;; OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +;;; WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +;;; +;;; -- LICENSE END + +;;; The problem with writing a defsystem replacement is bootstrapping: +;;; we can't use defsystem to compile it. Hence, all in one file. + +#+xcvb (module ()) + +(cl:in-package :common-lisp-user) +#+genera (in-package :future-common-lisp-user) + +#-(or abcl allegro clisp clozure cmu cormanlisp ecl gcl genera lispworks mcl mkcl sbcl scl xcl) +(error "ASDF is not supported on your implementation. Please help us port it.") + +;;;; Create and setup packages in a way that is compatible with hot-upgrade. +;;;; See https://bugs.launchpad.net/asdf/+bug/485687 +;;;; See these two eval-when forms, and more near the end of the file. + +#+gcl (defpackage :asdf (:use :cl)) ;; GCL treats defpackage magically and needs this + +(eval-when (:load-toplevel :compile-toplevel :execute) + ;;; Before we do anything, some implementation-dependent tweaks + ;; (declaim (optimize (speed 1) (debug 3) (safety 3))) ; NO: trust implementation defaults. + #+allegro + (setf excl::*autoload-package-name-alist* + (remove "asdf" excl::*autoload-package-name-alist* + :test 'equalp :key 'car)) ; need that BEFORE any mention of package ASDF as below + #+gcl ;; Debian's GCL 2.7 has bugs with compiling multiple-value stuff, but can run ASDF 2.011 + (when (or (< system::*gcl-major-version* 2) ;; GCL 2.6 fails to fully compile ASDF at all + (and (= system::*gcl-major-version* 2) + (< system::*gcl-minor-version* 7))) + (pushnew :gcl-pre2.7 *features*)) + #+(or abcl (and allegro ics) (and (or clisp cmu ecl mkcl) unicode) + clozure lispworks (and sbcl sb-unicode) scl) + (pushnew :asdf-unicode *features*) + ;;; make package if it doesn't exist yet. + ;;; DEFPACKAGE may cause errors on discrepancies, so we avoid it. + (unless (find-package :asdf) + (make-package :asdf :use '(:common-lisp)))) + +(in-package :asdf) + +(eval-when (:load-toplevel :compile-toplevel :execute) + ;;; This would belong amongst implementation-dependent tweaks above, + ;;; except that the defun has to be in package asdf. + #+ecl (defun use-ecl-byte-compiler-p () (and (member :ecl-bytecmp *features*) t)) + #+ecl (unless (use-ecl-byte-compiler-p) (require :cmp)) + #+mkcl (require :cmp) + #+mkcl (setq clos::*redefine-class-in-place* t) ;; Make sure we have strict ANSI class redefinition semantics + + ;;; Package setup, step 2. + (defvar *asdf-version* nil) + (defvar *upgraded-p* nil) + (defvar *asdf-verbose* nil) ; was t from 2.000 to 2.014.12. + (defun find-symbol* (s p) + (find-symbol (string s) p)) + ;; Strip out formatting that is not supported on Genera. + ;; Has to be inside the eval-when to make Lispworks happy (!) + (defun strcat (&rest strings) + (apply 'concatenate 'string strings)) + (defmacro compatfmt (format) + #-(or gcl genera) format + #+(or gcl genera) + (loop :for (unsupported . replacement) :in + (append + '(("~3i~_" . "")) + #+genera '(("~@<" . "") ("; ~@;" . "; ") ("~@:>" . "") ("~:>" . ""))) :do + (loop :for found = (search unsupported format) :while found :do + (setf format (strcat (subseq format 0 found) replacement + (subseq format (+ found (length unsupported))))))) + format) + (let* (;; For bug reporting sanity, please always bump this version when you modify this file. + ;; Please also modify asdf.asd to reflect this change. The script bin/bump-version + ;; can help you do these changes in synch (look at the source for documentation). + ;; Relying on its automation, the version is now redundantly present on top of this file. + ;; "2.345" would be an official release + ;; "2.345.6" would be a development version in the official upstream + ;; "2.345.0.7" would be your seventh local modification of official release 2.345 + ;; "2.345.6.7" would be your seventh local modification of development version 2.345.6 + (asdf-version "2.26") + (existing-asdf (find-class 'component nil)) + (existing-version *asdf-version*) + (already-there (equal asdf-version existing-version))) + (unless (and existing-asdf already-there) + (when (and existing-asdf *asdf-verbose*) + (format *trace-output* + (compatfmt "~&~@<; ~@;Upgrading ASDF ~@[from version ~A ~]to version ~A~@:>~%") + existing-version asdf-version)) + (labels + ((present-symbol-p (symbol package) + (member (nth-value 1 (find-symbol* symbol package)) '(:internal :external))) + (present-symbols (package) + ;; #-genera (loop :for s :being :the :present-symbols :in package :collect s) #+genera + (let (l) + (do-symbols (s package) + (when (present-symbol-p s package) (push s l))) + (reverse l))) + (unlink-package (package) + (let ((u (find-package package))) + (when u + (ensure-unintern u (present-symbols u)) + (loop :for p :in (package-used-by-list u) :do + (unuse-package u p)) + (delete-package u)))) + (ensure-exists (name nicknames use) + (let ((previous + (remove-duplicates + (mapcar #'find-package (cons name nicknames)) + :from-end t))) + ;; do away with packages with conflicting (nick)names + (map () #'unlink-package (cdr previous)) + ;; reuse previous package with same name + (let ((p (car previous))) + (cond + (p + (rename-package p name nicknames) + (ensure-use p use) + p) + (t + (make-package name :nicknames nicknames :use use)))))) + (intern* (symbol package) + (intern (string symbol) package)) + (remove-symbol (symbol package) + (let ((sym (find-symbol* symbol package))) + (when sym + #-cormanlisp (unexport sym package) + (unintern sym package) + sym))) + (ensure-unintern (package symbols) + (loop :with packages = (list-all-packages) + :for sym :in symbols + :for removed = (remove-symbol sym package) + :when removed :do + (loop :for p :in packages :do + (when (eq removed (find-symbol* sym p)) + (unintern removed p))))) + (ensure-shadow (package symbols) + (shadow symbols package)) + (ensure-use (package use) + (dolist (used (package-use-list package)) + (unless (member (package-name used) use :test 'string=) + (unuse-package used) + (do-external-symbols (sym used) + (when (eq sym (find-symbol* sym package)) + (remove-symbol sym package))))) + (dolist (used (reverse use)) + (do-external-symbols (sym used) + (unless (eq sym (find-symbol* sym package)) + (remove-symbol sym package))) + (use-package used package))) + (ensure-fmakunbound (package symbols) + (loop :for name :in symbols + :for sym = (find-symbol* name package) + :when sym :do (fmakunbound sym))) + (ensure-export (package export) + (let ((formerly-exported-symbols nil) + (bothly-exported-symbols nil) + (newly-exported-symbols nil)) + (do-external-symbols (sym package) + (if (member sym export :test 'string-equal) + (push sym bothly-exported-symbols) + (push sym formerly-exported-symbols))) + (loop :for sym :in export :do + (unless (member sym bothly-exported-symbols :test 'equal) + (push sym newly-exported-symbols))) + (loop :for user :in (package-used-by-list package) + :for shadowing = (package-shadowing-symbols user) :do + (loop :for new :in newly-exported-symbols + :for old = (find-symbol* new user) + :when (and old (not (member old shadowing))) + :do (unintern old user))) + (loop :for x :in newly-exported-symbols :do + (export (intern* x package))))) + (ensure-package (name &key nicknames use unintern + shadow export redefined-functions) + (let* ((p (ensure-exists name nicknames use))) + (ensure-unintern p (append unintern #+cmu redefined-functions)) + (ensure-shadow p shadow) + (ensure-export p export) + #-cmu (ensure-fmakunbound p redefined-functions) + p))) + (macrolet + ((pkgdcl (name &key nicknames use export + redefined-functions unintern shadow) + `(ensure-package + ',name :nicknames ',nicknames :use ',use :export ',export + :shadow ',shadow + :unintern ',unintern + :redefined-functions ',redefined-functions))) + (pkgdcl + :asdf + :use (:common-lisp) + :redefined-functions + (#:perform #:explain #:output-files #:operation-done-p + #:perform-with-restarts #:component-relative-pathname + #:system-source-file #:operate #:find-component #:find-system + #:apply-output-translations #:translate-pathname* #:resolve-location + #:system-relative-pathname + #:inherit-source-registry #:process-source-registry + #:process-source-registry-directive + #:compile-file* #:source-file-type) + :unintern + (#:*asdf-revision* #:around #:asdf-method-combination + #:split #:make-collector #:do-dep #:do-one-dep + #:resolve-relative-location-component #:resolve-absolute-location-component + #:output-files-for-system-and-operation) ; obsolete ASDF-BINARY-LOCATION function + :export + (#:defsystem #:oos #:operate #:find-system #:locate-system #:run-shell-command + #:system-definition-pathname #:with-system-definitions + #:search-for-system-definition #:find-component #:component-find-path + #:compile-system #:load-system #:load-systems + #:require-system #:test-system #:clear-system + #:operation #:compile-op #:load-op #:load-source-op #:test-op + #:feature #:version #:version-satisfies + #:upgrade-asdf + #:implementation-identifier #:implementation-type #:hostname + #:input-files #:output-files #:output-file #:perform + #:operation-done-p #:explain + + #:component #:source-file + #:c-source-file #:cl-source-file #:java-source-file + #:cl-source-file.cl #:cl-source-file.lsp + #:static-file + #:doc-file + #:html-file + #:text-file + #:source-file-type + #:module ; components + #:system + #:unix-dso + + #:module-components ; component accessors + #:module-components-by-name + #:component-pathname + #:component-relative-pathname + #:component-name + #:component-version + #:component-parent + #:component-property + #:component-system + #:component-depends-on + #:component-encoding + #:component-external-format + + #:system-description + #:system-long-description + #:system-author + #:system-maintainer + #:system-license + #:system-licence + #:system-source-file + #:system-source-directory + #:system-relative-pathname + #:map-systems + + #:operation-description + #:operation-on-warnings + #:operation-on-failure + #:component-visited-p + + #:*system-definition-search-functions* ; variables + #:*central-registry* + #:*compile-file-warnings-behaviour* + #:*compile-file-failure-behaviour* + #:*resolve-symlinks* + #:*load-system-operation* + #:*asdf-verbose* + #:*verbose-out* + + #:asdf-version + + #:operation-error #:compile-failed #:compile-warned #:compile-error + #:error-name + #:error-pathname + #:load-system-definition-error + #:error-component #:error-operation + #:system-definition-error + #:missing-component + #:missing-component-of-version + #:missing-dependency + #:missing-dependency-of-version + #:circular-dependency ; errors + #:duplicate-names + + #:try-recompiling + #:retry + #:accept ; restarts + #:coerce-entry-to-directory + #:remove-entry-from-registry + + #:*encoding-detection-hook* + #:*encoding-external-format-hook* + #:*default-encoding* + #:*utf-8-external-format* + + #:clear-configuration + #:*output-translations-parameter* + #:initialize-output-translations + #:disable-output-translations + #:clear-output-translations + #:ensure-output-translations + #:apply-output-translations + #:compile-file* + #:compile-file-pathname* + #:enable-asdf-binary-locations-compatibility + #:*default-source-registries* + #:*source-registry-parameter* + #:initialize-source-registry + #:compute-source-registry + #:clear-source-registry + #:ensure-source-registry + #:process-source-registry + #:system-registered-p #:registered-systems #:loaded-systems + #:resolve-location + #:asdf-message + #:user-output-translations-pathname + #:system-output-translations-pathname + #:user-output-translations-directory-pathname + #:system-output-translations-directory-pathname + #:user-source-registry + #:system-source-registry + #:user-source-registry-directory + #:system-source-registry-directory + + ;; Utilities: please use asdf-utils instead + #| + ;; #:aif #:it + ;; #:appendf #:orf + #:length=n-p + #:remove-keys #:remove-keyword + #:first-char #:last-char #:string-suffix-p + #:coerce-name + #:directory-pathname-p #:ensure-directory-pathname + #:absolute-pathname-p #:ensure-pathname-absolute #:pathname-root + #:getenv #:getenv-pathname #:getenv-pathnames + #:getenv-absolute-directory #:getenv-absolute-directories + #:probe-file* + #:find-symbol* #:strcat + #:make-pathname-component-logical #:make-pathname-logical + #:merge-pathnames* #:coerce-pathname #:subpathname #:subpathname* + #:pathname-directory-pathname #:pathname-parent-directory-pathname + #:read-file-forms + #:resolve-symlinks #:truenamize + #:split-string + #:component-name-to-pathname-components + #:split-name-type + #:subdirectories #:directory-files + #:while-collecting + #:*wild* #:*wild-file* #:*wild-directory* #:*wild-inferiors* + #:*wild-path* #:wilden + #:directorize-pathname-host-device|# + ))) + #+genera (import 'scl:boolean :asdf) + (setf *asdf-version* asdf-version + *upgraded-p* (if existing-version + (cons existing-version *upgraded-p*) + *upgraded-p*)))))) + +;;;; ------------------------------------------------------------------------- +;;;; User-visible parameters +;;;; +(defvar *resolve-symlinks* t + "Determine whether or not ASDF resolves symlinks when defining systems. + +Defaults to T.") + +(defvar *compile-file-warnings-behaviour* + (or #+clisp :ignore :warn) + "How should ASDF react if it encounters a warning when compiling a file? +Valid values are :error, :warn, and :ignore.") + +(defvar *compile-file-failure-behaviour* + (or #+sbcl :error #+clisp :ignore :warn) + "How should ASDF react if it encounters a failure (per the ANSI spec of COMPILE-FILE) +when compiling a file? Valid values are :error, :warn, and :ignore. +Note that ASDF ALWAYS raises an error if it fails to create an output file when compiling.") + +(defvar *verbose-out* nil) + +(defparameter +asdf-methods+ + '(perform-with-restarts perform explain output-files operation-done-p)) + +(defvar *load-system-operation* 'load-op + "Operation used by ASDF:LOAD-SYSTEM. By default, ASDF:LOAD-OP. +You may override it with e.g. ASDF:LOAD-FASL-OP from asdf-bundle, +or ASDF:LOAD-SOURCE-OP if your fasl loading is somehow broken.") + +(defvar *compile-op-compile-file-function* 'compile-file* + "Function used to compile lisp files.") + + + +#+allegro +(eval-when (:compile-toplevel :execute) + (defparameter *acl-warn-save* + (when (boundp 'excl:*warn-on-nested-reader-conditionals*) + excl:*warn-on-nested-reader-conditionals*)) + (when (boundp 'excl:*warn-on-nested-reader-conditionals*) + (setf excl:*warn-on-nested-reader-conditionals* nil))) + +;;;; ------------------------------------------------------------------------- +;;;; Resolve forward references + +(declaim (ftype (function (t) t) + format-arguments format-control + error-name error-pathname error-condition + duplicate-names-name + error-component error-operation + module-components module-components-by-name + circular-dependency-components + condition-arguments condition-form + condition-format condition-location + coerce-name) + (ftype (function (&optional t) (values)) initialize-source-registry) + #-(or cormanlisp gcl-pre2.7) + (ftype (function (t t) t) (setf module-components-by-name))) + +;;;; ------------------------------------------------------------------------- +;;;; Compatibility various implementations +#+cormanlisp +(progn + (deftype logical-pathname () nil) + (defun make-broadcast-stream () *error-output*) + (defun translate-logical-pathname (x) x) + (defun file-namestring (p) + (setf p (pathname p)) + (format nil "~@[~A~]~@[.~A~]" (pathname-name p) (pathname-type p)))) + +#.(or #+mcl ;; the #$ doesn't work on other lisps, even protected by #+mcl + (read-from-string + "(eval-when (:compile-toplevel :load-toplevel :execute) + (ccl:define-entry-point (_getenv \"getenv\") ((name :string)) :string) + (ccl:define-entry-point (_system \"system\") ((name :string)) :int) + ;; Note: ASDF may expect user-homedir-pathname to provide + ;; the pathname of the current user's home directory, whereas + ;; MCL by default provides the directory from which MCL was started. + ;; See http://code.google.com/p/mcl/wiki/Portability + (defun current-user-homedir-pathname () + (ccl::findfolder #$kuserdomain #$kCurrentUserFolderType)) + (defun probe-posix (posix-namestring) + \"If a file exists for the posix namestring, return the pathname\" + (ccl::with-cstrs ((cpath posix-namestring)) + (ccl::rlet ((is-dir :boolean) + (fsref :fsref)) + (when (eq #$noerr (#_fspathmakeref cpath fsref is-dir)) + (ccl::%path-from-fsref fsref is-dir))))))")) + +;;;; ------------------------------------------------------------------------- +;;;; General Purpose Utilities + +(macrolet + ((defdef (def* def) + `(defmacro ,def* (name formals &rest rest) + `(progn + #+(or ecl (and gcl (not gcl-pre2.7))) (fmakunbound ',name) + #-gcl ; gcl 2.7.0 notinline functions lose secondary return values :-( + ,(when (and #+ecl (symbolp name)) ; fails for setf functions on ecl + `(declaim (notinline ,name))) + (,',def ,name ,formals ,@rest))))) + (defdef defgeneric* defgeneric) + (defdef defun* defun)) + +(defmacro while-collecting ((&rest collectors) &body body) + "COLLECTORS should be a list of names for collections. A collector +defines a function that, when applied to an argument inside BODY, will +add its argument to the corresponding collection. Returns multiple values, +a list for each collection, in order. + E.g., +\(while-collecting \(foo bar\) + \(dolist \(x '\(\(a 1\) \(b 2\) \(c 3\)\)\) + \(foo \(first x\)\) + \(bar \(second x\)\)\)\) +Returns two values: \(A B C\) and \(1 2 3\)." + (let ((vars (mapcar #'(lambda (x) (gensym (symbol-name x))) collectors)) + (initial-values (mapcar (constantly nil) collectors))) + `(let ,(mapcar #'list vars initial-values) + (flet ,(mapcar #'(lambda (c v) `(,c (x) (push x ,v) (values))) collectors vars) + ,@body + (values ,@(mapcar #'(lambda (v) `(reverse ,v)) vars)))))) + +(defmacro aif (test then &optional else) + "Anaphoric version of IF, On Lisp style" + `(let ((it ,test)) (if it ,then ,else))) + +(defun* pathname-directory-pathname (pathname) + "Returns a new pathname with same HOST, DEVICE, DIRECTORY as PATHNAME, +and NIL NAME, TYPE and VERSION components" + (when pathname + (make-pathname :name nil :type nil :version nil :defaults pathname))) + +(defun* normalize-pathname-directory-component (directory) + "Given a pathname directory component, return an equivalent form that is a list" + (cond + #-(or cmu sbcl scl) ;; these implementations already normalize directory components. + ((stringp directory) `(:absolute ,directory) directory) + #+gcl + ((and (consp directory) (stringp (first directory))) + `(:absolute ,@directory)) + ((or (null directory) + (and (consp directory) (member (first directory) '(:absolute :relative)))) + directory) + (t + (error (compatfmt "~@") directory)))) + +(defun* merge-pathname-directory-components (specified defaults) + ;; Helper for merge-pathnames* that handles directory components. + (let ((directory (normalize-pathname-directory-component specified))) + (ecase (first directory) + ((nil) defaults) + (:absolute specified) + (:relative + (let ((defdir (normalize-pathname-directory-component defaults)) + (reldir (cdr directory))) + (cond + ((null defdir) + directory) + ((not (eq :back (first reldir))) + (append defdir reldir)) + (t + (loop :with defabs = (first defdir) + :with defrev = (reverse (rest defdir)) + :while (and (eq :back (car reldir)) + (or (and (eq :absolute defabs) (null defrev)) + (stringp (car defrev)))) + :do (pop reldir) (pop defrev) + :finally (return (cons defabs (append (reverse defrev) reldir))))))))))) + +(defun* make-pathname-component-logical (x) + "Make a pathname component suitable for use in a logical-pathname" + (typecase x + ((eql :unspecific) nil) + #+clisp (string (string-upcase x)) + #+clisp (cons (mapcar 'make-pathname-component-logical x)) + (t x))) + +(defun* make-pathname-logical (pathname host) + "Take a PATHNAME's directory, name, type and version components, +and make a new pathname with corresponding components and specified logical HOST" + (make-pathname + :host host + :directory (make-pathname-component-logical (pathname-directory pathname)) + :name (make-pathname-component-logical (pathname-name pathname)) + :type (make-pathname-component-logical (pathname-type pathname)) + :version (make-pathname-component-logical (pathname-version pathname)))) + +(defun* merge-pathnames* (specified &optional (defaults *default-pathname-defaults*)) + "MERGE-PATHNAMES* is like MERGE-PATHNAMES except that +if the SPECIFIED pathname does not have an absolute directory, +then the HOST and DEVICE both come from the DEFAULTS, whereas +if the SPECIFIED pathname does have an absolute directory, +then the HOST and DEVICE both come from the SPECIFIED. +Also, if either argument is NIL, then the other argument is returned unmodified." + (when (null specified) (return-from merge-pathnames* defaults)) + (when (null defaults) (return-from merge-pathnames* specified)) + #+scl + (ext:resolve-pathname specified defaults) + #-scl + (let* ((specified (pathname specified)) + (defaults (pathname defaults)) + (directory (normalize-pathname-directory-component (pathname-directory specified))) + (name (or (pathname-name specified) (pathname-name defaults))) + (type (or (pathname-type specified) (pathname-type defaults))) + (version (or (pathname-version specified) (pathname-version defaults)))) + (labels ((unspecific-handler (p) + (if (typep p 'logical-pathname) #'make-pathname-component-logical #'identity))) + (multiple-value-bind (host device directory unspecific-handler) + (ecase (first directory) + ((:absolute) + (values (pathname-host specified) + (pathname-device specified) + directory + (unspecific-handler specified))) + ((nil :relative) + (values (pathname-host defaults) + (pathname-device defaults) + (merge-pathname-directory-components directory (pathname-directory defaults)) + (unspecific-handler defaults)))) + (make-pathname :host host :device device :directory directory + :name (funcall unspecific-handler name) + :type (funcall unspecific-handler type) + :version (funcall unspecific-handler version)))))) + +(defun* pathname-parent-directory-pathname (pathname) + "Returns a new pathname with same HOST, DEVICE, DIRECTORY as PATHNAME, +and NIL NAME, TYPE and VERSION components" + (when pathname + (make-pathname :name nil :type nil :version nil + :directory (merge-pathname-directory-components + '(:relative :back) (pathname-directory pathname)) + :defaults pathname))) + +(define-modify-macro appendf (&rest args) + append "Append onto list") ;; only to be used on short lists. + +(define-modify-macro orf (&rest args) + or "or a flag") + +(defun* first-char (s) + (and (stringp s) (plusp (length s)) (char s 0))) + +(defun* last-char (s) + (and (stringp s) (plusp (length s)) (char s (1- (length s))))) + + +(defun* asdf-message (format-string &rest format-args) + (declare (dynamic-extent format-args)) + (apply 'format *verbose-out* format-string format-args)) + +(defun* split-string (string &key max (separator '(#\Space #\Tab))) + "Split STRING into a list of components separated by +any of the characters in the sequence SEPARATOR. +If MAX is specified, then no more than max(1,MAX) components will be returned, +starting the separation from the end, e.g. when called with arguments + \"a.b.c.d.e\" :max 3 :separator \".\" it will return (\"a.b.c\" \"d\" \"e\")." + (catch nil + (let ((list nil) (words 0) (end (length string))) + (flet ((separatorp (char) (find char separator)) + (done () (throw nil (cons (subseq string 0 end) list)))) + (loop + :for start = (if (and max (>= words (1- max))) + (done) + (position-if #'separatorp string :end end :from-end t)) :do + (when (null start) + (done)) + (push (subseq string (1+ start) end) list) + (incf words) + (setf end start)))))) + +(defun* split-name-type (filename) + (let ((unspecific + ;; Giving :unspecific as argument to make-pathname is not portable. + ;; See CLHS make-pathname and 19.2.2.2.3. + ;; We only use it on implementations that support it, + #+(or abcl allegro clozure cmu gcl genera lispworks mkcl sbcl scl xcl) :unspecific + #+(or clisp ecl #|These haven't been tested:|# cormanlisp mcl) nil)) + (destructuring-bind (name &optional (type unspecific)) + (split-string filename :max 2 :separator ".") + (if (equal name "") + (values filename unspecific) + (values name type))))) + +(defun* component-name-to-pathname-components (s &key force-directory force-relative) + "Splits the path string S, returning three values: +A flag that is either :absolute or :relative, indicating + how the rest of the values are to be interpreted. +A directory path --- a list of strings, suitable for + use with MAKE-PATHNAME when prepended with the flag + value. +A filename with type extension, possibly NIL in the + case of a directory pathname. +FORCE-DIRECTORY forces S to be interpreted as a directory +pathname \(third return value will be NIL, final component +of S will be treated as part of the directory path. + +The intention of this function is to support structured component names, +e.g., \(:file \"foo/bar\"\), which will be unpacked to relative +pathnames." + (check-type s string) + (when (find #\: s) + (error (compatfmt "~@") s)) + (let* ((components (split-string s :separator "/")) + (last-comp (car (last components)))) + (multiple-value-bind (relative components) + (if (equal (first components) "") + (if (equal (first-char s) #\/) + (progn + (when force-relative + (error (compatfmt "~@") s)) + (values :absolute (cdr components))) + (values :relative nil)) + (values :relative components)) + (setf components (remove-if #'(lambda (x) (member x '("" ".") :test #'equal)) components)) + (setf components (substitute :back ".." components :test #'equal)) + (cond + ((equal last-comp "") + (values relative components nil)) ; "" already removed + (force-directory + (values relative components nil)) + (t + (values relative (butlast components) last-comp)))))) + +(defun* remove-keys (key-names args) + (loop :for (name val) :on args :by #'cddr + :unless (member (symbol-name name) key-names + :key #'symbol-name :test 'equal) + :append (list name val))) + +(defun* remove-keyword (key args) + (loop :for (k v) :on args :by #'cddr + :unless (eq k key) + :append (list k v))) + +(defun* getenv (x) + (declare (ignorable x)) + #+(or abcl clisp ecl xcl) (ext:getenv x) + #+allegro (sys:getenv x) + #+clozure (ccl:getenv x) + #+(or cmu scl) (cdr (assoc x ext:*environment-list* :test #'string=)) + #+cormanlisp + (let* ((buffer (ct:malloc 1)) + (cname (ct:lisp-string-to-c-string x)) + (needed-size (win:getenvironmentvariable cname buffer 0)) + (buffer1 (ct:malloc (1+ needed-size)))) + (prog1 (if (zerop (win:getenvironmentvariable cname buffer1 needed-size)) + nil + (ct:c-string-to-lisp-string buffer1)) + (ct:free buffer) + (ct:free buffer1))) + #+gcl (system:getenv x) + #+genera nil + #+lispworks (lispworks:environment-variable x) + #+mcl (ccl:with-cstrs ((name x)) + (let ((value (_getenv name))) + (unless (ccl:%null-ptr-p value) + (ccl:%get-cstring value)))) + #+mkcl (#.(or (find-symbol* 'getenv :si) (find-symbol* 'getenv :mk-ext)) x) + #+sbcl (sb-ext:posix-getenv x) + #-(or abcl allegro clisp clozure cmu cormanlisp ecl gcl genera lispworks mcl mkcl sbcl scl xcl) + (error "~S is not supported on your implementation" 'getenv)) + +(defun* directory-pathname-p (pathname) + "Does PATHNAME represent a directory? + +A directory-pathname is a pathname _without_ a filename. The three +ways that the filename components can be missing are for it to be NIL, +:UNSPECIFIC or the empty string. + +Note that this does _not_ check to see that PATHNAME points to an +actually-existing directory." + (when pathname + (let ((pathname (pathname pathname))) + (flet ((check-one (x) + (member x '(nil :unspecific "") :test 'equal))) + (and (not (wild-pathname-p pathname)) + (check-one (pathname-name pathname)) + (check-one (pathname-type pathname)) + t))))) + +(defun* ensure-directory-pathname (pathspec) + "Converts the non-wild pathname designator PATHSPEC to directory form." + (cond + ((stringp pathspec) + (ensure-directory-pathname (pathname pathspec))) + ((not (pathnamep pathspec)) + (error (compatfmt "~@") pathspec)) + ((wild-pathname-p pathspec) + (error (compatfmt "~@") pathspec)) + ((directory-pathname-p pathspec) + pathspec) + (t + (make-pathname :directory (append (or (pathname-directory pathspec) + (list :relative)) + (list (file-namestring pathspec))) + :name nil :type nil :version nil + :defaults pathspec)))) + +#+genera +(unless (fboundp 'ensure-directories-exist) + (defun* ensure-directories-exist (path) + (fs:create-directories-recursively (pathname path)))) + +(defun* absolute-pathname-p (pathspec) + (and (typep pathspec '(or pathname string)) + (eq :absolute (car (pathname-directory (pathname pathspec)))))) + +(defun* coerce-pathname (name &key type defaults) + "coerce NAME into a PATHNAME. +When given a string, portably decompose it into a relative pathname: +#\\/ separates subdirectories. The last #\\/-separated string is as follows: +if TYPE is NIL, its last #\\. if any separates name and type from from type; +if TYPE is a string, it is the type, and the whole string is the name; +if TYPE is :DIRECTORY, the string is a directory component; +if the string is empty, it's a directory. +Any directory named .. is read as :BACK. +Host, device and version components are taken from DEFAULTS." + ;; The defaults are required notably because they provide the default host + ;; to the below make-pathname, which may crucially matter to people using + ;; merge-pathnames with non-default hosts, e.g. for logical-pathnames. + ;; NOTE that the host and device slots will be taken from the defaults, + ;; but that should only matter if you later merge relative pathnames with + ;; CL:MERGE-PATHNAMES instead of ASDF:MERGE-PATHNAMES* + (etypecase name + ((or null pathname) + name) + (symbol + (coerce-pathname (string-downcase name) :type type :defaults defaults)) + (string + (multiple-value-bind (relative path filename) + (component-name-to-pathname-components name :force-directory (eq type :directory) + :force-relative t) + (multiple-value-bind (name type) + (cond + ((or (eq type :directory) (null filename)) + (values nil nil)) + (type + (values filename type)) + (t + (split-name-type filename))) + (apply 'make-pathname :directory (cons relative path) :name name :type type + (when defaults `(:defaults ,defaults)))))))) + +(defun* merge-component-name-type (name &key type defaults) + ;; For backwards compatibility only, for people using internals. + ;; Will be removed in a future release, e.g. 2.016. + (warn "Please don't use ASDF::MERGE-COMPONENT-NAME-TYPE. Use ASDF:COERCE-PATHNAME.") + (coerce-pathname name :type type :defaults defaults)) + +(defun* subpathname (pathname subpath &key type) + (and pathname (merge-pathnames* (coerce-pathname subpath :type type) + (pathname-directory-pathname pathname)))) + +(defun subpathname* (pathname subpath &key type) + (and pathname + (subpathname (ensure-directory-pathname pathname) subpath :type type))) + +(defun* length=n-p (x n) ;is it that (= (length x) n) ? + (check-type n (integer 0 *)) + (loop + :for l = x :then (cdr l) + :for i :downfrom n :do + (cond + ((zerop i) (return (null l))) + ((not (consp l)) (return nil))))) + +(defun* string-suffix-p (s suffix) + (check-type s string) + (check-type suffix string) + (let ((start (- (length s) (length suffix)))) + (and (<= 0 start) + (string-equal s suffix :start1 start)))) + +(defun* read-file-forms (file) + (with-open-file (in file) + (loop :with eof = (list nil) + :for form = (read in nil eof) + :until (eq form eof) + :collect form))) + +(defun* pathname-root (pathname) + (make-pathname :directory '(:absolute) + :name nil :type nil :version nil + :defaults pathname ;; host device, and on scl, *some* + ;; scheme-specific parts: port username password, not others: + . #.(or #+scl '(:parameters nil :query nil :fragment nil)))) + +(defun* probe-file* (p) + "when given a pathname P, probes the filesystem for a file or directory +with given pathname and if it exists return its truename." + (etypecase p + (null nil) + (string (probe-file* (parse-namestring p))) + (pathname (unless (wild-pathname-p p) + #.(or #+(or allegro clozure cmu cormanlisp ecl lispworks mkcl sbcl scl) + '(probe-file p) + #+clisp (aif (find-symbol* '#:probe-pathname :ext) + `(ignore-errors (,it p))) + '(ignore-errors (truename p))))))) + +(defun* truenamize (pathname &optional (defaults *default-pathname-defaults*)) + "Resolve as much of a pathname as possible" + (block nil + (when (typep pathname '(or null logical-pathname)) (return pathname)) + (let ((p (merge-pathnames* pathname defaults))) + (when (typep p 'logical-pathname) (return p)) + (let ((found (probe-file* p))) + (when found (return found))) + (unless (absolute-pathname-p p) + (let ((true-defaults (ignore-errors (truename defaults)))) + (when true-defaults + (setf p (merge-pathnames pathname true-defaults))))) + (unless (absolute-pathname-p p) (return p)) + (let ((sofar (probe-file* (pathname-root p)))) + (unless sofar (return p)) + (flet ((solution (directories) + (merge-pathnames* + (make-pathname :host nil :device nil + :directory `(:relative ,@directories) + :name (pathname-name p) + :type (pathname-type p) + :version (pathname-version p)) + sofar))) + (loop :with directory = (normalize-pathname-directory-component + (pathname-directory p)) + :for component :in (cdr directory) + :for rest :on (cdr directory) + :for more = (probe-file* + (merge-pathnames* + (make-pathname :directory `(:relative ,component)) + sofar)) :do + (if more + (setf sofar more) + (return (solution rest))) + :finally + (return (solution nil)))))))) + +(defun* resolve-symlinks (path) + #-allegro (truenamize path) + #+allegro (if (typep path 'logical-pathname) + path + (excl:pathname-resolve-symbolic-links path))) + +(defun* resolve-symlinks* (path) + (if *resolve-symlinks* + (and path (resolve-symlinks path)) + path)) + +(defun* ensure-pathname-absolute (path) + (cond + ((absolute-pathname-p path) path) + ((stringp path) (ensure-pathname-absolute (pathname path))) + ((not (pathnamep path)) (error "not a valid pathname designator ~S" path)) + (t (let ((resolved (resolve-symlinks path))) + (assert (absolute-pathname-p resolved)) + resolved)))) + +(defun* default-directory () + (truenamize (pathname-directory-pathname *default-pathname-defaults*))) + +(defun* lispize-pathname (input-file) + (make-pathname :type "lisp" :defaults input-file)) + +(defparameter *wild* #-cormanlisp :wild #+cormanlisp "*") +(defparameter *wild-file* + (make-pathname :name *wild* :type *wild* + :version (or #-(or abcl xcl) *wild*) :directory nil)) +(defparameter *wild-directory* + (make-pathname :directory `(:relative ,*wild*) :name nil :type nil :version nil)) +(defparameter *wild-inferiors* + (make-pathname :directory '(:relative :wild-inferiors) :name nil :type nil :version nil)) +(defparameter *wild-path* + (merge-pathnames *wild-file* *wild-inferiors*)) + +(defun* wilden (path) + (merge-pathnames* *wild-path* path)) + +#-scl +(defun* directory-separator-for-host (&optional (pathname *default-pathname-defaults*)) + (let ((foo (make-pathname :directory '(:absolute "FOO") :defaults pathname))) + (last-char (namestring foo)))) + +#-scl +(defun* directorize-pathname-host-device (pathname) + (let* ((root (pathname-root pathname)) + (wild-root (wilden root)) + (absolute-pathname (merge-pathnames* pathname root)) + (separator (directory-separator-for-host root)) + (root-namestring (namestring root)) + (root-string + (substitute-if #\/ + #'(lambda (x) (or (eql x #\:) + (eql x separator))) + root-namestring))) + (multiple-value-bind (relative path filename) + (component-name-to-pathname-components root-string :force-directory t) + (declare (ignore relative filename)) + (let ((new-base + (make-pathname :defaults root + :directory `(:absolute ,@path)))) + (translate-pathname absolute-pathname wild-root (wilden new-base)))))) + +#+scl +(defun* directorize-pathname-host-device (pathname) + (let ((scheme (ext:pathname-scheme pathname)) + (host (pathname-host pathname)) + (port (ext:pathname-port pathname)) + (directory (pathname-directory pathname))) + (flet ((specificp (x) (and x (not (eq x :unspecific))))) + (if (or (specificp port) + (and (specificp host) (plusp (length host))) + (specificp scheme)) + (let ((prefix "")) + (when (specificp port) + (setf prefix (format nil ":~D" port))) + (when (and (specificp host) (plusp (length host))) + (setf prefix (strcat host prefix))) + (setf prefix (strcat ":" prefix)) + (when (specificp scheme) + (setf prefix (strcat scheme prefix))) + (assert (and directory (eq (first directory) :absolute))) + (make-pathname :directory `(:absolute ,prefix ,@(rest directory)) + :defaults pathname))) + pathname))) + +;;;; ------------------------------------------------------------------------- +;;;; ASDF Interface, in terms of generic functions. +(defgeneric* find-system (system &optional error-p)) +(defgeneric* perform-with-restarts (operation component)) +(defgeneric* perform (operation component)) +(defgeneric* operation-done-p (operation component)) +(defgeneric* mark-operation-done (operation component)) +(defgeneric* explain (operation component)) +(defgeneric* output-files (operation component)) +(defgeneric* input-files (operation component)) +(defgeneric* component-operation-time (operation component)) +(defgeneric* operation-description (operation component) + (:documentation "returns a phrase that describes performing this operation +on this component, e.g. \"loading /a/b/c\". +You can put together sentences using this phrase.")) + +(defgeneric* system-source-file (system) + (:documentation "Return the source file in which system is defined.")) + +(defgeneric* component-system (component) + (:documentation "Find the top-level system containing COMPONENT")) + +(defgeneric* component-pathname (component) + (:documentation "Extracts the pathname applicable for a particular component.")) + +(defgeneric* component-relative-pathname (component) + (:documentation "Returns a pathname for the component argument intended to be +interpreted relative to the pathname of that component's parent. +Despite the function's name, the return value may be an absolute +pathname, because an absolute pathname may be interpreted relative to +another pathname in a degenerate way.")) + +(defgeneric* component-property (component property)) + +(defgeneric* (setf component-property) (new-value component property)) + +(defgeneric* component-external-format (component)) + +(defgeneric* component-encoding (component)) + +(eval-when (#-gcl :compile-toplevel :load-toplevel :execute) + (defgeneric* (setf module-components-by-name) (new-value module))) + +(defgeneric* version-satisfies (component version)) + +(defgeneric* find-component (base path) + (:documentation "Finds the component with PATH starting from BASE module; +if BASE is nil, then the component is assumed to be a system.")) + +(defgeneric* source-file-type (component system)) + +(defgeneric* operation-ancestor (operation) + (:documentation + "Recursively chase the operation's parent pointer until we get to +the head of the tree")) + +(defgeneric* component-visited-p (operation component) + (:documentation "Returns the value stored by a call to +VISIT-COMPONENT, if that has been called, otherwise NIL. +This value stored will be a cons cell, the first element +of which is a computed key, so not interesting. The +CDR wil be the DATA value stored by VISIT-COMPONENT; recover +it as (cdr (component-visited-p op c)). + In the current form of ASDF, the DATA value retrieved is +effectively a boolean, indicating whether some operations are +to be performed in order to do OPERATION X COMPONENT. If the +data value is NIL, the combination had been explored, but no +operations needed to be performed.")) + +(defgeneric* visit-component (operation component data) + (:documentation "Record DATA as being associated with OPERATION +and COMPONENT. This is a side-effecting function: the association +will be recorded on the ROOT OPERATION \(OPERATION-ANCESTOR of the +OPERATION\). + No evidence that DATA is ever interesting, beyond just being +non-NIL. Using the data field is probably very risky; if there is +already a record for OPERATION X COMPONENT, DATA will be quietly +discarded instead of recorded. + Starting with 2.006, TRAVERSE will store an integer in data, +so that nodes can be sorted in decreasing order of traversal.")) + + +(defgeneric* (setf visiting-component) (new-value operation component)) + +(defgeneric* component-visiting-p (operation component)) + +(defgeneric* component-depends-on (operation component) + (:documentation + "Returns a list of dependencies needed by the component to perform + the operation. A dependency has one of the following forms: + + ( *), where is a class + designator and each is a component + designator, which means that the component depends on + having been performed on each ; or + + (FEATURE ), which means that the component depends + on 's presence in *FEATURES*. + + Methods specialized on subclasses of existing component types + should usually append the results of CALL-NEXT-METHOD to the + list.")) + +(defgeneric* component-self-dependencies (operation component)) + +(defgeneric* traverse (operation component) + (:documentation +"Generate and return a plan for performing OPERATION on COMPONENT. + +The plan returned is a list of dotted-pairs. Each pair is the CONS +of ASDF operation object and a COMPONENT object. The pairs will be +processed in order by OPERATE.")) + + +;;;; ------------------------------------------------------------------------- +;;; Methods in case of hot-upgrade. See https://bugs.launchpad.net/asdf/+bug/485687 +(when *upgraded-p* + (when (find-class 'module nil) + (eval + '(defmethod update-instance-for-redefined-class :after + ((m module) added deleted plist &key) + (declare (ignorable deleted plist)) + (when *asdf-verbose* + (asdf-message (compatfmt "~&~@<; ~@;Updating ~A for ASDF ~A~@:>~%") + m (asdf-version))) + (when (member 'components-by-name added) + (compute-module-components-by-name m)) + (when (typep m 'system) + (when (member 'source-file added) + (%set-system-source-file + (probe-asd (component-name m) (component-pathname m)) m) + (when (equal (component-name m) "asdf") + (setf (component-version m) *asdf-version*)))))))) + +;;;; ------------------------------------------------------------------------- +;;;; Classes, Conditions + +(define-condition system-definition-error (error) () + ;; [this use of :report should be redundant, but unfortunately it's not. + ;; cmucl's lisp::output-instance prefers the kernel:slot-class-print-function + ;; over print-object; this is always conditions::%print-condition for + ;; condition objects, which in turn does inheritance of :report options at + ;; run-time. fortunately, inheritance means we only need this kludge here in + ;; order to fix all conditions that build on it. -- rgr, 28-Jul-02.] + #+cmu (:report print-object)) + +(define-condition formatted-system-definition-error (system-definition-error) + ((format-control :initarg :format-control :reader format-control) + (format-arguments :initarg :format-arguments :reader format-arguments)) + (:report (lambda (c s) + (apply 'format s (format-control c) (format-arguments c))))) + +(define-condition load-system-definition-error (system-definition-error) + ((name :initarg :name :reader error-name) + (pathname :initarg :pathname :reader error-pathname) + (condition :initarg :condition :reader error-condition)) + (:report (lambda (c s) + (format s (compatfmt "~@") + (error-name c) (error-pathname c) (error-condition c))))) + +(define-condition circular-dependency (system-definition-error) + ((components :initarg :components :reader circular-dependency-components)) + (:report (lambda (c s) + (format s (compatfmt "~@") + (circular-dependency-components c))))) + +(define-condition duplicate-names (system-definition-error) + ((name :initarg :name :reader duplicate-names-name)) + (:report (lambda (c s) + (format s (compatfmt "~@") + (duplicate-names-name c))))) + +(define-condition missing-component (system-definition-error) + ((requires :initform "(unnamed)" :reader missing-requires :initarg :requires) + (parent :initform nil :reader missing-parent :initarg :parent))) + +(define-condition missing-component-of-version (missing-component) + ((version :initform nil :reader missing-version :initarg :version))) + +(define-condition missing-dependency (missing-component) + ((required-by :initarg :required-by :reader missing-required-by))) + +(define-condition missing-dependency-of-version (missing-dependency + missing-component-of-version) + ()) + +(define-condition operation-error (error) + ((component :reader error-component :initarg :component) + (operation :reader error-operation :initarg :operation)) + (:report (lambda (c s) + (format s (compatfmt "~@") + (error-operation c) (error-component c))))) +(define-condition compile-error (operation-error) ()) +(define-condition compile-failed (compile-error) ()) +(define-condition compile-warned (compile-error) ()) + +(define-condition invalid-configuration () + ((form :reader condition-form :initarg :form) + (location :reader condition-location :initarg :location) + (format :reader condition-format :initarg :format) + (arguments :reader condition-arguments :initarg :arguments :initform nil)) + (:report (lambda (c s) + (format s (compatfmt "~@<~? (will be skipped)~@:>") + (condition-format c) + (list* (condition-form c) (condition-location c) + (condition-arguments c)))))) +(define-condition invalid-source-registry (invalid-configuration warning) + ((format :initform (compatfmt "~@")))) +(define-condition invalid-output-translation (invalid-configuration warning) + ((format :initform (compatfmt "~@")))) + +(defclass component () + ((name :accessor component-name :initarg :name :type string :documentation + "Component name: designator for a string composed of portable pathname characters") + ;; We might want to constrain version with + ;; :type (and string (satisfies parse-version)) + ;; but we cannot until we fix all systems that don't use it correctly! + (version :accessor component-version :initarg :version) + (description :accessor component-description :initarg :description) + (long-description :accessor component-long-description :initarg :long-description) + ;; This one below is used by POIU - http://www.cliki.net/poiu + ;; a parallelizing extension of ASDF that compiles in multiple parallel + ;; slave processes (forked on demand) and loads in the master process. + ;; Maybe in the future ASDF may use it internally instead of in-order-to. + (load-dependencies :accessor component-load-dependencies :initform nil) + ;; In the ASDF object model, dependencies exist between *actions* + ;; (an action is a pair of operation and component). They are represented + ;; alists of operations to dependencies (other actions) in each component. + ;; There are two kinds of dependencies, each stored in its own slot: + ;; in-order-to and do-first dependencies. These two kinds are related to + ;; the fact that some actions modify the filesystem, + ;; whereas other actions modify the current image, and + ;; this implies a difference in how to interpret timestamps. + ;; in-order-to dependencies will trigger re-performing the action + ;; when the timestamp of some dependency + ;; makes the timestamp of current action out-of-date; + ;; do-first dependencies do not trigger such re-performing. + ;; Therefore, a FASL must be recompiled if it is obsoleted + ;; by any of its FASL dependencies (in-order-to); but + ;; it needn't be recompiled just because one of these dependencies + ;; hasn't yet been loaded in the current image (do-first). + ;; The names are crap, but they have been the official API since Dan Barlow's ASDF 1.52! + ;; LispWorks's defsystem has caused-by and requires for in-order-to and do-first respectively. + ;; Maybe rename the slots in ASDF? But that's not very backwards compatible. + ;; See our ASDF 2 paper for more complete explanations. + (in-order-to :initform nil :initarg :in-order-to + :accessor component-in-order-to) + (do-first :initform nil :initarg :do-first + :accessor component-do-first) + ;; methods defined using the "inline" style inside a defsystem form: + ;; need to store them somewhere so we can delete them when the system + ;; is re-evaluated + (inline-methods :accessor component-inline-methods :initform nil) + (parent :initarg :parent :initform nil :reader component-parent) + ;; no direct accessor for pathname, we do this as a method to allow + ;; it to default in funky ways if not supplied + (relative-pathname :initarg :pathname) + ;; the absolute-pathname is computed based on relative-pathname... + (absolute-pathname) + (operation-times :initform (make-hash-table) + :accessor component-operation-times) + (around-compile :initarg :around-compile) + (%encoding :accessor %component-encoding :initform nil :initarg :encoding) + ;; XXX we should provide some atomic interface for updating the + ;; component properties + (properties :accessor component-properties :initarg :properties + :initform nil))) + +(defun* component-find-path (component) + (reverse + (loop :for c = component :then (component-parent c) + :while c :collect (component-name c)))) + +(defmethod print-object ((c component) stream) + (print-unreadable-object (c stream :type t :identity nil) + (format stream "~{~S~^ ~}" (component-find-path c)))) + + +;;;; methods: conditions + +(defmethod print-object ((c missing-dependency) s) + (format s (compatfmt "~@<~A, required by ~A~@:>") + (call-next-method c nil) (missing-required-by c))) + +(defun* sysdef-error (format &rest arguments) + (error 'formatted-system-definition-error :format-control + format :format-arguments arguments)) + +;;;; methods: components + +(defmethod print-object ((c missing-component) s) + (format s (compatfmt "~@") + (missing-requires c) + (when (missing-parent c) + (coerce-name (missing-parent c))))) + +(defmethod print-object ((c missing-component-of-version) s) + (format s (compatfmt "~@") + (missing-requires c) + (missing-version c) + (when (missing-parent c) + (coerce-name (missing-parent c))))) + +(defmethod component-system ((component component)) + (aif (component-parent component) + (component-system it) + component)) + +(defvar *default-component-class* 'cl-source-file) + +(defun* compute-module-components-by-name (module) + (let ((hash (make-hash-table :test 'equal))) + (setf (module-components-by-name module) hash) + (loop :for c :in (module-components module) + :for name = (component-name c) + :for previous = (gethash name (module-components-by-name module)) + :do + (when previous + (error 'duplicate-names :name name)) + :do (setf (gethash name (module-components-by-name module)) c)) + hash)) + +(defclass module (component) + ((components + :initform nil + :initarg :components + :accessor module-components) + (components-by-name + :accessor module-components-by-name) + ;; What to do if we can't satisfy a dependency of one of this module's + ;; components. This allows a limited form of conditional processing. + (if-component-dep-fails + :initform :fail + :initarg :if-component-dep-fails + :accessor module-if-component-dep-fails) + (default-component-class + :initform nil + :initarg :default-component-class + :accessor module-default-component-class))) + +(defun* component-parent-pathname (component) + ;; No default anymore (in particular, no *default-pathname-defaults*). + ;; If you force component to have a NULL pathname, you better arrange + ;; for any of its children to explicitly provide a proper absolute pathname + ;; wherever a pathname is actually wanted. + (let ((parent (component-parent component))) + (when parent + (component-pathname parent)))) + +(defmethod component-pathname ((component component)) + (if (slot-boundp component 'absolute-pathname) + (slot-value component 'absolute-pathname) + (let ((pathname + (merge-pathnames* + (component-relative-pathname component) + (pathname-directory-pathname (component-parent-pathname component))))) + (unless (or (null pathname) (absolute-pathname-p pathname)) + (error (compatfmt "~@") + pathname (component-find-path component))) + (setf (slot-value component 'absolute-pathname) pathname) + pathname))) + +(defmethod component-property ((c component) property) + (cdr (assoc property (slot-value c 'properties) :test #'equal))) + +(defmethod (setf component-property) (new-value (c component) property) + (let ((a (assoc property (slot-value c 'properties) :test #'equal))) + (if a + (setf (cdr a) new-value) + (setf (slot-value c 'properties) + (acons property new-value (slot-value c 'properties))))) + new-value) + +(defvar *default-encoding* :default + "Default encoding for source files. +The default value :default preserves the legacy behavior. +A future default might be :utf-8 or :autodetect +reading emacs-style -*- coding: utf-8 -*- specifications, +and falling back to utf-8 or latin1 if nothing is specified.") + +(defparameter *utf-8-external-format* + #+(and asdf-unicode (not clisp)) :utf-8 + #+(and asdf-unicode clisp) charset:utf-8 + #-asdf-unicode :default + "Default :external-format argument to pass to CL:OPEN and also +CL:LOAD or CL:COMPILE-FILE to best process a UTF-8 encoded file. +On modern implementations, this will decode UTF-8 code points as CL characters. +On legacy implementations, it may fall back on some 8-bit encoding, +with non-ASCII code points being read as several CL characters; +hopefully, if done consistently, that won't affect program behavior too much.") + +(defun* always-default-encoding (pathname) + (declare (ignore pathname)) + *default-encoding*) + +(defvar *encoding-detection-hook* #'always-default-encoding + "Hook for an extension to define a function to automatically detect a file's encoding") + +(defun* detect-encoding (pathname) + (funcall *encoding-detection-hook* pathname)) + +(defmethod component-encoding ((c component)) + (or (loop :for x = c :then (component-parent x) + :while x :thereis (%component-encoding x)) + (detect-encoding (component-pathname c)))) + +(defun* default-encoding-external-format (encoding) + (case encoding + (:default :default) ;; for backwards compatibility only. Explicit usage discouraged. + (:utf-8 *utf-8-external-format*) + (otherwise + (cerror "Continue using :external-format :default" (compatfmt "~@") encoding) + :default))) + +(defvar *encoding-external-format-hook* + #'default-encoding-external-format + "Hook for an extension to define a mapping between non-default encodings +and implementation-defined external-format's") + +(defun encoding-external-format (encoding) + (funcall *encoding-external-format-hook* encoding)) + +(defmethod component-external-format ((c component)) + (encoding-external-format (component-encoding c))) + +(defclass proto-system () ; slots to keep when resetting a system + ;; To preserve identity for all objects, we'd need keep the components slots + ;; but also to modify parse-component-form to reset the recycled objects. + ((name) #|(components) (components-by-names)|#)) + +(defclass system (module proto-system) + (;; description and long-description are now available for all component's, + ;; but now also inherited from component, but we add the legacy accessor + (description :accessor system-description :initarg :description) + (long-description :accessor system-long-description :initarg :long-description) + (author :accessor system-author :initarg :author) + (maintainer :accessor system-maintainer :initarg :maintainer) + (licence :accessor system-licence :initarg :licence + :accessor system-license :initarg :license) + (source-file :reader %system-source-file :initarg :source-file ; for CLISP upgrade + :writer %set-system-source-file) + (defsystem-depends-on :reader system-defsystem-depends-on :initarg :defsystem-depends-on))) + +;;;; ------------------------------------------------------------------------- +;;;; version-satisfies + +(defmethod version-satisfies ((c component) version) + (unless (and version (slot-boundp c 'version)) + (when version + (warn "Requested version ~S but component ~S has no version" version c)) + (return-from version-satisfies t)) + (version-satisfies (component-version c) version)) + +(defun* asdf-version () + "Exported interface to the version of ASDF currently installed. A string. +You can compare this string with e.g.: +(ASDF:VERSION-SATISFIES (ASDF:ASDF-VERSION) \"2.345.67\")." + *asdf-version*) + +(defun* parse-version (string &optional on-error) + "Parse a version string as a series of natural integers separated by dots. +Return a (non-null) list of integers if the string is valid, NIL otherwise. +If on-error is error, warn, or designates a function of compatible signature, +the function is called with an explanation of what is wrong with the argument. +NB: ignores leading zeroes, and so doesn't distinguish between 2.003 and 2.3" + (and + (or (stringp string) + (when on-error + (funcall on-error "~S: ~S is not a string" + 'parse-version string)) nil) + (or (loop :for prev = nil :then c :for c :across string + :always (or (digit-char-p c) + (and (eql c #\.) prev (not (eql prev #\.)))) + :finally (return (and c (digit-char-p c)))) + (when on-error + (funcall on-error "~S: ~S doesn't follow asdf version numbering convention" + 'parse-version string)) nil) + (mapcar #'parse-integer (split-string string :separator ".")))) + +(defmethod version-satisfies ((cver string) version) + (let ((x (parse-version cver 'warn)) + (y (parse-version version 'warn))) + (labels ((bigger (x y) + (cond ((not y) t) + ((not x) nil) + ((> (car x) (car y)) t) + ((= (car x) (car y)) + (bigger (cdr x) (cdr y)))))) + (and x y (= (car x) (car y)) + (or (not (cdr y)) (bigger (cdr x) (cdr y))))))) + +;;;; ----------------------------------------------------------------- +;;;; Windows shortcut support. Based on: +;;;; +;;;; Jesse Hager: The Windows Shortcut File Format. +;;;; http://www.wotsit.org/list.asp?fc=13 + +#-(or clisp genera) ; CLISP doesn't need it, and READ-SEQUENCE annoys old Genera. +(progn +(defparameter *link-initial-dword* 76) +(defparameter *link-guid* #(1 20 2 0 0 0 0 0 192 0 0 0 0 0 0 70)) + +(defun* read-null-terminated-string (s) + (with-output-to-string (out) + (loop :for code = (read-byte s) + :until (zerop code) + :do (write-char (code-char code) out)))) + +(defun* read-little-endian (s &optional (bytes 4)) + (loop :for i :from 0 :below bytes + :sum (ash (read-byte s) (* 8 i)))) + +(defun* parse-file-location-info (s) + (let ((start (file-position s)) + (total-length (read-little-endian s)) + (end-of-header (read-little-endian s)) + (fli-flags (read-little-endian s)) + (local-volume-offset (read-little-endian s)) + (local-offset (read-little-endian s)) + (network-volume-offset (read-little-endian s)) + (remaining-offset (read-little-endian s))) + (declare (ignore total-length end-of-header local-volume-offset)) + (unless (zerop fli-flags) + (cond + ((logbitp 0 fli-flags) + (file-position s (+ start local-offset))) + ((logbitp 1 fli-flags) + (file-position s (+ start + network-volume-offset + #x14)))) + (strcat (read-null-terminated-string s) + (progn + (file-position s (+ start remaining-offset)) + (read-null-terminated-string s)))))) + +(defun* parse-windows-shortcut (pathname) + (with-open-file (s pathname :element-type '(unsigned-byte 8)) + (handler-case + (when (and (= (read-little-endian s) *link-initial-dword*) + (let ((header (make-array (length *link-guid*)))) + (read-sequence header s) + (equalp header *link-guid*))) + (let ((flags (read-little-endian s))) + (file-position s 76) ;skip rest of header + (when (logbitp 0 flags) + ;; skip shell item id list + (let ((length (read-little-endian s 2))) + (file-position s (+ length (file-position s))))) + (cond + ((logbitp 1 flags) + (parse-file-location-info s)) + (t + (when (logbitp 2 flags) + ;; skip description string + (let ((length (read-little-endian s 2))) + (file-position s (+ length (file-position s))))) + (when (logbitp 3 flags) + ;; finally, our pathname + (let* ((length (read-little-endian s 2)) + (buffer (make-array length))) + (read-sequence buffer s) + (map 'string #'code-char buffer))))))) + (end-of-file () + nil))))) + +;;;; ------------------------------------------------------------------------- +;;;; Finding systems + +(defun* make-defined-systems-table () + (make-hash-table :test 'equal)) + +(defvar *defined-systems* (make-defined-systems-table) + "This is a hash table whose keys are strings, being the +names of the systems, and whose values are pairs, the first +element of which is a universal-time indicating when the +system definition was last updated, and the second element +of which is a system object.") + +(defun* coerce-name (name) + (typecase name + (component (component-name name)) + (symbol (string-downcase (symbol-name name))) + (string name) + (t (sysdef-error (compatfmt "~@") name)))) + +(defun* system-registered-p (name) + (gethash (coerce-name name) *defined-systems*)) + +(defun* registered-systems () + (loop :for (() . system) :being :the :hash-values :of *defined-systems* + :collect (coerce-name system))) + +(defun* register-system (system) + (check-type system system) + (let ((name (component-name system))) + (check-type name string) + (asdf-message (compatfmt "~&~@<; ~@;Registering ~3i~_~A~@:>~%") system) + (unless (eq system (cdr (gethash name *defined-systems*))) + (setf (gethash name *defined-systems*) + (cons (get-universal-time) system))))) + +(defun* clear-system (name) + "Clear the entry for a system in the database of systems previously loaded. +Note that this does NOT in any way cause the code of the system to be unloaded." + ;; There is no "unload" operation in Common Lisp, and + ;; a general such operation cannot be portably written, + ;; considering how much CL relies on side-effects to global data structures. + (remhash (coerce-name name) *defined-systems*)) + +(defun* map-systems (fn) + "Apply FN to each defined system. + +FN should be a function of one argument. It will be +called with an object of type asdf:system." + (maphash #'(lambda (_ datum) + (declare (ignore _)) + (destructuring-bind (_ . def) datum + (declare (ignore _)) + (funcall fn def))) + *defined-systems*)) + +;;; for the sake of keeping things reasonably neat, we adopt a +;;; convention that functions in this list are prefixed SYSDEF- + +(defvar *system-definition-search-functions* '()) + +(setf *system-definition-search-functions* + (append + ;; Remove known-incompatible sysdef functions from ancient sbcl asdf. + (remove 'contrib-sysdef-search *system-definition-search-functions*) + ;; Tuck our defaults at the end of the list if they were absent. + ;; This is imperfect, in case they were removed on purpose, + ;; but then it will be the responsibility of whoever does that + ;; to upgrade asdf before he does such a thing rather than after. + (remove-if #'(lambda (x) (member x *system-definition-search-functions*)) + '(sysdef-central-registry-search + sysdef-source-registry-search + sysdef-find-asdf)))) + +(defun* search-for-system-definition (system) + (some (let ((name (coerce-name system))) #'(lambda (x) (funcall x name))) + (cons 'find-system-if-being-defined + *system-definition-search-functions*))) + +(defvar *central-registry* nil +"A list of 'system directory designators' ASDF uses to find systems. + +A 'system directory designator' is a pathname or an expression +which evaluates to a pathname. For example: + + (setf asdf:*central-registry* + (list '*default-pathname-defaults* + #p\"/home/me/cl/systems/\" + #p\"/usr/share/common-lisp/systems/\")) + +This is for backward compatibilily. +Going forward, we recommend new users should be using the source-registry. +") + +(defun* featurep (x &optional (features *features*)) + (cond + ((atom x) + (and (member x features) t)) + ((eq :not (car x)) + (assert (null (cddr x))) + (not (featurep (cadr x) features))) + ((eq :or (car x)) + (some #'(lambda (x) (featurep x features)) (cdr x))) + ((eq :and (car x)) + (every #'(lambda (x) (featurep x features)) (cdr x))) + (t + (error "Malformed feature specification ~S" x)))) + +(defun* os-unix-p () + (featurep '(:or :unix :cygwin :darwin))) + +(defun* os-windows-p () + (and (not (os-unix-p)) (featurep '(:or :win32 :windows :mswindows :mingw32)))) + +(defun* probe-asd (name defaults) + (block nil + (when (directory-pathname-p defaults) + (let* ((file (probe-file* (subpathname defaults (strcat name ".asd"))))) + (when file + (return file))) + #-(or clisp genera) ; clisp doesn't need it, plain genera doesn't have read-sequence(!) + (when (os-windows-p) + (let ((shortcut + (make-pathname + :defaults defaults :version :newest :case :local + :name (strcat name ".asd") + :type "lnk"))) + (when (probe-file* shortcut) + (let ((target (parse-windows-shortcut shortcut))) + (when target + (return (pathname target)))))))))) + +(defun* sysdef-central-registry-search (system) + (let ((name (coerce-name system)) + (to-remove nil) + (to-replace nil)) + (block nil + (unwind-protect + (dolist (dir *central-registry*) + (let ((defaults (eval dir))) + (when defaults + (cond ((directory-pathname-p defaults) + (let ((file (probe-asd name defaults))) + (when file + (return file)))) + (t + (restart-case + (let* ((*print-circle* nil) + (message + (format nil + (compatfmt "~@") + system dir defaults))) + (error message)) + (remove-entry-from-registry () + :report "Remove entry from *central-registry* and continue" + (push dir to-remove)) + (coerce-entry-to-directory () + :report (lambda (s) + (format s (compatfmt "~@") + (ensure-directory-pathname defaults) dir)) + (push (cons dir (ensure-directory-pathname defaults)) to-replace)))))))) + ;; cleanup + (dolist (dir to-remove) + (setf *central-registry* (remove dir *central-registry*))) + (dolist (pair to-replace) + (let* ((current (car pair)) + (new (cdr pair)) + (position (position current *central-registry*))) + (setf *central-registry* + (append (subseq *central-registry* 0 position) + (list new) + (subseq *central-registry* (1+ position)))))))))) + +(defun* make-temporary-package () + (flet ((try (counter) + (ignore-errors + (make-package (format nil "~A~D" :asdf counter) + :use '(:cl :asdf))))) + (do* ((counter 0 (+ counter 1)) + (package (try counter) (try counter))) + (package package)))) + +(defun* safe-file-write-date (pathname) + ;; If FILE-WRITE-DATE returns NIL, it's possible that + ;; the user or some other agent has deleted an input file. + ;; Also, generated files will not exist at the time planning is done + ;; and calls operation-done-p which calls safe-file-write-date. + ;; So it is very possible that we can't get a valid file-write-date, + ;; and we can survive and we will continue the planning + ;; as if the file were very old. + ;; (or should we treat the case in a different, special way?) + (or (and pathname (probe-file* pathname) (ignore-errors (file-write-date pathname))) + (progn + (when (and pathname *asdf-verbose*) + (warn (compatfmt "~@") + pathname)) + 0))) + +(defmethod find-system ((name null) &optional (error-p t)) + (declare (ignorable name)) + (when error-p + (sysdef-error (compatfmt "~@")))) + +(defmethod find-system (name &optional (error-p t)) + (find-system (coerce-name name) error-p)) + +(defvar *systems-being-defined* nil + "A hash-table of systems currently being defined keyed by name, or NIL") + +(defun* find-system-if-being-defined (name) + (when *systems-being-defined* + (gethash (coerce-name name) *systems-being-defined*))) + +(defun* call-with-system-definitions (thunk) + (if *systems-being-defined* + (funcall thunk) + (let ((*systems-being-defined* (make-hash-table :test 'equal))) + (funcall thunk)))) + +(defmacro with-system-definitions ((&optional) &body body) + `(call-with-system-definitions #'(lambda () ,@body))) + +(defun* load-sysdef (name pathname) + ;; Tries to load system definition with canonical NAME from PATHNAME. + (with-system-definitions () + (let ((package (make-temporary-package))) + (unwind-protect + (handler-bind + ((error #'(lambda (condition) + (error 'load-system-definition-error + :name name :pathname pathname + :condition condition)))) + (let ((*package* package) + (*default-pathname-defaults* + ;; resolve logical-pathnames so they won't wreak havoc in parsing namestrings. + (pathname-directory-pathname (translate-logical-pathname pathname))) + (external-format (encoding-external-format (detect-encoding pathname)))) + (asdf-message (compatfmt "~&~@<; ~@;Loading system definition from ~A into ~A~@:>~%") + pathname package) + (load pathname :external-format external-format))) + (delete-package package))))) + +(defun* locate-system (name) + "Given a system NAME designator, try to locate where to load the system from. +Returns five values: FOUNDP FOUND-SYSTEM PATHNAME PREVIOUS PREVIOUS-TIME +FOUNDP is true when a system was found, +either a new unregistered one or a previously registered one. +FOUND-SYSTEM when not null is a SYSTEM object that may be REGISTER-SYSTEM'ed as is +PATHNAME when not null is a path from where to load the system, +either associated with FOUND-SYSTEM, or with the PREVIOUS system. +PREVIOUS when not null is a previously loaded SYSTEM object of same name. +PREVIOUS-TIME when not null is the time at which the PREVIOUS system was loaded." + (let* ((name (coerce-name name)) + (in-memory (system-registered-p name)) ; load from disk if absent or newer on disk + (previous (cdr in-memory)) + (previous (and (typep previous 'system) previous)) + (previous-time (car in-memory)) + (found (search-for-system-definition name)) + (found-system (and (typep found 'system) found)) + (pathname (or (and (typep found '(or pathname string)) (pathname found)) + (and found-system (system-source-file found-system)) + (and previous (system-source-file previous)))) + (foundp (and (or found-system pathname previous) t))) + (check-type found (or null pathname system)) + (when foundp + (setf pathname (resolve-symlinks* pathname)) + (when (and pathname (not (absolute-pathname-p pathname))) + (setf pathname (ensure-pathname-absolute pathname)) + (when found-system + (%set-system-source-file pathname found-system))) + (when (and previous (not (#-cormanlisp equal #+cormanlisp equalp + (system-source-file previous) pathname))) + (%set-system-source-file pathname previous) + (setf previous-time nil)) + (values foundp found-system pathname previous previous-time)))) + +(defmethod find-system ((name string) &optional (error-p t)) + (with-system-definitions () + (loop + (restart-case + (multiple-value-bind (foundp found-system pathname previous previous-time) + (locate-system name) + (declare (ignore foundp)) + (when (and found-system (not previous)) + (register-system found-system)) + (when (and pathname + (or (not previous-time) + ;; don't reload if it's already been loaded, + ;; or its filestamp is in the future which means some clock is skewed + ;; and trying to load might cause an infinite loop. + (< previous-time (safe-file-write-date pathname) (get-universal-time)))) + (load-sysdef name pathname)) + (let ((in-memory (system-registered-p name))) ; try again after loading from disk if needed + (return + (cond + (in-memory + (when pathname + (setf (car in-memory) (safe-file-write-date pathname))) + (cdr in-memory)) + (error-p + (error 'missing-component :requires name)))))) + (reinitialize-source-registry-and-retry () + :report (lambda (s) + (format s (compatfmt "~@") name)) + (initialize-source-registry)))))) + +(defun* find-system-fallback (requested fallback &rest keys &key source-file &allow-other-keys) + (setf fallback (coerce-name fallback) + requested (coerce-name requested)) + (when (equal requested fallback) + (let ((registered (cdr (gethash fallback *defined-systems*)))) + (or registered + (apply 'make-instance 'system + :name fallback :source-file source-file keys))))) + +(defun* sysdef-find-asdf (name) + ;; Bug: :version *asdf-version* won't be updated when ASDF is updated. + (find-system-fallback name "asdf" :version *asdf-version*)) + + +;;;; ------------------------------------------------------------------------- +;;;; Finding components + +(defmethod find-component ((base string) path) + (let ((s (find-system base nil))) + (and s (find-component s path)))) + +(defmethod find-component ((base symbol) path) + (cond + (base (find-component (coerce-name base) path)) + (path (find-component path nil)) + (t nil))) + +(defmethod find-component ((base cons) path) + (find-component (car base) (cons (cdr base) path))) + +(defmethod find-component ((module module) (name string)) + (unless (slot-boundp module 'components-by-name) ;; SBCL may miss the u-i-f-r-c method!!! + (compute-module-components-by-name module)) + (values (gethash name (module-components-by-name module)))) + +(defmethod find-component ((component component) (name symbol)) + (if name + (find-component component (coerce-name name)) + component)) + +(defmethod find-component ((module module) (name cons)) + (find-component (find-component module (car name)) (cdr name))) + + +;;; component subclasses + +(defclass source-file (component) + ((type :accessor source-file-explicit-type :initarg :type :initform nil))) + +(defclass cl-source-file (source-file) + ((type :initform "lisp"))) +(defclass cl-source-file.cl (cl-source-file) + ((type :initform "cl"))) +(defclass cl-source-file.lsp (cl-source-file) + ((type :initform "lsp"))) +(defclass c-source-file (source-file) + ((type :initform "c"))) +(defclass java-source-file (source-file) + ((type :initform "java"))) +(defclass static-file (source-file) ()) +(defclass doc-file (static-file) ()) +(defclass html-file (doc-file) + ((type :initform "html"))) + +(defmethod source-file-type ((component module) (s module)) + (declare (ignorable component s)) + :directory) +(defmethod source-file-type ((component source-file) (s module)) + (declare (ignorable s)) + (source-file-explicit-type component)) + +(defmethod component-relative-pathname ((component component)) + (coerce-pathname + (or (slot-value component 'relative-pathname) + (component-name component)) + :type (source-file-type component (component-system component)) + :defaults (component-parent-pathname component))) + +;;;; ------------------------------------------------------------------------- +;;;; Operations + +;;; one of these is instantiated whenever #'operate is called + +(defclass operation () + (;; as of danb's 2003-03-16 commit e0d02781, :force can be: + ;; T to force the inside of the specified system, + ;; but not recurse to other systems we depend on. + ;; :ALL (or any other atom) to force all systems + ;; including other systems we depend on. + ;; (SYSTEM1 SYSTEM2 ... SYSTEMN) + ;; to force systems named in a given list + ;; However, but this feature has only ever worked but starting with ASDF 2.014.5 + (forced :initform nil :initarg :force :accessor operation-forced) + (forced-not :initform nil :initarg :force-not :accessor operation-forced-not) + (original-initargs :initform nil :initarg :original-initargs + :accessor operation-original-initargs) + (visited-nodes :initform (make-hash-table :test 'equal) :accessor operation-visited-nodes) + (visiting-nodes :initform (make-hash-table :test 'equal) :accessor operation-visiting-nodes) + (parent :initform nil :initarg :parent :accessor operation-parent))) + +(defmethod print-object ((o operation) stream) + (print-unreadable-object (o stream :type t :identity t) + (ignore-errors + (prin1 (operation-original-initargs o) stream)))) + +(defmethod shared-initialize :after ((operation operation) slot-names + &key force force-not + &allow-other-keys) + ;; the &allow-other-keys disables initarg validity checking + (declare (ignorable operation slot-names force force-not)) + (macrolet ((frob (x) ;; normalize forced and forced-not slots + `(when (consp (,x operation)) + (setf (,x operation) + (mapcar #'coerce-name (,x operation)))))) + (frob operation-forced) (frob operation-forced-not)) + (values)) + +(defun* node-for (o c) + (cons (class-name (class-of o)) c)) + +(defmethod operation-ancestor ((operation operation)) + (aif (operation-parent operation) + (operation-ancestor it) + operation)) + + +(defun* make-sub-operation (c o dep-c dep-o) + "C is a component, O is an operation, DEP-C is another +component, and DEP-O, confusingly enough, is an operation +class specifier, not an operation." + (let* ((args (copy-list (operation-original-initargs o))) + (force-p (getf args :force))) + ;; note explicit comparison with T: any other non-NIL force value + ;; (e.g. :recursive) will pass through + (cond ((and (null (component-parent c)) + (null (component-parent dep-c)) + (not (eql c dep-c))) + (when (eql force-p t) + (setf (getf args :force) nil)) + (apply 'make-instance dep-o + :parent o + :original-initargs args args)) + ((subtypep (type-of o) dep-o) + o) + (t + (apply 'make-instance dep-o + :parent o :original-initargs args args))))) + + +(defmethod visit-component ((o operation) (c component) data) + (unless (component-visited-p o c) + (setf (gethash (node-for o c) + (operation-visited-nodes (operation-ancestor o))) + (cons t data)))) + +(defmethod component-visited-p ((o operation) (c component)) + (gethash (node-for o c) + (operation-visited-nodes (operation-ancestor o)))) + +(defmethod (setf visiting-component) (new-value operation component) + ;; MCL complains about unused lexical variables + (declare (ignorable operation component)) + new-value) + +(defmethod (setf visiting-component) (new-value (o operation) (c component)) + (let ((node (node-for o c)) + (a (operation-ancestor o))) + (if new-value + (setf (gethash node (operation-visiting-nodes a)) t) + (remhash node (operation-visiting-nodes a))) + new-value)) + +(defmethod component-visiting-p ((o operation) (c component)) + (let ((node (node-for o c))) + (gethash node (operation-visiting-nodes (operation-ancestor o))))) + +(defmethod component-depends-on ((op-spec symbol) (c component)) + ;; Note: we go from op-spec to operation via make-instance + ;; to allow for specialization through defmethod's, even though + ;; it's a detour in the default case below. + (component-depends-on (make-instance op-spec) c)) + +(defmethod component-depends-on ((o operation) (c component)) + (cdr (assoc (type-of o) (component-in-order-to c)))) + +(defmethod component-self-dependencies ((o operation) (c component)) + (remove-if-not + #'(lambda (x) (member (component-name c) (cdr x) :test #'string=)) + (component-depends-on o c))) + +(defmethod input-files ((operation operation) (c component)) + (let ((parent (component-parent c)) + (self-deps (component-self-dependencies operation c))) + (if self-deps + (mapcan #'(lambda (dep) + (destructuring-bind (op name) dep + (output-files (make-instance op) + (find-component parent name)))) + self-deps) + ;; no previous operations needed? I guess we work with the + ;; original source file, then + (list (component-pathname c))))) + +(defmethod input-files ((operation operation) (c module)) + (declare (ignorable operation c)) + nil) + +(defmethod component-operation-time (o c) + (gethash (type-of o) (component-operation-times c))) + +(defmethod operation-done-p ((o operation) (c component)) + (let ((out-files (output-files o c)) + (in-files (input-files o c)) + (op-time (component-operation-time o c))) + (flet ((earliest-out () + (reduce #'min (mapcar #'safe-file-write-date out-files))) + (latest-in () + (reduce #'max (mapcar #'safe-file-write-date in-files)))) + (cond + ((and (not in-files) (not out-files)) + ;; arbitrary decision: an operation that uses nothing to + ;; produce nothing probably isn't doing much. + ;; e.g. operations on systems, modules that have no immediate action, + ;; but are only meaningful through traversed dependencies + t) + ((not out-files) + ;; an operation without output-files is probably meant + ;; for its side-effects in the current image, + ;; assumed to be idem-potent, + ;; e.g. LOAD-OP or LOAD-SOURCE-OP of some CL-SOURCE-FILE. + (and op-time (>= op-time (latest-in)))) + ((not in-files) + ;; an operation with output-files and no input-files + ;; is probably meant for its side-effects on the file-system, + ;; assumed to have to be done everytime. + ;; (I don't think there is any such case in ASDF unless extended) + nil) + (t + ;; an operation with both input and output files is assumed + ;; as computing the latter from the former, + ;; assumed to have been done if the latter are all older + ;; than the former. + ;; e.g. COMPILE-OP of some CL-SOURCE-FILE. + ;; We use >= instead of > to play nice with generated files. + ;; This opens a race condition if an input file is changed + ;; after the output is created but within the same second + ;; of filesystem time; but the same race condition exists + ;; whenever the computation from input to output takes more + ;; than one second of filesystem time (or just crosses the + ;; second). So that's cool. + (and + (every #'probe-file* in-files) + (every #'probe-file* out-files) + (>= (earliest-out) (latest-in)))))))) + + + +;;; For 1.700 I've done my best to refactor TRAVERSE +;;; by splitting it up in a bunch of functions, +;;; so as to improve the collection and use-detection algorithm. --fare +;;; The protocol is as follows: we pass around operation, dependency, +;;; bunch of other stuff, and a force argument. Return a force flag. +;;; The returned flag is T if anything has changed that requires a rebuild. +;;; The force argument is a list of components that will require a rebuild +;;; if the flag is T, at which point whoever returns the flag has to +;;; mark them all as forced, and whoever recurses again can use a NIL list +;;; as a further argument. + +(defvar *forcing* nil + "This dynamically-bound variable is used to force operations in +recursive calls to traverse.") + +(defgeneric* do-traverse (operation component collect)) + +(defun* resolve-dependency-name (component name &optional version) + (loop + (restart-case + (return + (let ((comp (find-component (component-parent component) name))) + (unless comp + (error 'missing-dependency + :required-by component + :requires name)) + (when version + (unless (version-satisfies comp version) + (error 'missing-dependency-of-version + :required-by component + :version version + :requires name))) + comp)) + (retry () + :report (lambda (s) + (format s (compatfmt "~@") name)) + :test + (lambda (c) + (or (null c) + (and (typep c 'missing-dependency) + (eq (missing-required-by c) component) + (equal (missing-requires c) name)))))))) + +(defun* resolve-dependency-spec (component dep-spec) + (cond + ((atom dep-spec) + (resolve-dependency-name component dep-spec)) + ;; Structured dependencies --- this parses keywords. + ;; The keywords could conceivably be broken out and cleanly (extensibly) + ;; processed by EQL methods. But for now, here's what we've got. + ((eq :version (first dep-spec)) + ;; https://bugs.launchpad.net/asdf/+bug/527788 + (resolve-dependency-name component (second dep-spec) (third dep-spec))) + ((eq :feature (first dep-spec)) + ;; This particular subform is not documented and + ;; has always been broken in the past. + ;; Therefore no one uses it, and I'm cerroring it out, + ;; after fixing it + ;; See https://bugs.launchpad.net/asdf/+bug/518467 + (cerror "Continue nonetheless." + "Congratulations, you're the first ever user of FEATURE dependencies! Please contact the asdf-devel mailing-list.") + (when (find (second dep-spec) *features* :test 'string-equal) + (resolve-dependency-name component (third dep-spec)))) + (t + (error (compatfmt "~@ ), (:feature ), or .~@:>") dep-spec)))) + +(defun* do-one-dep (op c collect dep-op dep-c) + ;; Collects a partial plan for performing dep-op on dep-c + ;; as dependencies of a larger plan involving op and c. + ;; Returns t if this should force recompilation of those who depend on us. + ;; dep-op is an operation class name (not an operation object), + ;; whereas dep-c is a component object.n + (do-traverse (make-sub-operation c op dep-c dep-op) dep-c collect)) + +(defun* do-dep (op c collect dep-op-spec dep-c-specs) + ;; Collects a partial plan for performing dep-op-spec on each of dep-c-specs + ;; as dependencies of a larger plan involving op and c. + ;; Returns t if this should force recompilation of those who depend on us. + ;; dep-op-spec is either an operation class name (not an operation object), + ;; or the magic symbol asdf:feature. + ;; If dep-op-spec is asdf:feature, then the first dep-c-specs is a keyword, + ;; and the plan will succeed if that keyword is present in *feature*, + ;; or fail if it isn't + ;; (at which point c's :if-component-dep-fails will kick in). + ;; If dep-op-spec is an operation class name, + ;; then dep-c-specs specifies a list of sibling component of c, + ;; as per resolve-dependency-spec, such that operating op on c + ;; depends on operating dep-op-spec on each of them. + (cond ((eq dep-op-spec 'feature) + (if (member (car dep-c-specs) *features*) + nil + (error 'missing-dependency + :required-by c + :requires (list :feature (car dep-c-specs))))) + (t + (let ((flag nil)) + (dolist (d dep-c-specs) + (when (do-one-dep op c collect dep-op-spec + (resolve-dependency-spec c d)) + (setf flag t))) + flag)))) + +(defvar *visit-count* 0) ; counter that allows to sort nodes from operation-visited-nodes + +(defun* do-collect (collect x) + (funcall collect x)) + +(defmethod do-traverse ((operation operation) (c component) collect) + (let ((*forcing* *forcing*) + (flag nil)) ;; return value: must we rebuild this and its dependencies? + (labels + ((update-flag (x) + (orf flag x)) + (dep (op comp) + (update-flag (do-dep operation c collect op comp)))) + ;; Have we been visited yet? If so, just process the result. + (aif (component-visited-p operation c) + (progn + (update-flag (cdr it)) + (return-from do-traverse flag))) + ;; dependencies + (when (component-visiting-p operation c) + (error 'circular-dependency :components (list c))) + (setf (visiting-component operation c) t) + (unwind-protect + (block nil + (when (typep c 'system) ;; systems can be forced or forced-not + (let ((ancestor (operation-ancestor operation))) + (flet ((match? (f) + (and f (or (not (consp f)) ;; T or :ALL + (member (component-name c) f :test #'equal))))) + (cond + ((match? (operation-forced ancestor)) + (setf *forcing* t)) + ((match? (operation-forced-not ancestor)) + (return)))))) + ;; first we check and do all the dependencies for the module. + ;; Operations planned in this loop will show up + ;; in the results, and are consumed below. + (let ((*forcing* nil)) + ;; upstream dependencies are never forced to happen just because + ;; the things that depend on them are.... + (loop + :for (required-op . deps) :in (component-depends-on operation c) + :do (dep required-op deps))) + ;; constituent bits + (let ((module-ops + (when (typep c 'module) + (let ((at-least-one nil) + ;; This is set based on the results of the + ;; dependencies and whether we are in the + ;; context of a *forcing* call... + ;; inter-system dependencies do NOT trigger + ;; building components + (*forcing* + (or *forcing* + (and flag (not (typep c 'system))))) + (error nil)) + (while-collecting (internal-collect) + (dolist (kid (module-components c)) + (handler-case + (update-flag + (do-traverse operation kid #'internal-collect)) + #-genera + (missing-dependency (condition) + (when (eq (module-if-component-dep-fails c) + :fail) + (error condition)) + (setf error condition)) + (:no-error (c) + (declare (ignore c)) + (setf at-least-one t)))) + (when (and (eq (module-if-component-dep-fails c) + :try-next) + (not at-least-one)) + (error error))))))) + (update-flag (or *forcing* (not (operation-done-p operation c)))) + ;; For sub-operations, check whether + ;; the original ancestor operation was forced, + ;; or names us amongst an explicit list of things to force... + ;; except that this check doesn't distinguish + ;; between all the things with a given name. Sigh. + ;; BROKEN! + (when flag + (let ((do-first (cdr (assoc (class-name (class-of operation)) + (component-do-first c))))) + (loop :for (required-op . deps) :in do-first + :do (do-dep operation c collect required-op deps))) + (do-collect collect (vector module-ops)) + (do-collect collect (cons operation c))))) + (setf (visiting-component operation c) nil))) + (visit-component operation c (when flag (incf *visit-count*))) + flag)) + +(defun* flatten-tree (l) + ;; You collected things into a list. + ;; Most elements are just things to collect again. + ;; A (simple-vector 1) indicate that you should recurse into its contents. + ;; This way, in two passes (rather than N being the depth of the tree), + ;; you can collect things with marginally constant-time append, + ;; achieving linear time collection instead of quadratic time. + (while-collecting (c) + (labels ((r (x) + (if (typep x '(simple-vector 1)) + (r* (svref x 0)) + (c x))) + (r* (l) + (dolist (x l) (r x)))) + (r* l)))) + +(defmethod traverse ((operation operation) (c component)) + (flatten-tree + (while-collecting (collect) + (let ((*visit-count* 0)) + (do-traverse operation c #'collect))))) + +(defmethod perform ((operation operation) (c source-file)) + (sysdef-error + (compatfmt "~@") + (class-of operation) (class-of c))) + +(defmethod perform ((operation operation) (c module)) + (declare (ignorable operation c)) + nil) + +(defmethod mark-operation-done ((operation operation) (c component)) + (setf (gethash (type-of operation) (component-operation-times c)) + (reduce #'max + (cons (get-universal-time) + (mapcar #'safe-file-write-date (input-files operation c)))))) + +(defmethod perform-with-restarts (operation component) + ;; TOO verbose, especially as the default. Add your own :before method + ;; to perform-with-restart or perform if you want that: + #|(when *asdf-verbose* (explain operation component))|# + (perform operation component)) + +(defmethod perform-with-restarts :around (operation component) + (loop + (restart-case + (return (call-next-method)) + (retry () + :report + (lambda (s) + (format s (compatfmt "~@") + (operation-description operation component)))) + (accept () + :report + (lambda (s) + (format s (compatfmt "~@") + (operation-description operation component))) + (mark-operation-done operation component) + (return))))) + +(defmethod explain ((operation operation) (component component)) + (asdf-message (compatfmt "~&~@<; ~@;~A~:>~%") + (operation-description operation component))) + +(defmethod operation-description (operation component) + (format nil (compatfmt "~@<~A on ~A~@:>") + (class-of operation) component)) + +;;;; ------------------------------------------------------------------------- +;;;; compile-op + +(defclass compile-op (operation) + ((proclamations :initarg :proclamations :accessor compile-op-proclamations :initform nil) + (on-warnings :initarg :on-warnings :accessor operation-on-warnings + :initform *compile-file-warnings-behaviour*) + (on-failure :initarg :on-failure :accessor operation-on-failure + :initform *compile-file-failure-behaviour*) + (flags :initarg :flags :accessor compile-op-flags + :initform nil))) + +(defun* output-file (operation component) + "The unique output file of performing OPERATION on COMPONENT" + (let ((files (output-files operation component))) + (assert (length=n-p files 1)) + (first files))) + +(defun* ensure-all-directories-exist (pathnames) + (dolist (pathname pathnames) + (ensure-directories-exist (translate-logical-pathname pathname)))) + +(defmethod perform :before ((operation compile-op) (c source-file)) + (ensure-all-directories-exist (output-files operation c))) + +(defmethod perform :after ((operation operation) (c component)) + (mark-operation-done operation c)) + +(defgeneric* around-compile-hook (component)) +(defgeneric* call-with-around-compile-hook (component thunk)) + +(defmethod around-compile-hook ((c component)) + (cond + ((slot-boundp c 'around-compile) + (slot-value c 'around-compile)) + ((component-parent c) + (around-compile-hook (component-parent c))))) + +(defun ensure-function (fun &key (package :asdf)) + (etypecase fun + ((or symbol function) fun) + (cons (eval `(function ,fun))) + (string (eval `(function ,(with-standard-io-syntax + (let ((*package* (find-package package))) + (read-from-string fun)))))))) + +(defmethod call-with-around-compile-hook ((c component) thunk) + (let ((hook (around-compile-hook c))) + (if hook + (funcall (ensure-function hook) thunk) + (funcall thunk)))) + +;;; perform is required to check output-files to find out where to put +;;; its answers, in case it has been overridden for site policy +(defmethod perform ((operation compile-op) (c cl-source-file)) + (let ((source-file (component-pathname c)) + ;; on some implementations, there are more than one output-file, + ;; but the first one should always be the primary fasl that gets loaded. + (output-file (first (output-files operation c))) + (*compile-file-warnings-behaviour* (operation-on-warnings operation)) + (*compile-file-failure-behaviour* (operation-on-failure operation))) + (multiple-value-bind (output warnings-p failure-p) + (call-with-around-compile-hook + c #'(lambda (&rest flags) + (apply *compile-op-compile-file-function* source-file + :output-file output-file + :external-format (component-external-format c) + (append flags (compile-op-flags operation))))) + (unless output + (error 'compile-error :component c :operation operation)) + (when failure-p + (case (operation-on-failure operation) + (:warn (warn + (compatfmt "~@") + operation c)) + (:error (error 'compile-failed :component c :operation operation)) + (:ignore nil))) + (when warnings-p + (case (operation-on-warnings operation) + (:warn (warn + (compatfmt "~@") + operation c)) + (:error (error 'compile-warned :component c :operation operation)) + (:ignore nil)))))) + +(defmethod output-files ((operation compile-op) (c cl-source-file)) + (declare (ignorable operation)) + (let* ((p (lispize-pathname (component-pathname c))) + (f (compile-file-pathname ;; fasl + p #+mkcl :fasl-p #+mkcl t #+ecl :type #+ecl :fasl)) + #+mkcl (o (compile-file-pathname p :fasl-p nil))) ;; object file + #+ecl (if (use-ecl-byte-compiler-p) + (list f) + (list (compile-file-pathname p :type :object) f)) + #+mkcl (list o f) + #-(or ecl mkcl) (list f))) + +(defmethod perform ((operation compile-op) (c static-file)) + (declare (ignorable operation c)) + nil) + +(defmethod output-files ((operation compile-op) (c static-file)) + (declare (ignorable operation c)) + nil) + +(defmethod input-files ((operation compile-op) (c static-file)) + (declare (ignorable operation c)) + nil) + +(defmethod operation-description ((operation compile-op) component) + (declare (ignorable operation)) + (format nil (compatfmt "~@") component)) + +(defmethod operation-description ((operation compile-op) (component module)) + (declare (ignorable operation)) + (format nil (compatfmt "~@") component)) + + +;;;; ------------------------------------------------------------------------- +;;;; load-op + +(defclass basic-load-op (operation) ()) + +(defclass load-op (basic-load-op) ()) + +(defmethod perform-with-restarts ((o load-op) (c cl-source-file)) + (loop + (restart-case + (return (call-next-method)) + (try-recompiling () + :report (lambda (s) + (format s "Recompile ~a and try loading it again" + (component-name c))) + (perform (make-sub-operation c o c 'compile-op) c))))) + +(defmethod perform ((o load-op) (c cl-source-file)) + (map () #'load + #-(or ecl mkcl) + (input-files o c) + #+(or ecl mkcl) + (loop :for i :in (input-files o c) + :unless (string= (pathname-type i) "fas") + :collect (compile-file-pathname (lispize-pathname i))))) + +(defmethod perform ((operation load-op) (c static-file)) + (declare (ignorable operation c)) + nil) + +(defmethod operation-done-p ((operation load-op) (c static-file)) + (declare (ignorable operation c)) + t) + +(defmethod output-files ((operation operation) (c component)) + (declare (ignorable operation c)) + nil) + +(defmethod component-depends-on ((operation load-op) (c component)) + (declare (ignorable operation)) + (cons (list 'compile-op (component-name c)) + (call-next-method))) + +(defmethod operation-description ((operation load-op) component) + (declare (ignorable operation)) + (format nil (compatfmt "~@") + component)) + +(defmethod operation-description ((operation load-op) (component cl-source-file)) + (declare (ignorable operation)) + (format nil (compatfmt "~@") + component)) + +(defmethod operation-description ((operation load-op) (component module)) + (declare (ignorable operation)) + (format nil (compatfmt "~@") + component)) + +;;;; ------------------------------------------------------------------------- +;;;; load-source-op + +(defclass load-source-op (basic-load-op) ()) + +(defmethod perform ((o load-source-op) (c cl-source-file)) + (declare (ignorable o)) + (let ((source (component-pathname c))) + (setf (component-property c 'last-loaded-as-source) + (and (call-with-around-compile-hook + c #'(lambda () (load source :external-format (component-external-format c)))) + (get-universal-time))))) + +(defmethod perform ((operation load-source-op) (c static-file)) + (declare (ignorable operation c)) + nil) + +(defmethod output-files ((operation load-source-op) (c component)) + (declare (ignorable operation c)) + nil) + +;;; FIXME: We simply copy load-op's dependencies. This is Just Not Right. +(defmethod component-depends-on ((o load-source-op) (c component)) + (declare (ignorable o)) + (loop :with what-would-load-op-do = (component-depends-on 'load-op c) + :for (op . co) :in what-would-load-op-do + :when (eq op 'load-op) :collect (cons 'load-source-op co))) + +(defmethod operation-done-p ((o load-source-op) (c source-file)) + (declare (ignorable o)) + (if (or (not (component-property c 'last-loaded-as-source)) + (> (safe-file-write-date (component-pathname c)) + (component-property c 'last-loaded-as-source))) + nil t)) + +(defmethod operation-description ((operation load-source-op) component) + (declare (ignorable operation)) + (format nil (compatfmt "~@") + component)) + +(defmethod operation-description ((operation load-source-op) (component module)) + (declare (ignorable operation)) + (format nil (compatfmt "~@") component)) + + +;;;; ------------------------------------------------------------------------- +;;;; test-op + +(defclass test-op (operation) ()) + +(defmethod perform ((operation test-op) (c component)) + (declare (ignorable operation c)) + nil) + +(defmethod operation-done-p ((operation test-op) (c system)) + "Testing a system is _never_ done." + (declare (ignorable operation c)) + nil) + +(defmethod component-depends-on :around ((o test-op) (c system)) + (declare (ignorable o)) + (cons `(load-op ,(component-name c)) (call-next-method))) + + +;;;; ------------------------------------------------------------------------- +;;;; Invoking Operations + +(defgeneric* operate (operation-class system &key &allow-other-keys)) +(defgeneric* perform-plan (plan &key)) + +;;;; Separating this into a different function makes it more forward-compatible +(defun* cleanup-upgraded-asdf (old-version) + (let ((new-version (asdf-version))) + (unless (equal old-version new-version) + (cond + ((version-satisfies new-version old-version) + (asdf-message (compatfmt "~&~@<; ~@;Upgraded ASDF from version ~A to version ~A~@:>~%") + old-version new-version)) + ((version-satisfies old-version new-version) + (warn (compatfmt "~&~@<; ~@;Downgraded ASDF from version ~A to version ~A~@:>~%") + old-version new-version)) + (t + (asdf-message (compatfmt "~&~@<; ~@;Changed ASDF from version ~A to incompatible version ~A~@:>~%") + old-version new-version))) + (let ((asdf (funcall (find-symbol* 'find-system :asdf) :asdf))) + ;; Invalidate all systems but ASDF itself. + (setf *defined-systems* (make-defined-systems-table)) + (register-system asdf) + ;; If we're in the middle of something, restart it. + (when *systems-being-defined* + (let ((l (loop :for name :being :the :hash-keys :of *systems-being-defined* :collect name))) + (clrhash *systems-being-defined*) + (dolist (s l) (find-system s nil)))) + t)))) + +;;;; Try to upgrade of ASDF. If a different version was used, return T. +;;;; We need do that before we operate on anything that depends on ASDF. +(defun* upgrade-asdf () + (let ((version (asdf-version))) + (handler-bind (((or style-warning warning) #'muffle-warning)) + (operate 'load-op :asdf :verbose nil)) + (cleanup-upgraded-asdf version))) + +(defmethod perform-plan ((steps list) &key) + (let ((*package* *package*) + (*readtable* *readtable*)) + (with-compilation-unit () + (loop :for (op . component) :in steps :do + (perform-with-restarts op component))))) + +(defmethod operate (operation-class system &rest args + &key ((:verbose *asdf-verbose*) *asdf-verbose*) version force + &allow-other-keys) + (declare (ignore force)) + (with-system-definitions () + (let* ((op (apply 'make-instance operation-class + :original-initargs args + args)) + (*verbose-out* (if *asdf-verbose* *standard-output* (make-broadcast-stream))) + (system (etypecase system + (system system) + ((or string symbol) (find-system system))))) + (unless (version-satisfies system version) + (error 'missing-component-of-version :requires system :version version)) + (let ((steps (traverse op system))) + (when (and (not (equal '("asdf") (component-find-path system))) + (find '("asdf") (mapcar 'cdr steps) + :test 'equal :key 'component-find-path) + (upgrade-asdf)) + ;; If we needed to upgrade ASDF to achieve our goal, + ;; then do it specially as the first thing, then + ;; invalidate all existing system + ;; retry the whole thing with the new OPERATE function, + ;; which on some implementations + ;; has a new symbol shadowing the current one. + (return-from operate + (apply (find-symbol* 'operate :asdf) operation-class system args))) + (perform-plan steps) + (values op steps))))) + +(defun* oos (operation-class system &rest args &key force verbose version + &allow-other-keys) + (declare (ignore force verbose version)) + (apply 'operate operation-class system args)) + +(let ((operate-docstring + "Operate does three things: + +1. It creates an instance of OPERATION-CLASS using any keyword parameters +as initargs. +2. It finds the asdf-system specified by SYSTEM (possibly loading +it from disk). +3. It then calls TRAVERSE with the operation and system as arguments + +The traverse operation is wrapped in WITH-COMPILATION-UNIT and error +handling code. If a VERSION argument is supplied, then operate also +ensures that the system found satisfies it using the VERSION-SATISFIES +method. + +Note that dependencies may cause the operation to invoke other +operations on the system or its components: the new operations will be +created with the same initargs as the original one. +")) + (setf (documentation 'oos 'function) + (format nil + "Short for _operate on system_ and an alias for the OPERATE function.~%~%~a" + operate-docstring)) + (setf (documentation 'operate 'function) + operate-docstring)) + +(defun* load-system (system &rest keys &key force verbose version &allow-other-keys) + "Shorthand for `(operate 'asdf:load-op system)`. +See OPERATE for details." + (declare (ignore force verbose version)) + (apply 'operate *load-system-operation* system keys) + t) + +(defun* load-systems (&rest systems) + (map () 'load-system systems)) + +(defun component-loaded-p (c) + (and (gethash 'load-op (component-operation-times (find-component c nil))) t)) + +(defun loaded-systems () + (remove-if-not 'component-loaded-p (registered-systems))) + +(defun require-system (s &rest keys &key &allow-other-keys) + (apply 'load-system s :force-not (loaded-systems) keys)) + +(defun* compile-system (system &rest args &key force verbose version + &allow-other-keys) + "Shorthand for `(asdf:operate 'asdf:compile-op system)`. See OPERATE +for details." + (declare (ignore force verbose version)) + (apply 'operate 'compile-op system args) + t) + +(defun* test-system (system &rest args &key force verbose version + &allow-other-keys) + "Shorthand for `(asdf:operate 'asdf:test-op system)`. See OPERATE for +details." + (declare (ignore force verbose version)) + (apply 'operate 'test-op system args) + t) + +;;;; ------------------------------------------------------------------------- +;;;; Defsystem + +(defun* load-pathname () + (resolve-symlinks* (or *load-pathname* *compile-file-pathname*))) + +(defun* determine-system-pathname (pathname) + ;; The defsystem macro calls us to determine + ;; the pathname of a system as follows: + ;; 1. the one supplied, + ;; 2. derived from *load-pathname* via load-pathname + ;; 3. taken from the *default-pathname-defaults* via default-directory + (let* ((file-pathname (load-pathname)) + (directory-pathname (and file-pathname (pathname-directory-pathname file-pathname)))) + (or (and pathname (subpathname directory-pathname pathname :type :directory)) + directory-pathname + (default-directory)))) + +(defun* find-class* (x &optional (errorp t) environment) + (etypecase x + ((or standard-class built-in-class) x) + (symbol (find-class x errorp environment)))) + +(defun* class-for-type (parent type) + (or (loop :for symbol :in (list + type + (find-symbol* type *package*) + (find-symbol* type :asdf)) + :for class = (and symbol (find-class symbol nil)) + :when (and class + (#-cormanlisp subtypep #+cormanlisp cl::subclassp + class (find-class 'component))) + :return class) + (and (eq type :file) + (find-class* + (or (loop :for module = parent :then (component-parent module) :while module + :thereis (module-default-component-class module)) + *default-component-class*) nil)) + (sysdef-error "don't recognize component type ~A" type))) + +(defun* maybe-add-tree (tree op1 op2 c) + "Add the node C at /OP1/OP2 in TREE, unless it's there already. +Returns the new tree (which probably shares structure with the old one)" + (let ((first-op-tree (assoc op1 tree))) + (if first-op-tree + (progn + (aif (assoc op2 (cdr first-op-tree)) + (if (find c (cdr it) :test #'equal) + nil + (setf (cdr it) (cons c (cdr it)))) + (setf (cdr first-op-tree) + (acons op2 (list c) (cdr first-op-tree)))) + tree) + (acons op1 (list (list op2 c)) tree)))) + +(defun* union-of-dependencies (&rest deps) + (let ((new-tree nil)) + (dolist (dep deps) + (dolist (op-tree dep) + (dolist (op (cdr op-tree)) + (dolist (c (cdr op)) + (setf new-tree + (maybe-add-tree new-tree (car op-tree) (car op) c)))))) + new-tree)) + + +(defvar *serial-depends-on* nil) + +(defun* sysdef-error-component (msg type name value) + (sysdef-error (strcat msg (compatfmt "~&~@")) + type name value)) + +(defun* check-component-input (type name weakly-depends-on + depends-on components in-order-to) + "A partial test of the values of a component." + (unless (listp depends-on) + (sysdef-error-component ":depends-on must be a list." + type name depends-on)) + (unless (listp weakly-depends-on) + (sysdef-error-component ":weakly-depends-on must be a list." + type name weakly-depends-on)) + (unless (listp components) + (sysdef-error-component ":components must be NIL or a list of components." + type name components)) + (unless (and (listp in-order-to) (listp (car in-order-to))) + (sysdef-error-component ":in-order-to must be NIL or a list of components." + type name in-order-to))) + +(defun* %remove-component-inline-methods (component) + (dolist (name +asdf-methods+) + (map () + ;; this is inefficient as most of the stored + ;; methods will not be for this particular gf + ;; But this is hardly performance-critical + #'(lambda (m) + (remove-method (symbol-function name) m)) + (component-inline-methods component))) + ;; clear methods, then add the new ones + (setf (component-inline-methods component) nil)) + +(defun* %define-component-inline-methods (ret rest) + (dolist (name +asdf-methods+) + (let ((keyword (intern (symbol-name name) :keyword))) + (loop :for data = rest :then (cddr data) + :for key = (first data) + :for value = (second data) + :while data + :when (eq key keyword) :do + (destructuring-bind (op qual (o c) &body body) value + (pushnew + (eval `(defmethod ,name ,qual ((,o ,op) (,c (eql ,ret))) + ,@body)) + (component-inline-methods ret))))))) + +(defun* %refresh-component-inline-methods (component rest) + (%remove-component-inline-methods component) + (%define-component-inline-methods component rest)) + +(defun* parse-component-form (parent options) + (destructuring-bind + (type name &rest rest &key + ;; the following list of keywords is reproduced below in the + ;; remove-keys form. important to keep them in sync + components pathname + perform explain output-files operation-done-p + weakly-depends-on depends-on serial in-order-to + do-first + (version nil versionp) + ;; list ends + &allow-other-keys) options + (declare (ignorable perform explain output-files operation-done-p)) + (check-component-input type name weakly-depends-on depends-on components in-order-to) + + (when (and parent + (find-component parent name) + ;; ignore the same object when rereading the defsystem + (not + (typep (find-component parent name) + (class-for-type parent type)))) + (error 'duplicate-names :name name)) + + (when versionp + (unless (parse-version version nil) + (warn (compatfmt "~@") + version name parent))) + + (let* ((args (list* :name (coerce-name name) + :pathname pathname + :parent parent + (remove-keys + '(components pathname + perform explain output-files operation-done-p + weakly-depends-on depends-on serial in-order-to) + rest))) + (ret (find-component parent name))) + (when weakly-depends-on + (appendf depends-on (remove-if (complement #'(lambda (x) (find-system x nil))) weakly-depends-on))) + (when *serial-depends-on* + (push *serial-depends-on* depends-on)) + (if ret ; preserve identity + (apply 'reinitialize-instance ret args) + (setf ret (apply 'make-instance (class-for-type parent type) args))) + (component-pathname ret) ; eagerly compute the absolute pathname + (when (typep ret 'module) + (let ((*serial-depends-on* nil)) + (setf (module-components ret) + (loop + :for c-form :in components + :for c = (parse-component-form ret c-form) + :for name = (component-name c) + :collect c + :when serial :do (setf *serial-depends-on* name)))) + (compute-module-components-by-name ret)) + + (setf (component-load-dependencies ret) depends-on) ;; Used by POIU + + (setf (component-in-order-to ret) + (union-of-dependencies + in-order-to + `((compile-op (compile-op ,@depends-on)) + (load-op (load-op ,@depends-on))))) + (setf (component-do-first ret) + (union-of-dependencies + do-first + `((compile-op (load-op ,@depends-on))))) + + (%refresh-component-inline-methods ret rest) + ret))) + +(defun* reset-system (system &rest keys &key &allow-other-keys) + (change-class (change-class system 'proto-system) 'system) + (apply 'reinitialize-instance system keys)) + +(defun* do-defsystem (name &rest options + &key pathname (class 'system) + defsystem-depends-on &allow-other-keys) + ;; The system must be registered before we parse the body, + ;; otherwise we recur when trying to find an existing system + ;; of the same name to reuse options (e.g. pathname) from. + ;; To avoid infinite recursion in cases where you defsystem a system + ;; that is registered to a different location to find-system, + ;; we also need to remember it in a special variable *systems-being-defined*. + (with-system-definitions () + (let* ((name (coerce-name name)) + (registered (system-registered-p name)) + (registered! (if registered + (rplaca registered (get-universal-time)) + (register-system (make-instance 'system :name name)))) + (system (reset-system (cdr registered!) + :name name :source-file (load-pathname))) + (component-options (remove-keys '(:class) options))) + (setf (gethash name *systems-being-defined*) system) + (apply 'load-systems defsystem-depends-on) + ;; We change-class (when necessary) AFTER we load the defsystem-dep's + ;; since the class might not be defined as part of those. + (let ((class (class-for-type nil class))) + (unless (eq (type-of system) class) + (change-class system class))) + (parse-component-form + nil (list* + :module name + :pathname (determine-system-pathname pathname) + component-options))))) + +(defmacro defsystem (name &body options) + `(apply 'do-defsystem ',name ',options)) + +;;;; --------------------------------------------------------------------------- +;;;; run-shell-command +;;;; +;;;; run-shell-command functions for other lisp implementations will be +;;;; gratefully accepted, if they do the same thing. +;;;; If the docstring is ambiguous, send a bug report. +;;;; +;;;; WARNING! The function below is mostly dysfunctional. +;;;; For instance, it will probably run fine on most implementations on Unix, +;;;; which will hopefully use the shell /bin/sh (which we force in some cases) +;;;; which is hopefully reasonably compatible with a POSIX *or* Bourne shell. +;;;; But behavior on Windows may vary wildly between implementations, +;;;; either relying on your having installed a POSIX sh, or going through +;;;; the CMD.EXE interpreter, for a totally different meaning, depending on +;;;; what is easily expressible in said implementation. +;;;; +;;;; We probably should move this functionality to its own system and deprecate +;;;; use of it from the asdf package. However, this would break unspecified +;;;; existing software, so until a clear alternative exists, we can't deprecate +;;;; it, and even after it's been deprecated, we will support it for a few +;;;; years so everyone has time to migrate away from it. -- fare 2009-12-01 +;;;; +;;;; As a suggested replacement which is portable to all ASDF-supported +;;;; implementations and operating systems except Genera, I recommend +;;;; xcvb-driver's xcvb-driver:run-program/ and its derivatives. + +(defun* run-shell-command (control-string &rest args) + "Interpolate ARGS into CONTROL-STRING as if by FORMAT, and +synchronously execute the result using a Bourne-compatible shell, with +output to *VERBOSE-OUT*. Returns the shell's exit code." + (let ((command (apply 'format nil control-string args))) + (asdf-message "; $ ~A~%" command) + + #+abcl + (ext:run-shell-command command :output *verbose-out*) + + #+allegro + ;; will this fail if command has embedded quotes - it seems to work + (multiple-value-bind (stdout stderr exit-code) + (excl.osi:command-output + #-mswindows (vector "/bin/sh" "/bin/sh" "-c" command) + #+mswindows command ; BEWARE! + :input nil :whole nil + #+mswindows :show-window #+mswindows :hide) + (asdf-message "~{~&~a~%~}~%" stderr) + (asdf-message "~{~&~a~%~}~%" stdout) + exit-code) + + #+clisp + ;; CLISP returns NIL for exit status zero. + (if *verbose-out* + (let* ((new-command (format nil "( ~A ) ; r=$? ; echo ; echo ASDF-EXIT-STATUS $r" + command)) + (outstream (ext:run-shell-command new-command :output :stream :wait t))) + (multiple-value-bind (retval out-lines) + (unwind-protect + (parse-clisp-shell-output outstream) + (ignore-errors (close outstream))) + (asdf-message "~{~&~a~%~}~%" out-lines) + retval)) + ;; there will be no output, just grab up the exit status + (or (ext:run-shell-command command :output nil :wait t) 0)) + + #+clozure + (nth-value 1 + (ccl:external-process-status + (ccl:run-program + (cond + ((os-unix-p) "/bin/sh") + ((os-windows-p) (strcat "CMD /C " command)) ; BEWARE! + (t (error "Unsupported OS"))) + (if (os-unix-p) (list "-c" command) '()) + :input nil :output *verbose-out* :wait t))) + + #+(or cmu scl) + (ext:process-exit-code + (ext:run-program + "/bin/sh" + (list "-c" command) + :input nil :output *verbose-out*)) + + #+cormanlisp + (win32:system command) + + #+ecl ;; courtesy of Juan Jose Garcia Ripoll + (ext:system command) + + #+gcl + (lisp:system command) + + #+lispworks + (apply 'system:call-system-showing-output command + :show-cmd nil :prefix "" :output-stream *verbose-out* + (when (os-unix-p) '(:shell-type "/bin/sh"))) + + #+mcl + (ccl::with-cstrs ((%command command)) (_system %command)) + + #+mkcl + ;; This has next to no chance of working on basic Windows! + ;; Your best hope is that Cygwin or MSYS is somewhere in the PATH. + (multiple-value-bind (io process exit-code) + (apply #'mkcl:run-program #+windows "sh" #-windows "/bin/sh" + (list "-c" command) + :input nil :output t #|*verbose-out*|# ;; will be *verbose-out* when we support it + #-windows '(:search nil)) + (declare (ignore io process)) + exit-code) + + #+sbcl + (sb-ext:process-exit-code + (apply 'sb-ext:run-program + #+win32 "sh" #-win32 "/bin/sh" + (list "-c" command) + :input nil :output *verbose-out* + #+win32 '(:search t) #-win32 nil)) + + #+xcl + (ext:run-shell-command command) + + #-(or abcl allegro clisp clozure cmu ecl gcl lispworks mcl mkcl sbcl scl xcl) + (error "RUN-SHELL-COMMAND not implemented for this Lisp"))) + +#+clisp +(defun* parse-clisp-shell-output (stream) + "Helper function for running shell commands under clisp. Parses a specially- +crafted output string to recover the exit status of the shell command and a +list of lines of output." + (loop :with status-prefix = "ASDF-EXIT-STATUS " + :with prefix-length = (length status-prefix) + :with exit-status = -1 :with lines = () + :for line = (read-line stream nil nil) + :while line :do (push line lines) :finally + (let* ((last (car lines)) + (status (and last (>= (length last) prefix-length) + (string-equal last status-prefix :end1 prefix-length) + (parse-integer last :start prefix-length :junk-allowed t)))) + (when status + (setf exit-status status) + (pop lines) (when (equal "" (car lines)) (pop lines))) + (return (values exit-status (reverse lines)))))) + +;;;; --------------------------------------------------------------------------- +;;;; system-relative-pathname + +(defun* system-definition-pathname (x) + ;; As of 2.014.8, we mean to make this function obsolete, + ;; but that won't happen until all clients have been updated. + ;;(cerror "Use ASDF:SYSTEM-SOURCE-FILE instead" + "Function ASDF:SYSTEM-DEFINITION-PATHNAME is obsolete. +It used to expose ASDF internals with subtle differences with respect to +user expectations, that have been refactored away since. +We recommend you use ASDF:SYSTEM-SOURCE-FILE instead +for a mostly compatible replacement that we're supporting, +or even ASDF:SYSTEM-SOURCE-DIRECTORY or ASDF:SYSTEM-RELATIVE-PATHNAME +if that's whay you mean." ;;) + (system-source-file x)) + +(defmethod system-source-file ((system system)) + ;; might be missing when upgrading from ASDF 1 and u-i-f-r-c failed + (unless (slot-boundp system 'source-file) + (%set-system-source-file + (probe-asd (component-name system) (component-pathname system)) system)) + (%system-source-file system)) +(defmethod system-source-file ((system-name string)) + (%system-source-file (find-system system-name))) +(defmethod system-source-file ((system-name symbol)) + (%system-source-file (find-system system-name))) + +(defun* system-source-directory (system-designator) + "Return a pathname object corresponding to the +directory in which the system specification (.asd file) is +located." + (pathname-directory-pathname (system-source-file system-designator))) + +(defun* relativize-directory (directory) + (cond + ((stringp directory) + (list :relative directory)) + ((eq (car directory) :absolute) + (cons :relative (cdr directory))) + (t + directory))) + +(defun* relativize-pathname-directory (pathspec) + (let ((p (pathname pathspec))) + (make-pathname + :directory (relativize-directory (pathname-directory p)) + :defaults p))) + +(defun* system-relative-pathname (system name &key type) + (subpathname (system-source-directory system) name :type type)) + + +;;; --------------------------------------------------------------------------- +;;; implementation-identifier +;;; +;;; produce a string to identify current implementation. +;;; Initially stolen from SLIME's SWANK, rewritten since. +;;; We're back to runtime checking, for the sake of e.g. ABCL. + +(defun* first-feature (features) + (dolist (x features) + (multiple-value-bind (val feature) + (if (consp x) (values (first x) (cons :or (rest x))) (values x x)) + (when (featurep feature) (return val))))) + +(defun implementation-type () + (first-feature + '(:abcl (:acl :allegro) (:ccl :clozure) :clisp (:corman :cormanlisp) :cmu + :ecl :gcl (:lw :lispworks) :mcl :mkcl :sbcl :scl :symbolics :xcl))) + +(defun operating-system () + (first-feature + '(:cygwin (:win :windows :mswindows :win32 :mingw32) ;; try cygwin first! + (:linux :linux :linux-target) ;; for GCL at least, must appear before :bsd + (:macosx :macosx :darwin :darwin-target :apple) ; also before :bsd + (:solaris :solaris :sunos) (:bsd :bsd :freebsd :netbsd :openbsd) :unix + :genera))) + +(defun architecture () + (first-feature + '((:x64 :amd64 :x86-64 :x86_64 :x8664-target (:and :word-size=64 :pc386)) + (:x86 :x86 :i386 :i486 :i586 :i686 :pentium3 :pentium4 :pc386 :iapx386 :x8632-target) + (:ppc64 :ppc64 :ppc64-target) (:ppc32 :ppc32 :ppc32-target :ppc :powerpc) + :hppa64 :hppa :sparc64 (:sparc32 :sparc32 :sparc) + :mipsel :mipseb :mips :alpha (:arm :arm :arm-target) :imach + ;; Java comes last: if someone uses C via CFFI or otherwise JNA or JNI, + ;; we may have to segregate the code still by architecture. + (:java :java :java-1.4 :java-1.5 :java-1.6 :java-1.7)))) + +#+clozure +(defun* ccl-fasl-version () + ;; the fasl version is target-dependent from CCL 1.8 on. + (or (let ((s 'ccl::target-fasl-version)) + (and (fboundp s) (funcall s))) + (and (boundp 'ccl::fasl-version) + (symbol-value 'ccl::fasl-version)) + (error "Can't determine fasl version."))) + +(defun lisp-version-string () + (let ((s (lisp-implementation-version))) + (car ; as opposed to OR, this idiom prevents some unreachable code warning + (list + #+allegro + (format nil "~A~@[~A~]~@[~A~]~@[~A~]" + excl::*common-lisp-version-number* + ;; M means "modern", as opposed to ANSI-compatible mode (which I consider default) + (and (eq excl:*current-case-mode* :case-sensitive-lower) "M") + ;; Note if not using International ACL + ;; see http://www.franz.com/support/documentation/8.1/doc/operators/excl/ics-target-case.htm + (excl:ics-target-case (:-ics "8")) + (and (member :smp *features*) "S")) + #+armedbear (format nil "~a-fasl~a" s system::*fasl-version*) + #+clisp + (subseq s 0 (position #\space s)) ; strip build information (date, etc.) + #+clozure + (format nil "~d.~d-f~d" ; shorten for windows + ccl::*openmcl-major-version* + ccl::*openmcl-minor-version* + (logand (ccl-fasl-version) #xFF)) + #+cmu (substitute #\- #\/ s) + #+scl (format nil "~A~A" s + ;; ANSI upper case vs lower case. + (ecase ext:*case-mode* (:upper "") (:lower "l"))) + #+ecl (format nil "~A~@[-~A~]" s + (let ((vcs-id (ext:lisp-implementation-vcs-id))) + (subseq vcs-id 0 (min (length vcs-id) 8)))) + #+gcl (subseq s (1+ (position #\space s))) + #+genera + (multiple-value-bind (major minor) (sct:get-system-version "System") + (format nil "~D.~D" major minor)) + #+mcl (subseq s 8) ; strip the leading "Version " + s)))) + +(defun* implementation-identifier () + (substitute-if + #\_ #'(lambda (x) (find x " /:;&^\\|?<>(){}[]$#`'\"")) + (format nil "~(~a~@{~@[-~a~]~}~)" + (or (implementation-type) (lisp-implementation-type)) + (or (lisp-version-string) (lisp-implementation-version)) + (or (operating-system) (software-type)) + (or (architecture) (machine-type))))) + +(defun* hostname () + ;; Note: untested on RMCL + #+(or abcl clozure cmucl ecl genera lispworks mcl mkcl sbcl scl xcl) (machine-instance) + #+cormanlisp "localhost" ;; is there a better way? Does it matter? + #+allegro (excl.osi:gethostname) + #+clisp (first (split-string (machine-instance) :separator " ")) + #+gcl (system:gethostname)) + + +;;; --------------------------------------------------------------------------- +;;; Generic support for configuration files + +(defun inter-directory-separator () + (if (os-unix-p) #\: #\;)) + +(defun* user-homedir () + (truenamize + (pathname-directory-pathname + #+cormanlisp (ensure-directory-pathname (user-homedir-pathname)) + #+mcl (current-user-homedir-pathname) + #-(or cormanlisp mcl) (user-homedir-pathname)))) + +(defun* ensure-pathname* (x want-absolute want-directory fmt &rest args) + (when (plusp (length x)) + (let ((p (if want-directory (ensure-directory-pathname x) (pathname x)))) + (when want-absolute + (unless (absolute-pathname-p p) + (cerror "ignore relative pathname" + "Invalid relative pathname ~A~@[ ~?~]" x fmt args) + (return-from ensure-pathname* nil))) + p))) +(defun* split-pathnames* (x want-absolute want-directory fmt &rest args) + (loop :for dir :in (split-string + x :separator (string (inter-directory-separator))) + :collect (apply 'ensure-pathname* dir want-absolute want-directory fmt args))) +(defun* getenv-pathname (x &key want-absolute want-directory &aux (s (getenv x))) + (ensure-pathname* s want-absolute want-directory "from (getenv ~S)" x)) +(defun* getenv-pathnames (x &key want-absolute want-directory &aux (s (getenv x))) + (and (plusp (length s)) + (split-pathnames* s want-absolute want-directory "from (getenv ~S) = ~S" x s))) +(defun* getenv-absolute-directory (x) + (getenv-pathname x :want-absolute t :want-directory t)) +(defun* getenv-absolute-directories (x) + (getenv-pathnames x :want-absolute t :want-directory t)) + +(defun* get-folder-path (folder) + (or ;; this semi-portably implements a subset of the functionality of lispworks' sys:get-folder-path + #+(and lispworks mswindows) (sys:get-folder-path folder) + ;; read-windows-registry HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders\AppData + (ecase folder + (:local-appdata (getenv-absolute-directory "LOCALAPPDATA")) + (:appdata (getenv-absolute-directory "APPDATA")) + (:common-appdata (or (getenv-absolute-directory "ALLUSERSAPPDATA") + (subpathname* (getenv-absolute-directory "ALLUSERSPROFILE") "Application Data/")))))) + +(defun* user-configuration-directories () + (let ((dirs + `(,@(when (os-unix-p) + (cons + (subpathname* (getenv-absolute-directory "XDG_CONFIG_HOME") "common-lisp/") + (loop :for dir :in (getenv-absolute-directories "XDG_CONFIG_DIRS") + :collect (subpathname* dir "common-lisp/")))) + ,@(when (os-windows-p) + `(,(subpathname* (get-folder-path :local-appdata) "common-lisp/config/") + ,(subpathname* (get-folder-path :appdata) "common-lisp/config/"))) + ,(subpathname (user-homedir) ".config/common-lisp/")))) + (remove-duplicates (remove-if-not #'absolute-pathname-p dirs) + :from-end t :test 'equal))) + +(defun* system-configuration-directories () + (cond + ((os-unix-p) '(#p"/etc/common-lisp/")) + ((os-windows-p) + (aif + ;; read-windows-registry HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders\Common AppData + (subpathname* (get-folder-path :common-appdata) "common-lisp/config/") + (list it))))) + +(defun* in-first-directory (dirs x &key (direction :input)) + (loop :with fun = (ecase direction + ((nil :input :probe) 'probe-file*) + ((:output :io) 'identity)) + :for dir :in dirs + :thereis (and dir (funcall fun (merge-pathnames* x (ensure-directory-pathname dir)))))) + +(defun* in-user-configuration-directory (x &key (direction :input)) + (in-first-directory (user-configuration-directories) x :direction direction)) +(defun* in-system-configuration-directory (x &key (direction :input)) + (in-first-directory (system-configuration-directories) x :direction direction)) + +(defun* configuration-inheritance-directive-p (x) + (let ((kw '(:inherit-configuration :ignore-inherited-configuration))) + (or (member x kw) + (and (length=n-p x 1) (member (car x) kw))))) + +(defun* report-invalid-form (reporter &rest args) + (etypecase reporter + (null + (apply 'error 'invalid-configuration args)) + (function + (apply reporter args)) + ((or symbol string) + (apply 'error reporter args)) + (cons + (apply 'apply (append reporter args))))) + +(defvar *ignored-configuration-form* nil) + +(defun* validate-configuration-form (form tag directive-validator + &key location invalid-form-reporter) + (unless (and (consp form) (eq (car form) tag)) + (setf *ignored-configuration-form* t) + (report-invalid-form invalid-form-reporter :form form :location location) + (return-from validate-configuration-form nil)) + (loop :with inherit = 0 :with ignore-invalid-p = nil :with x = (list tag) + :for directive :in (cdr form) + :when (cond + ((configuration-inheritance-directive-p directive) + (incf inherit) t) + ((eq directive :ignore-invalid-entries) + (setf ignore-invalid-p t) t) + ((funcall directive-validator directive) + t) + (ignore-invalid-p + nil) + (t + (setf *ignored-configuration-form* t) + (report-invalid-form invalid-form-reporter :form directive :location location) + nil)) + :do (push directive x) + :finally + (unless (= inherit 1) + (report-invalid-form invalid-form-reporter + :arguments (list (compatfmt "~@") + :inherit-configuration :ignore-inherited-configuration))) + (return (nreverse x)))) + +(defun* validate-configuration-file (file validator &key description) + (let ((forms (read-file-forms file))) + (unless (length=n-p forms 1) + (error (compatfmt "~@~%") + description forms)) + (funcall validator (car forms) :location file))) + +(defun* hidden-file-p (pathname) + (equal (first-char (pathname-name pathname)) #\.)) + +(defun* directory* (pathname-spec &rest keys &key &allow-other-keys) + (apply 'directory pathname-spec + (append keys '#.(or #+allegro '(:directories-are-files nil :follow-symbolic-links nil) + #+clozure '(:follow-links nil) + #+clisp '(:circle t :if-does-not-exist :ignore) + #+(or cmu scl) '(:follow-links nil :truenamep nil) + #+sbcl (when (find-symbol* :resolve-symlinks '#:sb-impl) + '(:resolve-symlinks nil)))))) + +(defun* validate-configuration-directory (directory tag validator &key invalid-form-reporter) + "Map the VALIDATOR across the .conf files in DIRECTORY, the TAG will +be applied to the results to yield a configuration form. Current +values of TAG include :source-registry and :output-translations." + (let ((files (sort (ignore-errors + (remove-if + 'hidden-file-p + (directory* (make-pathname :name :wild :type "conf" :defaults directory)))) + #'string< :key #'namestring))) + `(,tag + ,@(loop :for file :in files :append + (loop :with ignore-invalid-p = nil + :for form :in (read-file-forms file) + :when (eq form :ignore-invalid-entries) + :do (setf ignore-invalid-p t) + :else + :when (funcall validator form) + :collect form + :else + :when ignore-invalid-p + :do (setf *ignored-configuration-form* t) + :else + :do (report-invalid-form invalid-form-reporter :form form :location file))) + :inherit-configuration))) + + +;;; --------------------------------------------------------------------------- +;;; asdf-output-translations +;;; +;;; this code is heavily inspired from +;;; asdf-binary-translations, common-lisp-controller and cl-launch. +;;; --------------------------------------------------------------------------- + +(defvar *output-translations* () + "Either NIL (for uninitialized), or a list of one element, +said element itself being a sorted list of mappings. +Each mapping is a pair of a source pathname and destination pathname, +and the order is by decreasing length of namestring of the source pathname.") + +(defvar *user-cache* + (flet ((try (x &rest sub) (and x `(,x ,@sub)))) + (or + (try (getenv-absolute-directory "XDG_CACHE_HOME") "common-lisp" :implementation) + (when (os-windows-p) + (try (or (get-folder-path :local-appdata) + (get-folder-path :appdata)) + "common-lisp" "cache" :implementation)) + '(:home ".cache" "common-lisp" :implementation)))) + +(defun* output-translations () + (car *output-translations*)) + +(defun* (setf output-translations) (new-value) + (setf *output-translations* + (list + (stable-sort (copy-list new-value) #'> + :key #'(lambda (x) + (etypecase (car x) + ((eql t) -1) + (pathname + (let ((directory (pathname-directory (car x)))) + (if (listp directory) (length directory) 0)))))))) + new-value) + +(defun* output-translations-initialized-p () + (and *output-translations* t)) + +(defun* clear-output-translations () + "Undoes any initialization of the output translations. +You might want to call that before you dump an image that would be resumed +with a different configuration, so the configuration would be re-read then." + (setf *output-translations* '()) + (values)) + +(declaim (ftype (function (t &key (:directory boolean) (:wilden boolean)) + (values (or null pathname) &optional)) + resolve-location)) + +(defun* resolve-relative-location-component (x &key directory wilden) + (let ((r (etypecase x + (pathname x) + (string (coerce-pathname x :type (when directory :directory))) + (cons + (if (null (cdr x)) + (resolve-relative-location-component + (car x) :directory directory :wilden wilden) + (let* ((car (resolve-relative-location-component + (car x) :directory t :wilden nil))) + (merge-pathnames* + (resolve-relative-location-component + (cdr x) :directory directory :wilden wilden) + car)))) + ((eql :default-directory) + (relativize-pathname-directory (default-directory))) + ((eql :*/) *wild-directory*) + ((eql :**/) *wild-inferiors*) + ((eql :*.*.*) *wild-file*) + ((eql :implementation) + (coerce-pathname (implementation-identifier) :type :directory)) + ((eql :implementation-type) + (coerce-pathname (string-downcase (implementation-type)) :type :directory)) + ((eql :hostname) + (coerce-pathname (hostname) :type :directory))))) + (when (absolute-pathname-p r) + (error (compatfmt "~@") x)) + (if (or (pathnamep x) (not wilden)) r (wilden r)))) + +(defvar *here-directory* nil + "This special variable is bound to the currect directory during calls to +PROCESS-SOURCE-REGISTRY in order that we be able to interpret the :here +directive.") + +(defun* resolve-absolute-location-component (x &key directory wilden) + (let* ((r + (etypecase x + (pathname x) + (string (let ((p (#+mcl probe-posix #-mcl parse-namestring x))) + #+mcl (unless p (error "POSIX pathname ~S does not exist" x)) + (if directory (ensure-directory-pathname p) p))) + (cons + (return-from resolve-absolute-location-component + (if (null (cdr x)) + (resolve-absolute-location-component + (car x) :directory directory :wilden wilden) + (merge-pathnames* + (resolve-relative-location-component + (cdr x) :directory directory :wilden wilden) + (resolve-absolute-location-component + (car x) :directory t :wilden nil))))) + ((eql :root) + ;; special magic! we encode such paths as relative pathnames, + ;; but it means "relative to the root of the source pathname's host and device". + (return-from resolve-absolute-location-component + (let ((p (make-pathname :directory '(:relative)))) + (if wilden (wilden p) p)))) + ((eql :home) (user-homedir)) + ((eql :here) + (resolve-location (or *here-directory* + ;; give semantics in the case of use interactively + :default-directory) + :directory t :wilden nil)) + ((eql :user-cache) (resolve-location *user-cache* :directory t :wilden nil)) + ((eql :system-cache) + (error "Using the :system-cache is deprecated. ~%~ +Please remove it from your ASDF configuration")) + ((eql :default-directory) (default-directory)))) + (s (if (and wilden (not (pathnamep x))) + (wilden r) + r))) + (unless (absolute-pathname-p s) + (error (compatfmt "~@") x)) + s)) + +(defun* resolve-location (x &key directory wilden) + (if (atom x) + (resolve-absolute-location-component x :directory directory :wilden wilden) + (loop :with path = (resolve-absolute-location-component + (car x) :directory (and (or directory (cdr x)) t) + :wilden (and wilden (null (cdr x)))) + :for (component . morep) :on (cdr x) + :for dir = (and (or morep directory) t) + :for wild = (and wilden (not morep)) + :do (setf path (merge-pathnames* + (resolve-relative-location-component + component :directory dir :wilden wild) + path)) + :finally (return path)))) + +(defun* location-designator-p (x) + (flet ((absolute-component-p (c) + (typep c '(or string pathname + (member :root :home :here :user-cache :system-cache :default-directory)))) + (relative-component-p (c) + (typep c '(or string pathname + (member :default-directory :*/ :**/ :*.*.* + :implementation :implementation-type))))) + (or (typep x 'boolean) + (absolute-component-p x) + (and (consp x) (absolute-component-p (first x)) (every #'relative-component-p (rest x)))))) + +(defun* location-function-p (x) + (and + (length=n-p x 2) + (eq (car x) :function) + (or (symbolp (cadr x)) + (and (consp (cadr x)) + (eq (caadr x) 'lambda) + (length=n-p (cadadr x) 2))))) + +(defun* validate-output-translations-directive (directive) + (or (member directive '(:enable-user-cache :disable-cache nil)) + (and (consp directive) + (or (and (length=n-p directive 2) + (or (and (eq (first directive) :include) + (typep (second directive) '(or string pathname null))) + (and (location-designator-p (first directive)) + (or (location-designator-p (second directive)) + (location-function-p (second directive)))))) + (and (length=n-p directive 1) + (location-designator-p (first directive))))))) + +(defun* validate-output-translations-form (form &key location) + (validate-configuration-form + form + :output-translations + 'validate-output-translations-directive + :location location :invalid-form-reporter 'invalid-output-translation)) + +(defun* validate-output-translations-file (file) + (validate-configuration-file + file 'validate-output-translations-form :description "output translations")) + +(defun* validate-output-translations-directory (directory) + (validate-configuration-directory + directory :output-translations 'validate-output-translations-directive + :invalid-form-reporter 'invalid-output-translation)) + +(defun* parse-output-translations-string (string &key location) + (cond + ((or (null string) (equal string "")) + '(:output-translations :inherit-configuration)) + ((not (stringp string)) + (error (compatfmt "~@") string)) + ((eql (char string 0) #\") + (parse-output-translations-string (read-from-string string) :location location)) + ((eql (char string 0) #\() + (validate-output-translations-form (read-from-string string) :location location)) + (t + (loop + :with inherit = nil + :with directives = () + :with start = 0 + :with end = (length string) + :with source = nil + :with separator = (inter-directory-separator) + :for i = (or (position separator string :start start) end) :do + (let ((s (subseq string start i))) + (cond + (source + (push (list source (if (equal "" s) nil s)) directives) + (setf source nil)) + ((equal "" s) + (when inherit + (error (compatfmt "~@") + string)) + (setf inherit t) + (push :inherit-configuration directives)) + (t + (setf source s))) + (setf start (1+ i)) + (when (> start end) + (when source + (error (compatfmt "~@") + string)) + (unless inherit + (push :ignore-inherited-configuration directives)) + (return `(:output-translations ,@(nreverse directives))))))))) + +(defparameter *default-output-translations* + '(environment-output-translations + user-output-translations-pathname + user-output-translations-directory-pathname + system-output-translations-pathname + system-output-translations-directory-pathname)) + +(defun* wrapping-output-translations () + `(:output-translations + ;; Some implementations have precompiled ASDF systems, + ;; so we must disable translations for implementation paths. + #+sbcl ,(let ((h (getenv-pathname "SBCL_HOME" :want-directory t))) + (when h `((,(truenamize h) ,*wild-inferiors*) ()))) + ;; The below two are not needed: no precompiled ASDF system there + #+(or ecl mkcl) (,(translate-logical-pathname "SYS:**;*.*") ()) + #+mkcl (,(translate-logical-pathname "CONTRIB:") ()) + ;; #+clozure ,(ignore-errors (list (wilden (let ((*default-pathname-defaults* #p"")) (truename #p"ccl:"))) ())) + ;; All-import, here is where we want user stuff to be: + :inherit-configuration + ;; These are for convenience, and can be overridden by the user: + #+abcl (#p"/___jar___file___root___/**/*.*" (:user-cache #p"**/*.*")) + #+abcl (#p"jar:file:/**/*.jar!/**/*.*" (:function translate-jar-pathname)) + ;; We enable the user cache by default, and here is the place we do: + :enable-user-cache)) + +(defparameter *output-translations-file* (coerce-pathname "asdf-output-translations.conf")) +(defparameter *output-translations-directory* (coerce-pathname "asdf-output-translations.conf.d/")) + +(defun* user-output-translations-pathname (&key (direction :input)) + (in-user-configuration-directory *output-translations-file* :direction direction)) +(defun* system-output-translations-pathname (&key (direction :input)) + (in-system-configuration-directory *output-translations-file* :direction direction)) +(defun* user-output-translations-directory-pathname (&key (direction :input)) + (in-user-configuration-directory *output-translations-directory* :direction direction)) +(defun* system-output-translations-directory-pathname (&key (direction :input)) + (in-system-configuration-directory *output-translations-directory* :direction direction)) +(defun* environment-output-translations () + (getenv "ASDF_OUTPUT_TRANSLATIONS")) + +(defgeneric* process-output-translations (spec &key inherit collect)) +(declaim (ftype (function (t &key (:collect (or symbol function))) t) + inherit-output-translations)) +(declaim (ftype (function (t &key (:collect (or symbol function)) (:inherit list)) t) + process-output-translations-directive)) + +(defmethod process-output-translations ((x symbol) &key + (inherit *default-output-translations*) + collect) + (process-output-translations (funcall x) :inherit inherit :collect collect)) +(defmethod process-output-translations ((pathname pathname) &key inherit collect) + (cond + ((directory-pathname-p pathname) + (process-output-translations (validate-output-translations-directory pathname) + :inherit inherit :collect collect)) + ((probe-file* pathname) + (process-output-translations (validate-output-translations-file pathname) + :inherit inherit :collect collect)) + (t + (inherit-output-translations inherit :collect collect)))) +(defmethod process-output-translations ((string string) &key inherit collect) + (process-output-translations (parse-output-translations-string string) + :inherit inherit :collect collect)) +(defmethod process-output-translations ((x null) &key inherit collect) + (declare (ignorable x)) + (inherit-output-translations inherit :collect collect)) +(defmethod process-output-translations ((form cons) &key inherit collect) + (dolist (directive (cdr (validate-output-translations-form form))) + (process-output-translations-directive directive :inherit inherit :collect collect))) + +(defun* inherit-output-translations (inherit &key collect) + (when inherit + (process-output-translations (first inherit) :collect collect :inherit (rest inherit)))) + +(defun* process-output-translations-directive (directive &key inherit collect) + (if (atom directive) + (ecase directive + ((:enable-user-cache) + (process-output-translations-directive '(t :user-cache) :collect collect)) + ((:disable-cache) + (process-output-translations-directive '(t t) :collect collect)) + ((:inherit-configuration) + (inherit-output-translations inherit :collect collect)) + ((:ignore-inherited-configuration :ignore-invalid-entries nil) + nil)) + (let ((src (first directive)) + (dst (second directive))) + (if (eq src :include) + (when dst + (process-output-translations (pathname dst) :inherit nil :collect collect)) + (when src + (let ((trusrc (or (eql src t) + (let ((loc (resolve-location src :directory t :wilden t))) + (if (absolute-pathname-p loc) (truenamize loc) loc))))) + (cond + ((location-function-p dst) + (funcall collect + (list trusrc + (if (symbolp (second dst)) + (fdefinition (second dst)) + (eval (second dst)))))) + ((eq dst t) + (funcall collect (list trusrc t))) + (t + (let* ((trudst (if dst + (resolve-location dst :directory t :wilden t) + trusrc)) + (wilddst (merge-pathnames* *wild-file* trudst))) + (funcall collect (list wilddst t)) + (funcall collect (list trusrc trudst))))))))))) + +(defun* compute-output-translations (&optional parameter) + "read the configuration, return it" + (remove-duplicates + (while-collecting (c) + (inherit-output-translations + `(wrapping-output-translations ,parameter ,@*default-output-translations*) :collect #'c)) + :test 'equal :from-end t)) + +(defvar *output-translations-parameter* nil) + +(defun* initialize-output-translations (&optional (parameter *output-translations-parameter*)) + "read the configuration, initialize the internal configuration variable, +return the configuration" + (setf *output-translations-parameter* parameter + (output-translations) (compute-output-translations parameter))) + +(defun* disable-output-translations () + "Initialize output translations in a way that maps every file to itself, +effectively disabling the output translation facility." + (initialize-output-translations + '(:output-translations :disable-cache :ignore-inherited-configuration))) + +;; checks an initial variable to see whether the state is initialized +;; or cleared. In the former case, return current configuration; in +;; the latter, initialize. ASDF will call this function at the start +;; of (asdf:find-system). +(defun* ensure-output-translations () + (if (output-translations-initialized-p) + (output-translations) + (initialize-output-translations))) + +(defun* translate-pathname* (path absolute-source destination &optional root source) + (declare (ignore source)) + (cond + ((functionp destination) + (funcall destination path absolute-source)) + ((eq destination t) + path) + ((not (pathnamep destination)) + (error "Invalid destination")) + ((not (absolute-pathname-p destination)) + (translate-pathname path absolute-source (merge-pathnames* destination root))) + (root + (translate-pathname (directorize-pathname-host-device path) absolute-source destination)) + (t + (translate-pathname path absolute-source destination)))) + +(defun* apply-output-translations (path) + #+cormanlisp (truenamize path) #-cormanlisp + (etypecase path + (logical-pathname + path) + ((or pathname string) + (ensure-output-translations) + (loop :with p = (truenamize path) + :for (source destination) :in (car *output-translations*) + :for root = (when (or (eq source t) + (and (pathnamep source) + (not (absolute-pathname-p source)))) + (pathname-root p)) + :for absolute-source = (cond + ((eq source t) (wilden root)) + (root (merge-pathnames* source root)) + (t source)) + :when (or (eq source t) (pathname-match-p p absolute-source)) + :return (translate-pathname* p absolute-source destination root source) + :finally (return p))))) + +(defmethod output-files :around (operation component) + "Translate output files, unless asked not to" + operation component ;; hush genera, not convinced by declare ignorable(!) + (values + (multiple-value-bind (files fixedp) (call-next-method) + (if fixedp + files + (mapcar #'apply-output-translations files))) + t)) + +(defun* compile-file-pathname* (input-file &rest keys &key output-file &allow-other-keys) + (if (absolute-pathname-p output-file) + ;; what cfp should be doing, w/ mp* instead of mp + (let* ((type (pathname-type (apply 'compile-file-pathname "x.lisp" keys))) + (defaults (make-pathname + :type type :defaults (merge-pathnames* input-file)))) + (merge-pathnames* output-file defaults)) + (apply-output-translations + (apply 'compile-file-pathname input-file + (if output-file keys (remove-keyword :output-file keys)))))) + +(defun* tmpize-pathname (x) + (make-pathname + :name (strcat "ASDF-TMP-" (pathname-name x)) + :defaults x)) + +(defun* delete-file-if-exists (x) + (when (and x (probe-file* x)) + (delete-file x))) + +(defun* compile-file* (input-file &rest keys &key compile-check output-file &allow-other-keys) + (let* ((keywords (remove-keyword :compile-check keys)) + (output-file (apply 'compile-file-pathname* input-file :output-file output-file keywords)) + (tmp-file (tmpize-pathname output-file)) + (status :error)) + (multiple-value-bind (output-truename warnings-p failure-p) + (apply 'compile-file input-file :output-file tmp-file keywords) + (cond + (failure-p + (setf status *compile-file-failure-behaviour*)) + (warnings-p + (setf status *compile-file-warnings-behaviour*)) + (t + (setf status :success))) + (cond + ((and (ecase status + ((:success :warn :ignore) t) + ((:error nil))) + (or (not compile-check) + (apply compile-check input-file :output-file tmp-file keywords))) + (delete-file-if-exists output-file) + (when output-truename + (rename-file output-truename output-file) + (setf output-truename output-file))) + (t ;; error or failed check + (delete-file-if-exists output-truename) + (setf output-truename nil failure-p t))) + (values output-truename warnings-p failure-p)))) + +#+abcl +(defun* translate-jar-pathname (source wildcard) + (declare (ignore wildcard)) + (let* ((p (pathname (first (pathname-device source)))) + (root (format nil "/___jar___file___root___/~@[~A/~]" + (and (find :windows *features*) + (pathname-device p))))) + (apply-output-translations + (merge-pathnames* + (relativize-pathname-directory source) + (merge-pathnames* + (relativize-pathname-directory (ensure-directory-pathname p)) + root))))) + +;;;; ----------------------------------------------------------------- +;;;; Compatibility mode for ASDF-Binary-Locations + +(defmethod operate :before (operation-class system &rest args &key &allow-other-keys) + (declare (ignorable operation-class system args)) + (when (find-symbol* '#:output-files-for-system-and-operation :asdf) + (error "ASDF 2 is not compatible with ASDF-BINARY-LOCATIONS, which you are using. +ASDF 2 now achieves the same purpose with its builtin ASDF-OUTPUT-TRANSLATIONS, +which should be easier to configure. Please stop using ASDF-BINARY-LOCATIONS, +and instead use ASDF-OUTPUT-TRANSLATIONS. See the ASDF manual for details. +In case you insist on preserving your previous A-B-L configuration, but +do not know how to achieve the same effect with A-O-T, you may use function +ASDF:ENABLE-ASDF-BINARY-LOCATIONS-COMPATIBILITY as documented in the manual; +call that function where you would otherwise have loaded and configured A-B-L."))) + +(defun* enable-asdf-binary-locations-compatibility + (&key + (centralize-lisp-binaries nil) + (default-toplevel-directory + (subpathname (user-homedir) ".fasls/")) ;; Use ".cache/common-lisp/" instead ??? + (include-per-user-information nil) + (map-all-source-files (or #+(or clisp ecl mkcl) t nil)) + (source-to-target-mappings nil)) + #+(or clisp ecl mkcl) + (when (null map-all-source-files) + (error "asdf:enable-asdf-binary-locations-compatibility doesn't support :map-all-source-files nil on CLISP, ECL and MKCL")) + (let* ((fasl-type (pathname-type (compile-file-pathname "foo.lisp"))) + (mapped-files (if map-all-source-files *wild-file* + (make-pathname :type fasl-type :defaults *wild-file*))) + (destination-directory + (if centralize-lisp-binaries + `(,default-toplevel-directory + ,@(when include-per-user-information + (cdr (pathname-directory (user-homedir)))) + :implementation ,*wild-inferiors*) + `(:root ,*wild-inferiors* :implementation)))) + (initialize-output-translations + `(:output-translations + ,@source-to-target-mappings + ((:root ,*wild-inferiors* ,mapped-files) + (,@destination-directory ,mapped-files)) + (t t) + :ignore-inherited-configuration)))) + +;;;; ----------------------------------------------------------------- +;;;; Source Registry Configuration, by Francois-Rene Rideau +;;;; See the Manual and https://bugs.launchpad.net/asdf/+bug/485918 + +;; Using ack 1.2 exclusions +(defvar *default-source-registry-exclusions* + '(".bzr" ".cdv" + ;; "~.dep" "~.dot" "~.nib" "~.plst" ; we don't support ack wildcards + ".git" ".hg" ".pc" ".svn" "CVS" "RCS" "SCCS" "_darcs" + "_sgbak" "autom4te.cache" "cover_db" "_build" + "debian")) ;; debian often builds stuff under the debian directory... BAD. + +(defvar *source-registry-exclusions* *default-source-registry-exclusions*) + +(defvar *source-registry* nil + "Either NIL (for uninitialized), or an equal hash-table, mapping +system names to pathnames of .asd files") + +(defun* source-registry-initialized-p () + (typep *source-registry* 'hash-table)) + +(defun* clear-source-registry () + "Undoes any initialization of the source registry. +You might want to call that before you dump an image that would be resumed +with a different configuration, so the configuration would be re-read then." + (setf *source-registry* nil) + (values)) + +(defparameter *wild-asd* + (make-pathname :directory nil :name *wild* :type "asd" :version :newest)) + +(defun* filter-logical-directory-results (directory entries merger) + (if (typep directory 'logical-pathname) + ;; Try hard to not resolve logical-pathname into physical pathnames; + ;; otherwise logical-pathname users/lovers will be disappointed. + ;; If directory* could use some implementation-dependent magic, + ;; we will have logical pathnames already; otherwise, + ;; we only keep pathnames for which specifying the name and + ;; translating the LPN commute. + (loop :for f :in entries + :for p = (or (and (typep f 'logical-pathname) f) + (let* ((u (ignore-errors (funcall merger f)))) + ;; The first u avoids a cumbersome (truename u) error. + ;; At this point f should already be a truename, + ;; but isn't quite in CLISP, for doesn't have :version :newest + (and u (equal (ignore-errors (truename u)) (truename f)) u))) + :when p :collect p) + entries)) + +(defun* directory-files (directory &optional (pattern *wild-file*)) + (let ((dir (pathname directory))) + (when (typep dir 'logical-pathname) + ;; Because of the filtering we do below, + ;; logical pathnames have restrictions on wild patterns. + ;; Not that the results are very portable when you use these patterns on physical pathnames. + (when (wild-pathname-p dir) + (error "Invalid wild pattern in logical directory ~S" directory)) + (unless (member (pathname-directory pattern) '(() (:relative)) :test 'equal) + (error "Invalid file pattern ~S for logical directory ~S" pattern directory)) + (setf pattern (make-pathname-logical pattern (pathname-host dir)))) + (let ((entries (ignore-errors (directory* (merge-pathnames* pattern dir))))) + (filter-logical-directory-results + directory entries + #'(lambda (f) + (make-pathname :defaults dir + :name (make-pathname-component-logical (pathname-name f)) + :type (make-pathname-component-logical (pathname-type f)) + :version (make-pathname-component-logical (pathname-version f)))))))) + +(defun* directory-asd-files (directory) + (directory-files directory *wild-asd*)) + +(defun* subdirectories (directory) + (let* ((directory (ensure-directory-pathname directory)) + #-(or abcl cormanlisp genera xcl) + (wild (merge-pathnames* + #-(or abcl allegro cmu lispworks sbcl scl xcl) + *wild-directory* + #+(or abcl allegro cmu lispworks sbcl scl xcl) "*.*" + directory)) + (dirs + #-(or abcl cormanlisp genera xcl) + (ignore-errors + (directory* wild . #.(or #+clozure '(:directories t :files nil) + #+mcl '(:directories t)))) + #+(or abcl xcl) (system:list-directory directory) + #+cormanlisp (cl::directory-subdirs directory) + #+genera (fs:directory-list directory)) + #+(or abcl allegro cmu genera lispworks sbcl scl xcl) + (dirs (loop :for x :in dirs + :for d = #+(or abcl xcl) (extensions:probe-directory x) + #+allegro (excl:probe-directory x) + #+(or cmu sbcl scl) (directory-pathname-p x) + #+genera (getf (cdr x) :directory) + #+lispworks (lw:file-directory-p x) + :when d :collect #+(or abcl allegro xcl) d + #+genera (ensure-directory-pathname (first x)) + #+(or cmu lispworks sbcl scl) x))) + (filter-logical-directory-results + directory dirs + (let ((prefix (or (normalize-pathname-directory-component (pathname-directory directory)) + '(:absolute)))) ; because allegro returns NIL for #p"FOO:" + #'(lambda (d) + (let ((dir (normalize-pathname-directory-component (pathname-directory d)))) + (and (consp dir) (consp (cdr dir)) + (make-pathname + :defaults directory :name nil :type nil :version nil + :directory (append prefix (make-pathname-component-logical (last dir))))))))))) + +(defun* collect-asds-in-directory (directory collect) + (map () collect (directory-asd-files directory))) + +(defun* collect-sub*directories (directory collectp recursep collector) + (when (funcall collectp directory) + (funcall collector directory)) + (dolist (subdir (subdirectories directory)) + (when (funcall recursep subdir) + (collect-sub*directories subdir collectp recursep collector)))) + +(defun* collect-sub*directories-asd-files + (directory &key + (exclude *default-source-registry-exclusions*) + collect) + (collect-sub*directories + directory + (constantly t) + #'(lambda (x) (not (member (car (last (pathname-directory x))) exclude :test #'equal))) + #'(lambda (dir) (collect-asds-in-directory dir collect)))) + +(defun* validate-source-registry-directive (directive) + (or (member directive '(:default-registry)) + (and (consp directive) + (let ((rest (rest directive))) + (case (first directive) + ((:include :directory :tree) + (and (length=n-p rest 1) + (location-designator-p (first rest)))) + ((:exclude :also-exclude) + (every #'stringp rest)) + ((:default-registry) + (null rest))))))) + +(defun* validate-source-registry-form (form &key location) + (validate-configuration-form + form :source-registry 'validate-source-registry-directive + :location location :invalid-form-reporter 'invalid-source-registry)) + +(defun* validate-source-registry-file (file) + (validate-configuration-file + file 'validate-source-registry-form :description "a source registry")) + +(defun* validate-source-registry-directory (directory) + (validate-configuration-directory + directory :source-registry 'validate-source-registry-directive + :invalid-form-reporter 'invalid-source-registry)) + +(defun* parse-source-registry-string (string &key location) + (cond + ((or (null string) (equal string "")) + '(:source-registry :inherit-configuration)) + ((not (stringp string)) + (error (compatfmt "~@") string)) + ((find (char string 0) "\"(") + (validate-source-registry-form (read-from-string string) :location location)) + (t + (loop + :with inherit = nil + :with directives = () + :with start = 0 + :with end = (length string) + :with separator = (inter-directory-separator) + :for pos = (position separator string :start start) :do + (let ((s (subseq string start (or pos end)))) + (flet ((check (dir) + (unless (absolute-pathname-p dir) + (error (compatfmt "~@") string)) + dir)) + (cond + ((equal "" s) ; empty element: inherit + (when inherit + (error (compatfmt "~@") + string)) + (setf inherit t) + (push ':inherit-configuration directives)) + ((string-suffix-p s "//") ;; TODO: allow for doubling of separator even outside Unix? + (push `(:tree ,(check (subseq s 0 (- (length s) 2)))) directives)) + (t + (push `(:directory ,(check s)) directives)))) + (cond + (pos + (setf start (1+ pos))) + (t + (unless inherit + (push '(:ignore-inherited-configuration) directives)) + (return `(:source-registry ,@(nreverse directives)))))))))) + +(defun* register-asd-directory (directory &key recurse exclude collect) + (if (not recurse) + (collect-asds-in-directory directory collect) + (collect-sub*directories-asd-files + directory :exclude exclude :collect collect))) + +(defparameter *default-source-registries* + '(environment-source-registry + user-source-registry + user-source-registry-directory + system-source-registry + system-source-registry-directory + default-source-registry)) + +(defparameter *source-registry-file* (coerce-pathname "source-registry.conf")) +(defparameter *source-registry-directory* (coerce-pathname "source-registry.conf.d/")) + +(defun* wrapping-source-registry () + `(:source-registry + #+ecl (:tree ,(translate-logical-pathname "SYS:")) + #+mkcl (:tree ,(translate-logical-pathname "CONTRIB:")) + #+sbcl (:tree ,(truenamize (getenv-pathname "SBCL_HOME" :want-directory t))) + :inherit-configuration + #+cmu (:tree #p"modules:") + #+scl (:tree #p"file://modules/"))) +(defun* default-source-registry () + `(:source-registry + #+sbcl (:directory ,(subpathname (user-homedir) ".sbcl/systems/")) + (:directory ,(default-directory)) + ,@(loop :for dir :in + `(,@(when (os-unix-p) + `(,(or (getenv-absolute-directory "XDG_DATA_HOME") + (subpathname (user-homedir) ".local/share/")) + ,@(or (getenv-absolute-directories "XDG_DATA_DIRS") + '("/usr/local/share" "/usr/share")))) + ,@(when (os-windows-p) + (mapcar 'get-folder-path '(:local-appdata :appdata :common-appdata)))) + :collect `(:directory ,(subpathname* dir "common-lisp/systems/")) + :collect `(:tree ,(subpathname* dir "common-lisp/source/"))) + :inherit-configuration)) +(defun* user-source-registry (&key (direction :input)) + (in-user-configuration-directory *source-registry-file* :direction direction)) +(defun* system-source-registry (&key (direction :input)) + (in-system-configuration-directory *source-registry-file* :direction direction)) +(defun* user-source-registry-directory (&key (direction :input)) + (in-user-configuration-directory *source-registry-directory* :direction direction)) +(defun* system-source-registry-directory (&key (direction :input)) + (in-system-configuration-directory *source-registry-directory* :direction direction)) +(defun* environment-source-registry () + (getenv "CL_SOURCE_REGISTRY")) + +(defgeneric* process-source-registry (spec &key inherit register)) +(declaim (ftype (function (t &key (:register (or symbol function))) t) + inherit-source-registry)) +(declaim (ftype (function (t &key (:register (or symbol function)) (:inherit list)) t) + process-source-registry-directive)) + +(defmethod process-source-registry ((x symbol) &key inherit register) + (process-source-registry (funcall x) :inherit inherit :register register)) +(defmethod process-source-registry ((pathname pathname) &key inherit register) + (cond + ((directory-pathname-p pathname) + (let ((*here-directory* (truenamize pathname))) + (process-source-registry (validate-source-registry-directory pathname) + :inherit inherit :register register))) + ((probe-file* pathname) + (let ((*here-directory* (pathname-directory-pathname pathname))) + (process-source-registry (validate-source-registry-file pathname) + :inherit inherit :register register))) + (t + (inherit-source-registry inherit :register register)))) +(defmethod process-source-registry ((string string) &key inherit register) + (process-source-registry (parse-source-registry-string string) + :inherit inherit :register register)) +(defmethod process-source-registry ((x null) &key inherit register) + (declare (ignorable x)) + (inherit-source-registry inherit :register register)) +(defmethod process-source-registry ((form cons) &key inherit register) + (let ((*source-registry-exclusions* *default-source-registry-exclusions*)) + (dolist (directive (cdr (validate-source-registry-form form))) + (process-source-registry-directive directive :inherit inherit :register register)))) + +(defun* inherit-source-registry (inherit &key register) + (when inherit + (process-source-registry (first inherit) :register register :inherit (rest inherit)))) + +(defun* process-source-registry-directive (directive &key inherit register) + (destructuring-bind (kw &rest rest) (if (consp directive) directive (list directive)) + (ecase kw + ((:include) + (destructuring-bind (pathname) rest + (process-source-registry (resolve-location pathname) :inherit nil :register register))) + ((:directory) + (destructuring-bind (pathname) rest + (when pathname + (funcall register (resolve-location pathname :directory t))))) + ((:tree) + (destructuring-bind (pathname) rest + (when pathname + (funcall register (resolve-location pathname :directory t) + :recurse t :exclude *source-registry-exclusions*)))) + ((:exclude) + (setf *source-registry-exclusions* rest)) + ((:also-exclude) + (appendf *source-registry-exclusions* rest)) + ((:default-registry) + (inherit-source-registry '(default-source-registry) :register register)) + ((:inherit-configuration) + (inherit-source-registry inherit :register register)) + ((:ignore-inherited-configuration) + nil))) + nil) + +(defun* flatten-source-registry (&optional parameter) + (remove-duplicates + (while-collecting (collect) + (let ((*default-pathname-defaults* (default-directory))) + (inherit-source-registry + `(wrapping-source-registry + ,parameter + ,@*default-source-registries*) + :register #'(lambda (directory &key recurse exclude) + (collect (list directory :recurse recurse :exclude exclude)))))) + :test 'equal :from-end t)) + +;; Will read the configuration and initialize all internal variables. +(defun* compute-source-registry (&optional parameter (registry *source-registry*)) + (dolist (entry (flatten-source-registry parameter)) + (destructuring-bind (directory &key recurse exclude) entry + (let* ((h (make-hash-table :test 'equal))) ; table to detect duplicates + (register-asd-directory + directory :recurse recurse :exclude exclude :collect + #'(lambda (asd) + (let* ((name (pathname-name asd)) + (name (if (typep asd 'logical-pathname) + ;; logical pathnames are upper-case, + ;; at least in the CLHS and on SBCL, + ;; yet (coerce-name :foo) is lower-case. + ;; won't work well with (load-system "Foo") + ;; instead of (load-system 'foo) + (string-downcase name) + name))) + (cond + ((gethash name registry) ; already shadowed by something else + nil) + ((gethash name h) ; conflict at current level + (when *asdf-verbose* + (warn (compatfmt "~@") + directory recurse name (gethash name h) asd))) + (t + (setf (gethash name registry) asd) + (setf (gethash name h) asd)))))) + h))) + (values)) + +(defvar *source-registry-parameter* nil) + +(defun* initialize-source-registry (&optional (parameter *source-registry-parameter*)) + (setf *source-registry-parameter* parameter) + (setf *source-registry* (make-hash-table :test 'equal)) + (compute-source-registry parameter)) + +;; Checks an initial variable to see whether the state is initialized +;; or cleared. In the former case, return current configuration; in +;; the latter, initialize. ASDF will call this function at the start +;; of (asdf:find-system) to make sure the source registry is initialized. +;; However, it will do so *without* a parameter, at which point it +;; will be too late to provide a parameter to this function, though +;; you may override the configuration explicitly by calling +;; initialize-source-registry directly with your parameter. +(defun* ensure-source-registry (&optional parameter) + (unless (source-registry-initialized-p) + (initialize-source-registry parameter)) + (values)) + +(defun* sysdef-source-registry-search (system) + (ensure-source-registry) + (values (gethash (coerce-name system) *source-registry*))) + +(defun* clear-configuration () + (clear-source-registry) + (clear-output-translations)) + + +;;; ECL and MKCL support for COMPILE-OP / LOAD-OP +;;; +;;; In ECL and MKCL, these operations produce both +;;; FASL files and the object files that they are built from. +;;; Having both of them allows us to later on reuse the object files +;;; for bundles, libraries, standalone executables, etc. +;;; +;;; This has to be in asdf.lisp and not asdf-ecl.lisp, or else it becomes +;;; a problem for asdf on ECL to compile asdf-ecl.lisp after loading asdf.lisp. +;;; +;;; Also, register-pre-built-system. + +#+(or ecl mkcl) +(progn + (defun register-pre-built-system (name) + (register-system (make-instance 'system :name (coerce-name name) :source-file nil))) + + #+(or (and ecl win32) (and mkcl windows)) + (unless (assoc "asd" #+ecl ext:*load-hooks* #+mkcl si::*load-hooks* :test 'equal) + (appendf #+ecl ext:*load-hooks* #+mkcl si::*load-hooks* '(("asd" . si::load-source)))) + + (setf #+ecl ext:*module-provider-functions* #+mkcl mk-ext::*module-provider-functions* + (loop :for f :in #+ecl ext:*module-provider-functions* + #+mkcl mk-ext::*module-provider-functions* + :unless (eq f 'module-provide-asdf) + :collect #'(lambda (name) + (let ((l (multiple-value-list (funcall f name)))) + (and (first l) (register-pre-built-system (coerce-name name))) + (values-list l))))) + + (setf *compile-op-compile-file-function* 'compile-file-keeping-object) + + (defun compile-file-keeping-object (input-file &rest keys &key &allow-other-keys) + (#+ecl if #+ecl (use-ecl-byte-compiler-p) #+ecl (apply 'compile-file* input-file keys) + #+mkcl progn + (multiple-value-bind (object-file flags1 flags2) + (apply 'compile-file* input-file + #+ecl :system-p #+ecl t #+mkcl :fasl-p #+mkcl nil keys) + (values (and object-file + (compiler::build-fasl + (compile-file-pathname object-file + #+ecl :type #+ecl :fasl #+mkcl :fasl-p #+mkcl t) + #+ecl :lisp-files #+mkcl :lisp-object-files (list object-file)) + object-file) + flags1 + flags2))))) + +;;;; ----------------------------------------------------------------------- +;;;; Hook into REQUIRE for ABCL, CLISP, ClozureCL, CMUCL, ECL, MKCL and SBCL +;;;; +(defun* module-provide-asdf (name) + (handler-bind + ((style-warning #'muffle-warning) + #-genera + (missing-component (constantly nil)) + (error #'(lambda (e) + (format *error-output* (compatfmt "~@~%") + name e)))) + (let ((*verbose-out* (make-broadcast-stream)) + (system (find-system (string-downcase name) nil))) + (when system + (require-system system :verbose nil) + t)))) + +#+(or abcl clisp clozure cmu ecl mkcl sbcl) +(let ((x (and #+clisp (find-symbol* '#:*module-provider-functions* :custom)))) + (when x + (eval `(pushnew 'module-provide-asdf + #+abcl sys::*module-provider-functions* + #+clisp ,x + #+clozure ccl:*module-provider-functions* + #+(or cmu ecl) ext:*module-provider-functions* + #+mkcl mk-ext:*module-provider-functions* + #+sbcl sb-ext:*module-provider-functions*)))) + + +;;;; ------------------------------------------------------------------------- +;;;; Cleanups after hot-upgrade. +;;;; Things to do in case we're upgrading from a previous version of ASDF. +;;;; See https://bugs.launchpad.net/asdf/+bug/485687 +;;;; + +;;; If a previous version of ASDF failed to read some configuration, try again. +(when *ignored-configuration-form* + (clear-configuration) + (setf *ignored-configuration-form* nil)) + +;;;; ----------------------------------------------------------------- +;;;; Done! +(when *load-verbose* + (asdf-message ";; ASDF, version ~a~%" (asdf-version))) + +#+mkcl +(progn + (defvar *loading-asdf-bundle* nil) + (unless *loading-asdf-bundle* + (let ((*central-registry* + (cons (translate-logical-pathname #P"CONTRIB:asdf-bundle;") *central-registry*)) + (*loading-asdf-bundle* t)) + (clear-system :asdf-bundle) ;; we hope to force a reload. + (multiple-value-bind (result bundling-error) + (ignore-errors (asdf:oos 'asdf:load-op :asdf-bundle)) + (unless result + (format *error-output* + "~&;;; ASDF: Failed to load package 'asdf-bundle'!~%;;; ASDF: Reason is: ~A.~%" + bundling-error)))))) + +#+allegro +(eval-when (:compile-toplevel :execute) + (when (boundp 'excl:*warn-on-nested-reader-conditionals*) + (setf excl:*warn-on-nested-reader-conditionals* *acl-warn-save*))) + +(pushnew :asdf *features*) +(pushnew :asdf2 *features*) + +(provide :asdf) + +;;; Local Variables: +;;; mode: lisp +;;; End: diff --git a/sbcl/.quicklisp/client-info.sexp b/sbcl/.quicklisp/client-info.sexp new file mode 100644 index 0000000..15ea093 --- /dev/null +++ b/sbcl/.quicklisp/client-info.sexp @@ -0,0 +1,28 @@ +(:version "2020-01-04" + :client-info-format "1" + + :subscription-url + "http://beta.quicklisp.org/client/quicklisp.sexp" + :canonical-client-info-url + "http://beta.quicklisp.org/client/2020-01-04/client-info.sexp" + + :client-tar + (:url "http://beta.quicklisp.org/client/2020-01-04/quicklisp.tar" + :size 256000 + :md5 "1ac647d2f5735d9fa57d88f982e07970" + :sha256 + "3d8d0a8f0aee3a510c343bb3bcf668e5d327e992412ce98634c7d24c9881b9b8") + + :setup + (:url "http://beta.quicklisp.org/client/2015-09-24/setup.lisp" + :size 5054 + :md5 "bc380ac2e8296a67caba954802998bd4" + :sha256 + "2a7fbb8dbda22bb932ad12898f2ad3ebf1e770a4d0992cf4a2debe5739e35801") + + :asdf + (:url "http://beta.quicklisp.org/asdf/2.26/asdf.lisp" + :size 198729 + :md5 "6c2702561f5b8f02acd40d08c5429c96" + :sha256 + "def6bac208961aedf7e9593c3106adb3474241370f84ad1438a5f1d6632d4a7f")) diff --git a/sbcl/.quicklisp/dists/quicklisp/archives/alexandria-20191227-git.tgz b/sbcl/.quicklisp/dists/quicklisp/archives/alexandria-20191227-git.tgz new file mode 100644 index 0000000000000000000000000000000000000000..ae3278c34d1fb97e633c04e8aa318394076b608d GIT binary patch literal 53842 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 literal 0 HcmV?d00001 diff --git a/sbcl/.quicklisp/dists/quicklisp/archives/slime-v2.24.tgz b/sbcl/.quicklisp/dists/quicklisp/archives/slime-v2.24.tgz new file mode 100644 index 0000000000000000000000000000000000000000..b0a2c9f722afdcd7aef3e57f69795da5d34e685f GIT binary patch literal 813432 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

!@3}u7Q`5Y|E59Cr?`E&K- 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

RygNYZK0WiDb(t zyA-yo$@+CQd*iN#YMyO=*;1i7wf3((nHV{_S4=G5cDp8LugtGm|MOq`EKt|4FT4^V zCYHvPr*~UONo@BE%{OcxgU>d8bZ!q2*?Wjnz3=U}&b;IK6KbvmXX&MgZRd1ed|xlz z{b|M#t=w6vA&K=*-yaE&Il-6wc;%X!GNskrg=gGUWZA`Z-;uY*({@Bvo znGuuM+Zd#jJngibnSaH)S$8(NY0eVVuga>Q?qQQ<`|=CJy8MIxUUnZikmV!ub3#nz z2Cri^IR(a2oA)>GKk4=LSKiXyE%SFd+ooS_hJ%=P(gp~>l$xsEkPM+-l_nzrm%^RkJ1X0Ei8`17Alq`qd~-W?k_ zbo6ieHY5`SbnC{!GK z*Dx_)&gs5D*PtnECk-~08ET&upX2-b!s?gF*$1Abh!?P4mm;Cof17 zn9&ieE|;-)MctHhlbS=7<2RQCX6P-nxaFbpw?%^I;n%lqs{9Ny-#^;N$`YJay6jj_ zw#2$;JG{=Ec9{3AYj(!=e~w!&Zq_}`QsC73LUEo@)3nG_O4~ed9o>;CmlC{v#@y_A zYZNl`cU#?Q^|vYCw^Sy_NALD7S@+;&f#rn)?-kQuBqez4SpAV9rgxgq*3&0n zhnieF$=lSF@py0g_2XVw#JMM1&e&GVVaOJ5-)|st$2YIj;Yam^=%|2Sc121rBlS(a zShq|!__8HLpg3qA>#p|oX>~2j5=wMG>s|0I*IAwvo_ATv{`17p%P;CAKPEi>@L?L; zZ0qi)-Q|J3cVsiV{zb_yRXul?-ROGyc8+(lExt)cN_$L~YDMc!xOGZs)6z9B^Rg^g z-xr?0EkWn_@`wA<-TJTWl3e06Z4<-Ja7EQK|F3cwhW%N4Ecv#_&4YfcH-)cWE9SD{ zaz?1w6mk7qNfMIBCdgF3ZF=J5k&$Ir-2^&U_b=O{m+Whf7;jn;{^HBgWb)2HjxjS~s-HkU@7yKx@dO$>!TJ08tX5;jL9J<{7EWF2wd=!w=+U2ij)D<@;0cm7Gedh!0# zWxE(69&hd3dEPwJtIhY%UDp@OV$%b}*Ig5zdwNl>dwfu_&*O_z?P@qrOjfY_na+IH zDp<6ztkicl*%hhxPdygBU+2uX z-G==ze|@<8zt4wnw%7A~U&jKt>5B>Lbl5dbCo@1Kl8YJGPo+& z&0eSW;CaD`sLL<5in*^AYuxj8XNk@xi;jKA;?~^DmMpe2?mMz&?T?fnd$NL#dI?>6 zaVTS3NwC^$gL7|n1Re7l=Os1pFfV+{I!9V0N_?(bqsV9Txhqc2>{r!b|1WcEt>DZJ zi#939`CT}9{NjgdXLU#aZ`_lFnY*N|<>pEMES#-*L@qJ)XQa%dV+UD8j$XSRBj3PY zEW4;9^6e_Ms)&DYCO|QXMbiD$IaYhbkRNF z-Aw<$RiVDSqDpixv+wym;oJJZwg+qec%Y%Sgu=P-*BU~S~=r&>E3;=TvKA&^{N7X zE}!PW$5JqVVMwiL8+UW|=~b-FS4z#prhiR3TJAbQBH29) zkJ#^fe?M;rv$faJlZrE2*4{n3&wk2ofm;*pzg=p*`zLU!WBa-1>*x8Z^@x=HdL^1t zVpm)E>G0;u$DKu&ubC_`@xjaD_Y6$j-X&LV{uKS;z_~Ciy}sZ|aEpxUIj7!x6{6O~ z4m*yzt#10IvLROK$y_xCr|mkH%S~j~sdi@WZ9AbGo5;KU;*yz?Pv3rhxjOwZ!@mRN zMHgceil0{4$UR#iWH86q=dWPCi{pxxL0K77tKeLmyzP3b!l`5U^pnEZ7) z#2EMrPDFIveA3^{-!9m`K}S<)%0Nta256(|P$p#71K~ zrSO&ZpF8$+?>YRi^1PsNx2|DE=V7zyay2pCRkxEx_LexmS$Rh6w6yS~S4qDv&pfMp zk!_|yaYAm)y*eJsB(Ri|Mx}d$4XK-SN;3HFy-I=-bpVHi@r;HZ@oz5 z-EP}WS6#~vxcfU?&^n{&wBYmEOWJ!@ed$*o z(Z9BRvK4lFS0BuF5O#CmUbFqhk9UXUKD^8lNS(UwO6O_4a>uIPh?ayEn^+B>i7f2f zuxHP~7VBiCquv)zR{xZJpLMCLx?EK44AaheGxS^C7_-`^PJVgu^xZ4Vo0hIy{grRZ zftJwF@I~LuBqa8;bst&BA=U9bmSKv=uey`vLgoRgS({?_MQ<}dJ@M9;cD9?0+=Yu> zs<)edo1UM#cWv=`zpl3zzo>`0*Pp06UL~ydtHj_Zp9AlMS?P>1-)nchtdLDf%ImALh?4yf|=DzCF*V^53VgE8Y8(6U4V4vfQ(SNy7Tl zy@!*I&1PP3K)FA!{uP5)_1%N7)LM?l>pr_%wsWFhO;1K*;O9A0E=-=#o3STM;O&Ld zP0Rl0?>%k}?#~xW=S$34qB5!OT6||}a=y9k(~~E;@;BX?@$;otf=#c- zgEe8E&wToiziS9E%qsi%R+5>Exvc*FCL6!Trv2uV=G2GG^Rqj8EbKKm-^xANFW%UB zYkhyeZ_XMA^JP14Dn2?o&nxE8@8GaY^?M%d`#sH|`K>tbQT{@8vvk=@0&JNFPA@NB zYVN*aee?2_VVs5hZxmR(V;whKv)mmQ@_xg1Nh9-uwPvfYPCN2uz2lSq%O5(9J?b!y zNOJx-@3`=^%Aa%6L%O`awHDj|%G!Tns_&7D`>dC(N?7-Anu50)8?(yC*!D+{*_AZE z$6j8NAoHYeS;4Ud-G35Jrj*ZXN%`rTa`d=&SAd_2q~!U#JIZ>qPMGWd`*3#A#Mi}K zcYGd7)IZFeD3*0-iC3Wz<0uH@0{QYAH`YyUNh_P-H*yw85At^Ai+j^%UO1D6_9 z7W`iPb^E+%U$eqc0n=wkbKDIh1q)mfADym?QuuPegZUhfl9x;4qiwQpp7ouWd|>r9 z{ZB3)Lg$5JS(d%Gif_%F`>p7b9@+jb8oy+J_u6^yadfoCD zscY}qR9VV>dEhlm=FXnOzYR}2X-BM8IJx8jgM7cm&N7}2HGA?7yvmK?HJ={k&2Pwd zdsnnvjtH;7&$o^oU17JsPCpPBFnM`GSx>HD^*6z^V>xE*bM<)knX*jUkaIXcM*pRk3m;hd|9^1RFS}`>>zm|zmu~rP`RE|{{+7JHsNA9A^vojp z*OMLWtLJ~*oZ*n?&Es4zTtzxY4af5qhDHIx0S?zQS_3My>pZ?<9zJJ4-%Y|VbH zMd^)U`$E@Wd%Gu6;gZ*;Ox^12-8>8{OeRh0(E1wfV!F6VIQU`4zBk=YxAflo+zh=r z-E5(`WO!o--#xFn2li$CUHo>pq{ZE@JRNfHMOo@xue|)35uUo^zu%SCHEJc{Z9j$1 zT)CjQBd**!>gk4myJqZqSz3QNMl9#wQ3e^IN72ufMI~&OFW`xN|D^J;KzetrRe+Px z%gd^dB)8QxpL$XJD$aHB z$393f91kkBsNR0#kpGj|%458YXRLp)vPdR1yjVQ<{-VJ9uf3J-eff9XbYXUV}#dLp6?q@6i1_KtO`)%bvSG5$(UDx&gQ|QUmOQEe=8HGES z*j&vmkeH%uAG>9NYr6Yf3x(pp!bL}qC~oZR`=I{8W76v*x08N&h_6mxwRhdj>AOz` z>@1z}a!>02w&rDuUa>W@GM>K7H`d(C4?4T?kDU8wwVSyijUMk3f7FOrHJ%bEU{9X( zsphM`reU+eWdYHfdVhyjSeW zyuR5wVxy|$1BYcv0!!}N?|fC&k}K$Ae!18uwLL$qTKT#8PYr4BdB;x9Fr911cQsu2 z^XZ>WI}d-F-NYglJLtu*{u!L4QHQioAO)fkbL`D z&E}?!9jxt2Jlv1AmDnCRG|A9(T?xOlVp2XvaJODqcq<|{Ivbzd)-w#?5bwOVJ=0N2MJqp%tQ9yUiZL; zgK??!j;DDWw5~AwxcO$zk;{vH^v;<#r8$wWac!wY@WIC+qPY zj`xaxbFncTGmu#O=OmAS*v{S6rk8d%m(RI)re>*N)6&)Z?;4$&*z@6WBU|1lRhI?D zL5t+pPJgoN$%f>H#ZP4lciU85Il$Atxb=`vmGSNHAlIHVwV!7$-Y%>x-+5rY<&XT7 zfFHA#Or7ywc6~kD?pu3b<@wB6bD+`a<6_xIJs~P5-%2nnFrUEY^xJoWy;9NE2CdvH z7piIu-3l@io4#HNIc@gIyG^xxOVkck>|V?&JdH8I$zH+nKAYq zcv!b?-aOyKZ;D_4Vp`O2Jtpadi*e1{si_|R@fPe=V$xG=-mkZvzW21MfGqEa4b~mY zrnEV1cj)KHzWT*u$uBOx`o>=d9sEw0gxxOmL>??oQ50j|muNq2O3#$_=Xg0?zpXwq_3yroFYX^Z$-p=B zgN;Ycw)ooe8@s>H%zv+wrrWzFF~-ieZBdx$JifO*O)usjNW5JAa+9BJtKPvA4^}Lk z`HlCH-S6h>FQ5BQm$;X)&|3Y$hA;uIFXaZz_xq1b?lk0(|6u*~?Xu7>e0^%y;(T7r z7B60==pmAmxm^5}wZn!(G28C{4->t=Q)S`n_x8=#UU$V5Md_aG*~!wb9d(bZ@oPta z=S?4zH_P_!h`6F!w|ULBS(l&9Fn@RbL2_!XO|D(0U%Ttdrx$)dZn$MF6?tT>z}C|h zojKF5Y*t<)x6n!A{s#W^k~{kXV-n5eR&D5dKJnm}nZMpYSkYs#J^!ImLDbq^ZS?YK_khH??NufFL~KiG6`={?har^7FVnAQbe-tgpf ze4EYb{(ti>oqcM*b$!aDzv|zvP1VZP{-D>EciV2!^gWKtIjncFX_sFNlXkjy*?n$F zikOJzbkS$k2koDPKZ&lge6{eBj-kw>ZS7Mul3w1uyf?P)qk`-9)ei!yTpg3yoX^em zU3+@-nJZ@IKTo`nSCv4E7wg}^n7qWg~?mQ3r8&AnB6@N-M9U0O7wjsB;o6l(Q45b`MBWcC2_tA zF`nOsFL=AnE5d&*E@BdT=+k^JAw=j(_6vK-f9^?J9{6zP2Q5~9!)#LHkUT{{C8=pf zkukgK-fi)3`^6XVXf3h|dDhLPW-#evR7FLvoi6NU~^_Jv6i z``0hO?p&+%*6UB{lAPW)LDdO2cI_(4U$(UU^ODrdTebLv-`hUcyi|TAM&j~^(!Eg) zVh7pzb#|)mZ2$20s?b9B(A{f#1E=MsJgHO!B%e8#Xm<61)kAGc1Ut;xw{!lequ{IY9~#x&m+ z=kMdVbfQZ2mA{*M`KC)Rn(u7$Zr>s@Epy7;%SKmT^`7&+aXw<#kEA1v8WNlWGh|n? ze=f~^cJacOip;hB8fQfx)?bW$l(9j&=IVHPvO7eZWE==OP>6Up( zyFzHnwN`bGx68kTdFL&t?VPPGB5LNDFs+20)4{=3v6;-L5ougGOr9TQ&KZk=+k{(;EqpPUcP{^tj2OkQ<)Rph}( zp+6?)xxX=LN^eZ|n{TztTQPKzTE*GxUH12cTlagH{=IqXwd~dF*4i61*IamFaAWu8 z1qwRvv&@>Wo}DajdiIRs+MkYMpzB*n|uJ6zWvg;q@`>fKg{XRMXuGV>C8&hYGQ(5(B-lhWR|H~mbKY`bfD z?KOATjc0q_{hZ;V9Nu$!X8!ckZ0DQra;33F&z{Bk{Kz!Bt{Htb-?&R#?lABDTEz4J zd#Sz8m$(AG-(Sk#2kSQLOsJexZECrGS6Y-+&%}%8mDAnU%HR67_Qmysg0bv{*ZWrF zyO+Pdqknt*+}P7?$CjtG#pGFEOZDTKX!3HQ_6oHp=T1z2y=Y?fn)x9vyY{YAJnAR^ ztYGPfZQ;`2*Uwq1vTgE&Cn*t=zs$>;CABs)prSr#8E>YD`d+v9JEAU~`gnX&f%~ht zkJm1|QI0{RKa62ZOO8RuF5f$h$uBZyKb$uquBGDsoU^8lBGW`R z%(@Y}wEW@KThDfJ9a`}tYW?L@hF2{Iv=bFY=2|~cm^ty$oTjMV*$*?^*`)C8Skz$sQd8rxygfIi_dz;3nu++-B%d@|M#!c`VXIfG>^YK-Tv!- z{r&$w{rej)TmSK?Isd+&pH{Em|MOY+ueX2K@B2A**Z=bp4Z3p{PWg4!|90B1b;~dB zzV|==*ZGu8mFn3uszawOt!k-Xo&LexYWx0yS?h%{b1T~>8- zjmQ5FDne&j_rL3_SdsF8(P+` z{<27B+k=!%MJ4ENu9Rpi=(?&e1R?qg5RIn3J3)nhFywCWmf+qy!V z(6!rsIdtuFTr@MUBCatx_U}J_H&B*+4At)TkY;#ox;00 z(og)hfhk)tUAiW*cV{2R&a|Z8MK;HLYSzwsmnQjj=7+|EpF{f>y)$m8y%x*+ z_ixzUZP7LTB?q3bYppSU@NECiHD*74v6$aL)IQ&xW z`@x90Iw$le1Z&Q0UdHNu?YDiJ?4DKE-j{6j>c3uA=V6i;aECSg*x@AUPe*4= z>s+=dT#%(nvgyeJbLZtod0It!8^pKYG&%T*Gi|cjlK2;qFYhcma{nLiGVW>THeLH7 zXIr(*{n6^=S69|nmY>Ml@@$K<){2`stS?ek%u94__CMNVup-j+apBIJYt-h~*A*8V z^F2NKTw!U&cCDSaCLY?oZ?;=8yO;X8N4!=F4dpop>lk^XwG9$`M9Uf$cNi+_74AE` zlzZcW2jb1fobQCHx3O;zH80r_k?<+;VBYlJvt7lzH;7OFwYJ0aor2$4K?`PQc^`Y8 zX?atoRf(MS|5z3yLo_IAs3zmuzhF6{VRwC%iBTJ#gJ$Q*gt&T_I5h zXBlp;%@TXS>vFXua7o|}1M3fSuf-cAuX}U(bXH|!v+Il2U5sB?zPQMR^z6_7$0qx$ zc(cu6jt!Ge&GwU$-XkZLpw=aH?e3DhTwAAQ?v6>i_4}xA>FvPm1HR!re`eFsSg& zo4dg(M4hK|!SyxM47UIIBAB*u`qOz^MN>QT#rAaZZ>@;lUKRaw&Y5-3P3`N>sOA5= z>{xT~{*m+g^82^wK1(|Pup@QN({EcAF0U-+Hb2NQk3n+X?#_M|kLoCvx8+MzG&t;6 znViiw5GkM2JXOm(e}|y?bN%)H^FOTT^YGuYB|E(8klBpCmD8f8%N~q-mD+LHRAbiC zR;Sq&>B41cRjdym@jjEwyp`KNiSHZl-KUNRquXXFZ1TLGAphW;kNnF!r~THqR6Vx6 zwEIKl)vKQ_Cb2FrI(vAXZGjO>{-fvm@h`9CKQFf0_PRH;Snp+7_}i=|%a~PPeNHbg zQ(hz8-6%VIgH%^3vZ>@a{B)`BS8AX05Q)P@N?Z zHRnU1)D(gH2Uh#e6N{*eV$v<1@?qCbN1bIW7Yk3G@cD#5vzVCM`Rq-hAMTjHs#Z}J znVD7Fc$#HH=CZ1#%yTk!&r{4|sL~b>6g9dtNz!%t&DX|P@)%sK+Ba~-tnsmb!#FAA z)Vfc5UkD4Ho4TX9C@q62G3Xc5l7{PU^beO{%;|1cM|FRd>@BApZ<;kPJ9j`X# z++6-WNBnL%OF-;#=g;$$uW9?ei<6Z&hPQf)YC_CogQ~eZN^!Y6*+U!m}G@?mJKzAhRT5@$5UFc13RYHc1mH){ovT_sCUK ziZ}Xsijv%qpI7$23(Qe!?~;8{)xrDzPke|+&HmXPK65f2@+LGmF~rWCyZFB#kI1gw zGP{J1&tLf>SEwj{%A-GeEGvsW)|bR@5elEb{$1JfARlw#ON|F@*Icvq*?DV?`|hZM z(7n@b4fPH^T=7n2vA<%|nZgyGeF)|JZPO6w~=*@S_`q23={m*NM%=;O&4V76N4omCL-)Uf+ z^TV+5){I;+QIk(f8tHQ8i|@@YimSBC6+E5BSUzp1b*9D1T+`Wy4X?YrTIk7seos-+ z^B2YUa?e}a-r5(lQ0f8KI*!^YKkjL_6x_9$mo@LGBYRBkqIF#%|G1(V?%czFV4KU8Yu;_|SiYPs|46op1W4 zgnmsD&WXBtCG^ULCmEHJ(K%d8N~e4=jQSQY^(AFq-5DG9i9GylCqr2$uGQ;(dNA-} z>|s$IGpF^pY(ItEGMV?>%&@e1yCS2mzTM$(E4VkO6jb-srSG!lVl!|G-x&GMqSdT- z?xxI{-_ISMHtXhJ^=q@Wjl3r`rs@*_&r}ME3ehki?(&1k=> ze>-m$7W^~G^$LfwHG!Ab#$J5Qu%`9pDFt=^tyi|rXi-zx?-+CF${8n?#{WG1 z81Y3V-B;|9 zyPJ49{(Ia{*SGOE47(3-vhbZP&siX1|AOx-U+L}(&-441?^<0C3mmA4;PSbI@w>4T`t{tuY2-phIyBpuEcY9UT{0}jQhM-lG&V$_nQKw zWvY&MUS*lYxsyri1^=!Ig}+uE<~PjZSk^U5X(!X%*v z`=A9o^X$&%TQ5>Pl=`J%7;L>9chB&qHbm;Eu+hR2ZWhwd`Al!8P2 zP6zI-%8OZKcS(*(oL! z`MW({6@2Qp-RH>7nq!^vJ6}?XyVqj2_u3hclB?~D4gDprRpq}hdfe_jd3}Pb?B|7c zYxJVmUX@Ba{i%PuK~G}%In(&bqW500wmmaxKP`AG_phm>S)1YZ%e&<(8>giGQ8YIH zDN#5pUH$9VozD4FI(jqCcz#K`_A2(VY)nG8bKkl=V^{Xg9BV(V|FghA;6bCY{%a0i zQNweBbz(OA!@pKd-luK;{D{k{%1h=ujOScFyZorWt#;$@PX{EWUwp}`m|Og1SE08= z=~oZg8C8F;+>I2TQMYgQ4n_I4N6SuL-l}ksP4ifsa*y#$vkyYG`x?zz-$Z=Zh8N?n@MTw6aTG z-zL+UPs1%^M#1LH`eo^BH-w4Ia=fORE_vhev=bFuxVR6O%&&@F%YWfPqFLjG6MqY$ z)OsRi8rbIXT(z4uHEdPI{dpg(=?{XzA)K-PEXsbhV6FT9%**jYun8jjndjK*Z*7CbR3+FSXyaVs)PKoZ{y;*%=!|!dXQ;ZXC2#+I4$Ugn*Z6iFD4nyykuXX1oYE za9h>)`-@rC5p(j*xm#Xszg{5`E`0A(=W8qW_{1nt*||O!A5N5d=e6*}s;QQHEZZ+` zKl*_+ZH~OwYSEd*uUe`GaQ`!=8EdlU{8*zvsr+#Z#_oN)$E|+Mii1m(IPc#NPHy{zuEVx#v=n*0Wrk9IU@)qUlEYPh2}P#f-~K zcWm0~+?rCs#OQ7OyUwPEdq?@6J;5{AcgLi?eZo0iOwn`F!gBW~6XY*{{db{k_QJh! zhO#Q=EwZ8V*RP-5BF7e*{-dNkwfMj37p>dgmtwyz++VnR@65BIwZ*%=LXKwi$Azta~i`!>)?r- zr?+@!HNJbm^JRa~TMiwjh#gz{4Q0QnPjFD*m~{82%DV7?O_h%;cC7qrDY~HR!|Lc$ zs`Wm%Q#Rg-+t{XlD`b||(&}8fn})`*hTA>2G3<`#I`3R$xn)a$#nWl4^z?2=)-03T zP^_?$XZCzgxxGj3OsHA5kL|*1w^~xlutI`%uk4XNbza*`>(_h?U)7+)JxKq^Ym$q6^ zL$M^U(1+ZGSNEHU5RU#P%4AFGgAdd`8lDLs$m zW@i0%pQcy%@6+`CJ0w)E=CJ)vS%1`~beY*9lbEI;#-9lcevfL_T4q?@us^)!b-9)D zbgPE0uRd=$J9(B@vTeD(zx+(Zuao~ez3fjuRsVZrsp?+mO@6;0hAi`YJUM4~_GZOL z@kYDT{D1l0N_jV-)c88P-;9%dIV;=VCmfmB6Oit?)&IH9xB5-xX2FlS9^Vt5sd?A! zzHZjq#dqZ8e@icTmfBQjwf>xVOJ4ECZN^MS7oX3xx37GcY}&Aw!N#=2|0&MW1Uc#RM{WB4sLWR4-iSe$jw! z@qvVT>6G4yJiU$6UX+%3gucp)TDxa5=l+J7?SiE*TVDPwJDH#L+w!xiS@dMC4UH>! z?h5bd75&hdVzaT-Lzr{+%Vf?d^^H?kFS~j*Y(Yvi*J6p{f^^y6SO0T=`1$YWkNUeM zhW}Cv-&KA5FL&qvquIaX*?-i>*MIyP{$KvzeS6OT{!`mk)v6kK7g)VNwYn_K-(l@f zF+IhHKbR{0Uw>cC=@wV>`=-Dui=L&K!TPVOc<1RyT@cz9!lxqe)O_C_7Z2mTcLXI$ z(;9BZ<(?Nm8)BRH_1Oj)?b1czCeGhX#VXdb6)3p$8Y|>zNcW!D-qTZI#vp1QtHHnN zxQOEYaErj{GyGEC?muvPXQt`iB^FK_SKsh|a85-*Wc{tHd>x%)MxVY!>$}@?rzvl0 zUL<;8!H)fvU%Ubzbk08Lex74q590}|Ih~wyD}*k1B%OFKXY82bZf|_3E!g6$!kx&| zU&{)8ry1Oddm#S2{pY=7+1Y-_HgxdrXcc_edGqjxXpj6&>lmX?x+K0Us-01=xnQ#C z{`#q*XN)FVd!KDgDY9LrmV7|}_-2RO2CG}vv~{NYXq=W^TwUNJq;ET`ocmW`v$aLX z8*xFG;y3pmGW`A-zvplLw0CVBp0YmH`_7hX; zO^=Qcw$7H&e2cu!V?7_N-flP;bx6(cO1p7K9Jh3i)Xp{e3+xj&F`p@Ln7nc3x+g7X z(pOG->5?|#K&e*Bi;&Aw=`8>9EJDi*XDZqIS*MnN^3&kjvG0)OzGT}o5;l?BPXFpN z)r?6x^xdUa&)n?T8k3Egto^f|#P7{@=&;s0zHG)b?iMTNJM85F26}thcYLb7ba16% z;Gq|rwPKmS^YR@N-Cx|y|AEEAQ02$@1|jLdJ4y%E9%=C_%iFx^w7-Y6@WieIn-bWk zN5*~m|G@IJKxai&-D z5zd?Q_lJi{`Qc6L1m5|StUP-qrvF2Vv`*xX9oMA96OO+Sym=+OJwsPZ&G-7W{Xfr! z|BsUUyh^Ug`T8asxm)+WPH?RJ-?HeR^16o^JWu6APQ;Yun}7afp4DOB_UE#GVE*!_ z^=q$8sN*}UAG1RLiP{wZ*6X2B?FMbHS6#jwe<;hCEy7^AK}c7)=U)Czi&@jIeAr+Suuki+pwBb^3k<&<)Y_`olzUL z@6I`%|KQ8P9i3|SaxVm*DNX*uSR3%m*m=G(pY8+k-zGJt^FBY?sM>qs_`xac3@3}v z=A8_w@i_W_L)P-kYyZ{Eab35d_lS^IY^d_Ylf7auE2@K%cHaH{I^SLXEAO{Oe^>N# z7*DjcnJcLMNS0w&&9bEZ*RQU%RPS2xwz*o^M>^Gmvm?&NGJDcofk#!!d!AJQ-d@3Cw3NA-EqUe8jWdirOG)BbD)h8@># zIJY#czpB~Ry>b6X-(L07MY#>18iV6ZxE~l*?YFtX;%f3+u=UCJlUtteX`6h}q`~C~ z-{G4AfA2L&={W{);6M zaaU&VZ8PcfZjjs=$sA#^5=g+Q{xd^Zvb=3TK%fa|IL#tdM$iu*H%iaL2t@%tBRVA8lklo}af>t!ui>f%24H zyVFhIU7grnSJ-u7`>S40y`3hRjv9*{eI=a^8ay?aZZ%!y_$sL>liCiueU;w(esbl1 z-A|8I?xpf?nU~2IvbVZVYfo&>5B8#)E2ebltuAFDsoKT~3nx!0WL#4(bhTr|wbKZ}ZmAu6h@B?tJ+*^Pt;)bC;Lje14Fj+VNn@d1rmD zRa=7oN=-F9dW&n?CA+UV+=-%9p^snoxEn^O9lDXqF7Fe&EhMAk^YgU=n&M9wdLFnP z{gZhnYGRNzXWZ{oS`Lm^-Yu;?v;T*ft>L#ienShUgIjLxl!&|Qd{O3N80Ves%?q0r z{$V_&pQrn*af;EE_yCO$J6Noa%y+b3cvx84;U(8O0}~eQf@ASJ%v8HIwbWOOeg2>4 zxc=ah_;;emSYyn@r*nIp3OjFMED{l_pndhrr8&1$H2gNZi0_H|sl&fAXWHhhliO}^ zbhu~yR%$TZTEX?+UuMnm-Rvh%SGu*htX>%yws1iTLqQ+!&NH3yJHkKw_TX|4n!IlM zf`-G#Gc(p^T+P0_*s!B0O)cWCh@Nibv4o(D7nbzJOD1^=F_m#M_Y})=CMDSad3XQx zr|Pc{-^=g&{Xz3zna$5{hflKqJ#BAS^XsAgm*4#L^*=sT|NVWk{r}4Uzx(&VI4p9SY)e;zFdhn})3Zy4(5VrwjX;lV@z=bYcw1bz0!05)~Pg z?fK8byD>>5p;OJWLtw_184Dj26tAAtp5Sq~{jTUv#oj9u0?L^e=w_|s)QCu2?OxLM zVgFwD*_kZ|6XI_LwBB3n#TCl<;pB>$an|M=mR`SVZU5IN?Xz~x%}s3P9yV8JGQFLn zdUnyu>tV+hwcQG6GT2i0^3@*YuvcqW)-cSQ`nIZ!rSdG7TjmeH?Q65A-|v4AHobq5 z%H)KH4{PIBOi7$v`;T8CLic!@n2nK9s{$9J*j&fo9uc8E-Dw<*^*m0stZ&v_j4b<~ zzwmtT^5qp10xZ-@U!FBstGW68%U6!Z!OpKfdM{#N&f53t)!Q|t{)zVw7V|FMF)J)# zsZF}rs-LS=kGx!PUx&B*$5YhR@zNA?;k4-a%0)?BVqsx^OWO{Z2mDPc(osFSC-J~mE%wHCN4}=5ms|dB zo7^XN=9t0eO}kfJPi+)mtnmKjq(6)Dvrc`GSka!mUXO+E&%(Wd74+GVOf=%!K~wp z3;W6=O!sQ8R8ZNtG~w0lTQTAdPOIfYyIIp+zjlaZv|QL_^59tOk{#Z2tA728xREo&y!JN_;8-8tE$o6-^k2!i-ZEttnGuie_`TEyKWqZ0Ad*3UzePzqKWw*k` z>DG^!m=h;lO}rjfcV^D!GTOq|H{+{eqWzwoS60oK$I)E*@?DA$>qSR_L!Z8D@&5WA z$7=2IcBjAP>>no&N_`6xn6djG`x)DN!WK#n-y0Weeco-*`IM{SBd3jn!Pe((;#_Sf z8ZRgBW~lpf&G2H+owSqe^7=Igzc0D{>SWW|A7N)p*{A)Pw>NX=K9yBd#m}BvUFONX z@zAw^d(Tg?Ha9d|iJiVJ?=S3M9LCab+46Kf-?J@Rud}LNTCHY( zz|bXE@{eJ|?3UuQPF3$;eccr2^CLREs^Y-fvEthO($jGIxcx0_czddflBJE>2u6}4uHJE|)x_`hGud#Ax@ znRQwFmU{1bObgvOrZ?>_alCZftG3Qu*i(`!0!agOe*SS|zDX+$Q-t$Zq%5q?I$}60HvL{<*a7 z<}R5lgB+ zh@Jdecg$;gA$Nr84Q+uex$s1{cU@0yE9-Aw3G}u&lr$q#<@1k-%#A6_b9<{6R0=FS z>ejO{+c5IvL|qlP>s(WotnoNG-@n0D;os#0-#=(`eObck-fJmfxJX9bn9;f*>dJ{t z^Etv<`_A;-NWG%G{m_?RP}h!VHWo1kxZr}&-AugCuHU>x$~|3@V@dVN4hiFb}L`)dHqq)iYZ!_ zFMQd%0LI088gJz2{(G4I{r1Iz2j>D3rZ@%L*GFtN+oAG8mQDP>ZJ9{@^);tvdtX?S z(9s{_s&e7`jg`F?wgTW`L!nkhWld*+XG%+J&L7$Rr* zD?ivHEm7FBO0FS2%|6Ja-Yb08+N&((? zZYz#G{^;@Q*s+W4PnqI7F1|ed=3vFP37@8H>h*}cbto_U`%M3hE900W&lEPET%OnV zpeyU$>?Q$EJ)g_2oAdVxJh}Ga)#Z0Hp0yOTMT$@7)Xv$(oUJI^%dz0@tH*!B^;TXy z_O_F6N8SCIhPUU~Y*rD`{N1T>)8S*>dx?WzE~wYuT{W4RXS=`3#d6=I6%xz>{CD}B zE;|1EW_NyXTV?URtb5xQoqvA&r_JxVXU@&ou2p$g)S9`}%%|+fKn zbG_`Iz~x51XQp3dxgN`LdHq&_J@O`8M{GXLOqe+@QcF_2TjajJ^G%!hvP;f?OxZ+s zM*E*Wdrsj?(eAKt-kHL@Hm8?`I`_FsX(cM(zOcYr>p|SrAPJMGhzn+aET!LjaxCmU zd5lZqc7l1D?8OUiO6FU4WnO=OV%x%-oVAv{$qk0_atdPlN~XGb-ae}umd8HfQBl@= z+#kZek2R{ivinVP{yDxCsrgUmEtl`RI(b@;Pk2Gk?5nd^MP|HRx%%WT6O+!JS67!- zZ(O%--3CYhg9ohFGhA6`tT;7Azu8ORVoj*-*B>V?6yJ+2O@AfI^K08}r~Wl(yME=o zNj7MAPFyIjB%1u+^sdzE=?s~o(l<`7T0g(pwuUua^!C)PCq1tR$xOMvT)m(F%Z+B? zTe=OWw%qRaHah*%l9`>)dZI_j=fV~5VpOH(f^-D>y$#cC!mo(pz2HmJ)TU#PLRS1&93+Lyg)7q1>=*pcB|wJ%oV z&h(t3;^kAT?}u%0i~Ts*HBymau=Ji{+}Ub{D=2(({|BHS5N~NlmKL z)?S~WY-M`KMAnM^W{3RqV0U%lJBIgXJ+ZN1IeOyZ9LeVsYWn9aFjt=Cap&2b*s!Wj zJ>I`JHr{>u)kw7L>Gz<^fliN&7mKIoe~nXSo|EYoX#QX=*L2ftjxD?@!oQ#VTEgdX z^TdXm4lyOaQfyAuW!vWOxmzk+TPeF~-KTYH`1eQ!ML*&>5zVkXPp$6#+ufPFPCC_J zDOG>|_UJZltxVNRb_T|MLgJG;^ls&ruQp$@E2{MUfzAKo8y@EKZ`sl!u#fGEy^5E~ zj`Y4$mA&V7`El-FX|?=ki1Y=y+tR^1@8z^4@8dlB-|<3u!}bZEk8Z72+1vL-ZK|yC zYqN*FGrm|g#foMfZx8r+WVN$Yd4#*nqP6B%9p;oYK2xZir<=1_alOeh4~6A|C$mpp z6M2(1VaXA>*VPjnebW^3J6Z2Hox6DRcjb=HF$YtHj&0rhG}2Cjed~Eeo969dwdb;| zG_Oqb*!=Rm^mX(|@?ymDOI^s7$TyD|6NlHBX zw;y(S#{cc(-``o2JsKop*x2`}PZH#kF1~2ot5P0dd^h;RgS)d8bC+IFl)IHCb4tk2 z!g0%)Pp_R`S+X`R-oakyp2lQgCcj3}RDGh{TRuI-+HKuS{5=dli!74*)%qj(W@@fu z{?}hIW>wM6d)PB>7}uBC3g&wjBvYJ1c)j^NZN`!Cy=zS;Bkl>RU|zvfKJjE#cb z%aXF4_Fq=p_+DCEYhS9|nm%Vpv7Y7gXZKh|cu-|Dmb8=FC0V{Z02nf@9md0fzx;%M-SK`j>rxZL`*>{)h9g_& z2TYRv9#%77`q?_xAKqWQSEc^8SbVfHK&v3^;QKrBz3*Nv6^p(5R^~*;^r}0XxQ|A! zC~-(Ae~>Hq;`wRb2(KpIV|pL&b8TjkGD|RwbeAmZ*|qZep*vnX`M+Fi`{VoMhSlA} zY`e<^IM>ftPImEj>}#KO%pqm=o3K+N8@3zQebCsXe1Fx;_ZvU_-n&(%GAmU3P5Vye z9qW&_%xZPMJz;tHmblOF92L_R{yP!9F=)8}qy60tjmekSiEYi(EK+&GX^}4O^V9sC zmxJ)B3z|ZY|1CXv-t6uy+ohZn{-ii6n4ey@dkJ?$-n_M5?13TE1SGeM&hjgfV_&Lt z!$9p#WD%c&&YS4D#!3yhPo)`}OF7n9Tulz?a(q-|$7mU2$okXFh;@Q1tjX=HemIVhi7SGh&G&Q(`LsmsrpQ)q!2b1L8 zDfYLz;*uh7wzLHvO8Z*98QBS2SR>Xy#iMk z%@lfftUx}h;pJ?DpG7`jlcLMG!;BsTe{X&ufANjulnH-#w}0q;+WKzN?_(Z*$2=lm zo8LEaC~CXUcd7c=-@uZusWC=6Ocw33;ac+xZyZ}K63oDJG}pVQF=yWNm$$i7AKcen ze(ELnau*eIFHWC@7mh!=lu&;+G-gxh<2CD=nI2jRzPj(Xboc)gv#eHo?axrqD4sI2 zdPeElU$0r`{Cc?TS=jrP#d~JnQut%p^rqA0;Rcg!1+s3_4Q73lkXf*MSCqg0;cB)O z-gXyfblx-n^?1^{2|OEaSn%sUuM~{T=bZfL=&Q(05hYXk?g{)=^@;lYFKEu5_3Js< z%)Se6{CHYI;Nty)qXV{YwYA#o`{Ua@q6d;%8YAjYp5S&wTY~S5A1r%H9Qxf}GBCE}Oi6 z=_b6(b78m1oaZ^w>P`pVuF$>gS#X*+L+9_yCJoD^3GKN8Z&&7Xmv>i9`THjD&`(9< zYjtbZNxpy5uKuu~n0r#0u5euS6V~PP1zA%y80tP5+!e9TuZw1~e^F_{J<*z<$FBId z7EkF1uA+rTyUo8`6U%GQkNw^E?S$#{q7Xri>`Q09uC3a6?RODtoNvO9Cu;S5!M`p2 z&!5oE5w_LGxsc?8InC3pU9^XDy}SUOi1N>K&$&E+sJ+{nTIaE-&F8;f(CPG0_49n(5F z_FMaporccma}Kz3+j~rNZJs+NZo``;Go$UF-H3KO&7QQ_NoCc}#sx}O=AT{_d4Jly z_J@V-%WeMe+&jt0{K~Pz)?&Wz?$$^qrJVTCx##;DP952kC$`0gdv#iHTsGOP`_1dv zhAjyzmtN+%BL5(yj(PU9uyq$sybRjyw5W5P^PHFB3=xghN;wyId{6$m(A)0ShrjJj zZFU(i4xfpb8{pd9llp4^*0210Y3pWLKXIw<*EgD1ro^)@UiRnP3of=x#3!g0zd!Kf z+3jx$>#kqwX>ZT{ZP;SPvvHsGO#j?;o8_C%oZEf9?WxJ~x3ki3@M^G_J9|7|mMVDK zJfX5RVawrazv6#BTMQITW-m?6jM2GmzA_@}Z(O|yGgr;qV_%*v6yN8&a9Nub+oVtF zt~#1ui}Mt!x15Oy**@dt;jOQQnRoWTpKZA#QR1ITW^1fh(?RunmaW3&2LxI6yiZ_w z_^xwnTjt(~7lHNmLMODU_I6KCc;&L{+uv$0%Qx-G{wr?I61%oE!1J6y@}gxi&sX$# z_N`fTAW-d;iKo`7Unh5d{gG()I(%Kr4vFFicZ7@8CbV7jTJ=@p^E818ZL5zkCYX6| zoU0+QWy2?brLaSj+B>K8wuv8aHa3fqzMfF@d1{HnX-oFsTkKx^KB&J)@q@kG2T3X2 zhbF>hYV~z0DW-?nHqTsh^P94}{lQRvv6ZRPEEe$!{vrKbdYW0hwUbCCOzISexxOwn~ zU1r6~>uv!qZcQ3-S7+{6eS*b3!DRNink#bmtg^!|nE2?L?G+LK{4aS*o&T3T%c_(U zeyM4^%-X$e_KKhT>ysA9yqzW}XQ20N$pgPdg+~_dp27asbIYFPsV3`YIrpj-hkILo zdU4P3%iI`a-qig|J70atNLhG{E10dvq&>eE*-DmD!l0M5eoV6!Hk4zx0ZgTbOnZ1Y0D{A0@(t(#S3cpT2$6$U6b75zMy+jjPkh^eNWZJrgk?^ zoVlaZsBDFdXI5Flhg%o6eOa0Rnq{@7j{(aMiP^FzVjNGF|ICQV_^6Qj%J$HC$;>^6 zr@ZC~x!9X9(JOjdMrgY4e2?Zu+386e7N2Ibe>Ed(qLcgn$@k~Bn0zl>v~Yrn@FL&AS<}LP3B|fRa$h3ZYk7FBeDxF$Ii>UY zALn}3uw>iM;8?kO_U8nRRc}&l#6Mj6_fqskKl{QgZT`?N)d}0v)Mpr3@30GVPfFO+ z*}p7YW_?A|TXXe$F~4uVzp&!yMD=@zBCZ^Itdc8M{!o^$>b7^gm4IiYZBOs&s#-@s zD-mhmxOLC+=XEPq9OC8d9JyqetYt+Q2q(i^0~I}vpe)Hfsy~4T&6c${ytd|r!P~#tVl2a{^XML z-IkcdSCT5l0?oO%4L^#gm1n z?P%lA?;E~{&v)3jhgFO7QPbtT@I1cqRfo?VS6Q-y`@-`CE-xp^u+!ljC9n5rN9_1; zQg23<@juzT4zmv}JU(yQ(mz_pvPDC-*N{_ms&?DfgdD@3-5lyS}7OP|kM$bFOnwj$g*bWjg|Ieic1;jwkWg z%GtG-CqKH@xn@qG)~d{eEsKS9b94g_Sd=Y zbEf7u9#`39+Gj0isQPOxmM2ul{l@Qr+=KqxFR$$iS^js;S=|Cp>4iQkL=+tjcP%~e z;ZgSXNNZJF)kDi$v!!lw+{?eX&-l=iprw`Z=NGA{8x*j#Zi{N({_xqgm_F4_-j8NG zwv@8}QZbj2{2cIe%a5hvr4RPyys-4mwpTsNICoa&HkJ)5B%^i2Qj?BcG}L#DZYfMj z4`!Y@?}tRwD&MP(Kc~DAx+`BOX_l^bq9RL!VT(#+o~8DecK>soy&@c3+5(P^8~rB_?mCCzHM z(7kv5@+%P^D!oPITVou*ylC3pFBcu&uwX;MM=j>&1&g{~9U;pFd_oaIS%Q6angjSZe$aLh@A6$Mic7sdT z!Rtpitb09w+u5k{tGhFGbCj6=f0Q~@^~Zg}ue-9_4W+6oTJG(ZEANsZNxxf8JlNS?=I5w_$Y*drP5>z0ya9)*6b!hUR-Rrg=FiB9n$oyF? zQg+TVwu^ZT`|LirzF%T-@o~vwe`hU^*&Vv+G5$Hr^u%S1)YFWDLMO}WeO%)IcG?m5 zQxmxC8-;&!UtqUVvXKj{Kd7AA`bwaB!>53RYl@3Sv`uKK+y8@G5Ae+@X z*^V=k+qS*Vj*w7@m$Trm)O6*VXmC)@b(nv+R7I?pIH9b^X-~5h57wF|HI241XM5DHam@R=OIn5 z`yB!CXQryJumAt%*c8pQOJ{r9g{gI&?=TbcR^NPd#@W`~$n&%L z?yOv$dN*(P7G3X@F6}_?!_v&h_kR6UW#Ta-`hn%_S2~QYYG0p}f0=ox>gOcm3hsk* zzJ-6<<8IBIVHJ3BV*Bi;a{VWIfAt82FbdDmnsvJ9^Tl@p!pC3oe%q5R-mo?&Q-Jl9 zK_8>d*VNLxTV~We`T6qo{rS_@``!D)DDjrZA$~S5>y~WGO|H3>IkWG5FP(kd;QB$q z{^Bn-#fy563BC3%*!ZSAh$VNjdG5)uFH<2?B*>PlZM`q%H* z`kP*IV?o+Y?T5eAJ5JA)Y1*T;{#In|3e#c+U%8cu=CM2<_di{3RU*`>TR+ufEZtcB!q7~DLJ<(^* zDYo$o-PyAGa7nkJsiM-th=WV{r(Zw2D|XR2w@c5N_LSTz3q7~@%#(-e7or>r{Mx@| zR<5ir=y=5SZ`S(AW3@>W<}X@gm$hx8f4kaE%Oqaes0cakBfiUJMY?aR+PcL5o5?87 z8>G`2@;Y-q*B4id19s0QmhPz+p8e$J!wIK-UdGK4?l_TAV!M5fsa~~(l9)+OGe^11 zBh^^L=q|G>soIO*cTF@bzFBi&!p!pC)eMa@J+cyRiPcD*&;Oz;e*C(@j^M(Wq-SoI zuRhBEx-0gj`zgQLNrJamPZe9L+F>@5A=!!VS6!FglHYAJ{Y$A=*2?{C`JA`w^ZXeT)?= z&RBew$3o%SR`1_@8ZHOQ+(MTdF{jUEJ21;+tM00AjRqQAAEFLNUE6lFu5ry}>3qA- zYv<;$<+lDgmDg0sf67Pioj&&t@v|FdW`0z+m^F7QYu>N7COvhVS2?sUPSM+|8v9>%kQQ1S|nAiz{1ruji1lLQP zXK`DcGi9#fmFZuft((7l$v25I`!l}zOIzQW?l|TUv_$k_XGAJ@->eUNY_89KXgxVx zKT2q3u~vqE#Ks)O6+F8&JKWa?l}KLXZQ%dtka;_?;k3o>rPq9yO@GBDteUtk#Ukd_ z&Dr_ZM_fe?SlId+DG0b2uZ;a=_T|kkRiTB;Po>`8XZ+|{&D1Z-iH=RRYp(N0+8FHY z=naf(dg*>9z(+DoD7p7qh}~OyINrRjX`NcITkLS@dj@rXf6Lf^zGcntj$h(o4^yg~p>`{D z#>`{ekGj;`FgP_Y`FyX6fxYH*#mB%?pF}?1Ftn|EaP&6AAJgTT3g;esWxTBa^y|sb zmxi;LK3-?8__ z;V!?i#A)YS-jxDY6Q%MCxfk$q=Bcnq91Cu}Z+h2q%b|pvNa-W3c2T;$D+H&ToI14B zq3VQh_rCyf?-Q+jH{Va-(3yX3vdx6+m!}K6eGDpGw>qMC#|Fr4zM1s1+Dzj#8@z>eD>SlfJ!wr_Ihy7}1o}Cn+-*t7Z>zkWXxwQ{j#P~gL z^XX!$sh_p?%01hw7sZ!fTHW?OQ*g(DY-Yn%=38E#{xE;jA)`5WmK1nwvHK~@zLDp% zMbPn+L5bdSMU&#zJW?x}aw2xtQ$cq{llAQXlwywcGkIkQ-8=XC#tMHyzDpA)hN$28 zQg!jFIfGuzx=ot9H>mj4NaZ&LIlr2klJW2fue)8HS^vd{m7<$8lEmftm_B40q`s16 z?&*!%utDYJO8J2n0(Z8^uXz8L^?uXy6E3;J>Ub$+{=A%YSgWm+``COe> zRp4?_Iy zbGE8m)V9mjCyJR8*$qyvIAPQITgQF^_q2uAzb<<`Y0JfVoB=blSr^~v)lIs|cDcJN z3bftW@oJjx+~8&1yQ1{+j_2LKeuqWUy5YGt-{GsP7*ywe`Z70r_H9S~;Jp=@ueb4T z)}6$0bVK^9Sm|}kIC*LwKk!(2*rU}gam~3Xjo7p6q&+vqh?k9ntlZ{qQqw?3ft&XsUsnJHOQf3H*hBDm3;p}=D9`kuIi?V|sTVmKUoz8<~O zFqM;eM(#GlmYsDxK@T+!nBM(1$MEr-Ru0AoQ{Jste(_7C;3r4doO3pO0>yFnCDO7F zxH&JrbW^msj-N;M+)2GaDwOZ^<^&W0-Mu z&CIYT=Fan%p1Bm$ELa>fnd3;;*CGk#O#u zD~XxkRN*wot1I&@eIK=035Td&WZ~0&VEgi%bJYtuk50S53G!9vICo@vEqL8zIAQ6I zDTkesN@f|V>mT#-EAq1R<+S^5(eY65%r@nOz=LA{W>nr4D^6j1`$vrTFZXuNp2shb zuW2aRzlxpn>w&fRlCO8joP3#{?{g@7g~!gz6Rlfsu)8h&t8QlTGwFhD*Mt=}yf57E z%ltlhvUk(0saqfOJ^k--Dtxnk24ioP^$DB9RS*6qwdPN_!G7v-hi+c$`mWAA6TAJ> z&sJ{M%wP3&6JyK?{Yh;8MTOUl_8hribbGEApQxoV$IIvH`yC9mvhFk3ER{GCI3XyH ze|6|3KU0q6D~Tz)SI#&0Ejp)g#o%Pwv+ZK@mqxvQ@bqO;?$o{lolnwQdHYvtP3g40 zC%ymgv>E!`4)%ZE?Y=YXli0EE_xW?B3@xqpsdOEC{_57Zd6`v&1UB%=wv{i^bx06=?pS@p{+Uw~M~*S^C%Ikn!ZxcQ*Qe(BwY& zplCk(&V47{ZNu-Ih}u7WXCZLspvCr%+;s^Bna|%d6?5y&jt!5!lJGm%?17N&M*nLZ z%G%q_>RNk^`6et{Rx5OUN%)f=%i<3UiJr4NHv8ZXbCHkcQ}5Z%Ie$2zL7^n0Qoy%-+m3~e zL0?7rjeR#%|NHRk%ai`~adx#I*`}D9#P_r3pQ!LwxVURu>F@p5xHx*dx1XQ4{{GF% znV)6tc1n1=m;2u-6@T$(P5YyJjT`RGz7?ULdEdjj-F14vy9w+0T%PMrcVy;yETQ%> zD0y~+dxUpVY;cL{o6X9GE3TbjnXNNLpvgYjR`Zux$`bn&S zg`}D%Nu4Zrdu|lO`G3v|{`&s~%k2Inzi=y@uzmNP-)lG&lW(TY+%9xE!dg4=irMdD zcavPZ6@RFeu+BQ^fJ$X>Dz7| zR!GpeyIHuHSB(D*-$u2()vI~8`dged4&J$TiGFZ1Ys;e8JIuSMh4U`(tNfkNv+Mc& zA1^z1x9sRLyAjsD?{!U=@@4Z2hpc7$mj(abb}}MId4Fl7a`4jc*D4Fjnb*Gk_TXJw zI}r^o7`?6qw37JjL3S{grdc96%p&$p6F zyJRE+as<}|&nBUyOQU;eEJ4o~VYW>tc zcVd=f^;$9UXH_>9Cn){dzQ<9czg8xw-t=98n$Lkr%XX~vUmEi8pC6~Q$Gf**ws=20 zydy<1d>os!G(R$CR~Ul?Zx9~0wP_QEAfWb3SD zHby;~MN1F;_By@w`P-vrKI?=x7RxNp{6F>hO4e67GcwKG5AV|c^5V_aiB(@*{y$&& z@4ok+w>Mu4Z%;ZcZg2Ph;g_xTlQudrJas&Da>ZvZj@-d(35@m zRAsf!wW$g-S3hXabzI%JXI(@56_Y1Fy#Bu}nBuDzSEwoAWuTiTo_fnM_{qnwF%l>2 zWNQ%kg571OsNLaH9=V6Sst1ZfyO` zRa3mQeg6#8=X&SbWzMLz$eC<2nziWWa&{M{wVfu>E-{VXyF4vk-<#;nmiTX(^&3^& z-yZV~Wovg<)J-({(^tEsMe zyQ3rY%jZ3_HA{0o?TXr*_W5&A(8f};q;XAVsCkO$WLCl_BYS9 z(~L2O*RFq^v^YaX;e=_7v(wR)p|kf)U;FG;>CKqftDD)b9Q%DQIwJXH*5=4p!F)nV z{rXC#u1;p3rLn&Hp}xw# zC+&Qvek>5-TYsWA<+y}+R%x6wi}S_Y=eu4n$b6t5x9y`s{h9CQu6BCw+`q9Xs(0Zg z{@yPS-}?l-w-0lb6#T34<@5&Cg^mhx90lH0^WUtH7QX+-Tll5@xe}>~n=I`9)E;^I z(u(K!H@lyc4!CfgHyoUjWR0l)jYCUeJ`+Yb=f~z&XP@N0h7y~ZI5L&ZJ8#& zULCjL*x!yhuOF|-{q^CX^qIf(wDX-8 z?{4dxx0CnTcMf~k&)WNxeMRT|XA`u1cww7U|FlJ^9a_mJPN^^RUbuCiZd<+5!|x>86P%rWOSYS^@TexL9>ft>Ou85rG$Fh zOZQeqJALL&;@&^=p?LQk-mPyk6Cy7!_sQEo?|tNS@mDi@r1q_U_v_*@RpC1)OY4d} z%`z^9M(layl>OTIsO!=R6KBdSexmu&Wa78v&Af-#EdAKg9aGO=EnaA7vs(OfBHxrH zcN-&Oc;YkUyh7diAK9*Y-CHn&`SGpTzbyu#ZMFs4yE`3>R*JA1ueM%g&s3fpeb;}* zDV_`O4)`zEUGv|1=G#5DSvBX{S>9BR>YmV5TDmmpdEETg;GG`AGILTA*6n8hzwGR< zi%Q$BnBnQ^x;k0c)5mL$ z++y!>PrKt5m!34SaC+L+WnSwx%{x~)+c|FUDsi`)SHbv8)ns9oSnGf2am)zG|D*Uw7^L%D3>2Mor=p&jN=xfv={!7_Jt2yYz&( zaIw_M$d*fsgMF@D{Uoc<>2Ukw_n3o~%+IrmPo~_Mp;h(%n_|GaUmg!$EbZK2xPyCj zw8h;^(=MpETvai>W6k9CVU0z}ZM zJvylCUe*13dg2NE_o4ND$gfMo)S*=$#MP$FSZU6GpbL#Tn-7F6C4t57^D!9VB zQ=pn}9w+lGrb54Cg*7$-tM*IPHlLZK=e=o``PZaty;HW#`eefQZRR1SZweVbQ?5PP zF8buFCP!q}%iX3NJFGJ}nVMD~_o|{+YWdJ|gk` zY$xp-Z)NJ{*~rE6wA z-+W=+>6~-CURS1yvnQs$ZdA+8|C7A&?W&#LbzAek?&AnQ>AB{xnD8F1_&|&P*UH@c zXU-6EzvgM|n!fvv@5!k*CyPB4_&({;?hUOR6Nf5+v$~rlIPII_8b*7MM?)DD<&5M_wQ@eDroae8zg6=)JZ`(^keeX9$*Cy5}?wRX% zah=D)GY8K+*75OS{WnusU07|!SH6F`;X<)94_=hFKT|&|jpIqym*0`w1uC=eDmp!X z9@?t0+Pn3|^J)LhrVC^mEtFSn_k0n=^ZvNzeUslhx1YWZ-ThYPjD*|z;-hRff`zjf zwr_iGxS7{>uqVg?AM+$-baG} z)86eWPiStvv!b<;ySw)H(x!c)OgqnI8-<_x-f!>tM(vrgPl2pS=Or7dN3~O||32UL zIb(D2$F*vgd~z-1>krf@R=nMpdRT<>`*nSDri8Y%;PY)!6LO~uSkGpCR(vL2MSN+s zzVL^%k84@43)i2JF}=1`{=3if56|vyPrWAa$ExUIixF?!CRd*1+!6e}&nm0iqec9#eDLK+wqOaecD($W}O4xCJ?zSyImt|bu zx6SPJ^0zBWe?J%7HhJqA{k`SAZ_B)9QsZ~vRTBd+ap!Y3w`oqCyS zTWkKpm61m}(R;I=pS;ME54&$HnZIr8wN3n8g404e4Q}k*?zAZBE3uN3s;*}9!LzYW8Sz` z&x5z5)OMBAujOi|b5*|8+$f!JMZ!`HqcJ7y7y%ytTvA?nN$-=ku zGiCM`%nHsi?r7?&^E#K#6%;YuNUp*l!6MGSl}#t)!Ges0MW>2GFR3?J<{D-{EB-1h zbVb=>?%J2vHS&%#>~N}Jn!cem#$=6jU3jyrolM3Z+2!YZ8tj;oPhb6cxs37QqqZRD z()vGBxm(%OZ;2H*l+XU65N-cS<%OM;?NsNQZmzd5o>1zFd z$uD77wmd)CYn5>5)$M%7=e+UF*Al!o9DZ|jj(u~=k8YMa_BKmZseaq%Tg}+`xFkF-_r9!Hie8 zSHZ_=imI$#rJ1>~>Yw|AD)x)l18UTn!slF%dcHWjw3*>&R`tG&Wv>cXhi-ftp}C`D zN2B+(r^{AKo~i9^TzuJ;bz0RTU(NdT@Uxp3xgV4UPh4T@R(AXpM+eJ~+RLo=Pp>U1 z$(xoM!#dsS=8;+2oVD%@AL3ce-mQ))+R42`EA5lg?Ry9Ja_(ugnqk*sk|_L(Gs1qx zBVS*!wRZn!*_RexxRJ`QCj8fNN7BQYnc-?7E(=eu^1Qq%bh#(!=)A1?wM(~eejxgo z?UYd9tc*?Ko65Afyo_Y{4$a=9lUg*lu_Ak!=+144D}^?f2F&|4%RkcFZd-(J^xq%P zPUc^_E|I~*w)sPu@&8^<7M0qd^RJg&wffDr@TS@>ho92I3^R7SU3OX0J9AZVlE~wj z42_T0ll!8I|1A#xC9;2Cn@(%_>~xvs!d>%^HqCmgn`WrE!sy+mSLaTD&I>F1rNb#} zyylF@T;_ZI4-Y0?ymz5=W?c8KZlMXK|RHPWk`AC#pMrAFm7G2 z)I)%Q@$055O-Z{Cn2XO?u=G&R2DOh{tRA#Q9)GAi=iTnIh5p~C=WbtUn#g;5#)=c~ zFR^qrZeRCNf3Oq|f!9T%yS8adA>! z_fCad^)PntmA0&v%Kj$wuQyjdL25r^@XWp$NKCO zzZdSW`SsTEYAug~bAYt!KoAG4QPCKPm72Xu%CV#%rt9(qq5QzPN9) zz?TP)tEQByto&-RUhvb4S6RDre6IPn2)b^~Zt~;%CBAYGYi`5cxc3tlxCpE`t+>cp zWb(4?)A#>8TU~D|5aP_RE^69w=ikws9LIk7YrM37B-M8$;Gbh_#HUS0hDYR`|D9BA zS-|DK>BFraZO$c3@0Mq;_1YS2vP@c9_fB*644b>d)YT0raUik@%^_@C&aNfsTzN%)CG7lTs798Pxw>S3M zk?+es=CGa#v)*|y(Z6m>68?_us=xurLre0({1vi$tL z7uo0A8*|=MjkBp;CJ-l6V#%^w#iiu^?Yk4FHP6}l_q@9PKa0vQzrH*zDuX z^>>#$YVHod^-!Vp+25M$2aa$UA8=($PU1Vxm2yF4zRuy>Y)z`iL|!dX+gyLC-bmUP)4;)UFX649cFC49!{YUpZ1=2;Wir-X-n;kEpDShjyi?cx)#7b3 zRQxWvyGaSX1mAv++~}Y{rAlA6L(g)UJiRu8W^%pdWX)3$s~*<|yy@y;Vpz(0%{rw=J%}{*si0`4*-9_sZ zFRQEYoBw37n zS>=&z)#VuzMJEpvzvT2srFVi9^f$)a~N6&m= zn)35NY>$JNhn(NfM7x?}J6hW94M>dQy)fyn&DXsB zMX%ioWcF{Hdw%+P8O2N9Y5lXd9qkNz7_lR=wXjrH=11zu-RH#oJ~hw$zE|DWxX3>G z!Jk8)*tqUEKC5VbuUES0)$bE?^WSTgeOtY8`-7X4@9-0&`dpW8t0z~V zcvO46{dZ}p`h?yii|u0H>z401)Y<<=Y-dQ2#u`r7!>d^SB^eja{LQmwTIE*DmtSA1 zS7&GhxpO`isF8Ke(qz&%TOj7x^!u^x`Y$i1^X@g7uz2sQK;Go)(^n@iwMmX$#}svC z%`5eX0!KcF99_}%aoIzyv?D@`LZ3}2)7hr|DDl;lFG9kTFEQTS)W7k{ zIy*rusp|X<_Fc=TG6^NsF|22)Pk$ryV>nfxwlNjtyHxWGhNaK@(a$wxbv?Z0Ynzy9hU*~=eh&%awBBE5Td?EgJ!kHdWy zzqU4w$}WCc&ARdNFNc>$3fRIk_PWZMDzhif`n)QV!6&>!IKF~AcFpI`h!;f{-|tcS zc=xW)zNC;8nGP|lZ{bCpG_rQfyEX*uhjAN>1FxGp{V%4Pl9;GpN`50mD8iC=9m z!FWNv=8%!RcIylNc!AU{udXyM=HM~AHaSJ%BV*;c*3dOCl=fsBvIHJ+?r+Lk|W|EvR3-8;>>mj3&!|HJ=TJeR~lJO2%F zXR?jHN9=YwQ<~xGetauuWZuHp&#skSI&=D$?X!(@9W?HrjZ!(TbX)t7-UQxB0un2Z zd-DW%*r`28Id$-eK<0cAkC__-Htw-?$)9ds@S5eH)G_l@Qb~Ki7&d;muzc%$JFkkC zM~83oyp>uiV>!*GZ0@gyv%4-npQN+K=&Zm>{iCK%kLsRI>DUl<`S{zC?5EACSG%{) zyW(n@y}ah<^3=Jl+^YMFntc;;zkO?f^g z6aO;ZJF@8h6(7IeqULw}OO~xHYM!5A#vge8(}KNMea!M+ul{i<@SgdR@F+D0>s^fn zcU6>)R2dq?T9vzxf1dW0YxmQaYHLNd>zaxS$DUD)b6vmlnZm<^6BaN0lxI_9d*VQ2 z*XNz{ws%i`#CkGrhC=LhQ3mO?PJ3jet#eO&(>tWm8#`sv^mq1WBLZ)<{?#^Yd0F;Y zbk6STzxM0SJ_t_KxaD@6i!KED7u;FU@I~SHi+yu@W=&j?*!)7no&VXo z+#?5;ZJK&cu8y`D|Cs`Xt8XjbI*dMv^X9HPIaxm5rt0&Tr`)EMU*0@<<0FyGd6Q+b=&XG1od+^CG9L5uYwQXW*>Ju$ zX^MRghrsgVeKXJA|J$q}C6rOC!K|}IW=T(kxrqMMfM~um(Z+tl+v|dlHnXk{XJV0G za{7^WyVSAg96g>DJPQ@YTh^BxFAWV4InFRw+fi|G&$p$|boSXFYCoIGe)W)hO`)Kj z-SuR(`Dd@cOlLfLmW%gs_^j&PA1uuxY@WP&$GH7MeL`^eO!i&T?;OorujE`Y`6yCz z?X1L){X4|^1-6Mh4b2Xl(4*!V?R6NgUsYvoFbDOcSjnXoY-@H_Ra#M zO>b*^cCLTdd-3JPX)_;87y9kEYeBESR~W~fe4($3d>LOZPHnV~{pRvg_I`;?%9Q1@ zzRqrvTNUp%bZ^`FMNukOFX#8VJ*&*B9!(7HVQkdfm6Q8e>xSk{y#n<`>!aD%Uzz&x zNPbtql%Up=M{kK8v)|mh{=H76>$Tz9SC zV)gQV0ska*HLE8_cQMS2b;zuKuOOBby+6P1P)cJ-zTie?Nj|1_t0#tHJj)(GbYIb} z@_WaNbEoIdoVZ;<$>$wM--X={$6Lxm&sASsyJ!;=%d^}0-0@<^iriNG@_WRzC-#Gk ziq3jdV?K84Uxr;B5}NCEJlA(jefQ*t?$TAe*1!9!ul?%(b=#*>tNrzl&u85HaYDb+ ztUG1F4*S%;Y`>Rg`TQ_*cFw>`cl`wzxdB5 zk~KW?V76@%uZV)nyZztSMDO6Ne3KF^ysDaA({fMD;kSF@loy3L@GYv|d;Qze%K=A> z7tZ@Joj=d&4p*6>P))sz_Y&Ku3)V4(%LyF&@jw0j{ol7O)|CWW{NGjo+xd!vwR3}; z^OPFi6zheWC!U$PzM2s7=1qp*6&9(KXay-ZW~G_7(ewYVEnOWQZtmcD^30xe6XD4$ zuj(SVW?hXsAG}X+U)ai9-kVlG*xy(5eoIdCghxVE6T{yhE8Dd8LXW(SQ-fgNSLwJm zmlL}K++Hs{=ssuN>!fuOnc3}G>~`O%A)-zDT$xF)UM?9nUmE}-CZ+pD`XAOBso zE}SoD(QC8E8NAch$1Jkt>FRJ#it%yw4gbH}m&v*HqDxF$$?3}(aqBAX=B{70Wu;nM zsYGt;pOB|k&aFX@N~ix>^y`YYO!76akh6(hQ>Sj|QTH#=T;~3F$9l!9Pj}jVjdedI z)xT$NW7XwN(lf=`%TsLmkDV@5GzwO^GBLw{?l!?)pO!gI%D66dqfPkv*<6FWTi#Yb zj4E8UGxuzL^y8lIRWZ^owG)JjFW>(4YTJ!-6{n4D-J+9!ER^8Tx<1RPH*VJD?rdS+ z0}00~cDwr+@Ob7$J(XMV<*r=jtuO48w`raH(b04Mljva$8x z<Iud? zv+Jr?-R6D#YZ(_5o2F-W<(zr*ian~EH)NjYyLoc9R{Y9`_fNm>cHlMf?+o6*MdjO< zR-vf*7pI6dy=fD;!4a+J7Iymmw*xYtt_$`E`xaTYF8+AmO7N%Y)8GwHH5cctSRZ~p zFgRY3_ukP$i_WF_f-g74C#;=0cb|cwR?Vst4CY){>tl%%V5#X^QQ+ z>000JsqVijlk42dzEtP_v$eu%+M+8KUKNx+^jUY0cEwKV`}zhKC32k(ILoh`^5w7Z z(d|?EJ_v7|q}#2>x7vHr>yobmmlJ~5SXuvhc=Y^oue07Z z-@lyqy8oa?@X?aLPahmTZIJt!l~1a}F7U&p%mvp|ub*LN3*&ejAJ-og!2cGQ@j-n`wC;X%x4?nf%?yHuTc9&zg4n5I#!D=1?d zrrIkpd!}9Zw8=^Hbl*qhRkMULt`59j{PD${7w-!qtU8zLR+Ox5EEQXPYO`TbXke?0 z8G4i*Qd?D{P!;B z!EBYrS7mNnK7ClZUin>@;`OleXAivFSQAMz<<|H0Pvy|B!n^q{0`(b@< z?$g(L*|%zgwnkr?x%q75wr5W@kLV?s1$=8Z6Am+Fmbn?Zc20ZQ7vU0HzS`^au6}J= z`(tZ$Oh=9|+ws?Wr8nWh zrkPXfPTT3JYbQ*}WVGY!U+SMw$^Xi$fAgosn?lK;>X6qrxOY%eq3|7#_y=hu^Afs=cF&$xleQ%pKVHiw~>gg z^iPG^KPA_OmQHM(%kipQC@%ehyYPV@->VYaoH_)hjgPdkYrNYgBQ^Jmyjb+lc`7z?6EH&bj72Y@1HE1(R9Q*rz+Rv<~4Y!`ZZ&rQ7 z-@IOT_guEfx2N;G{jaO+?e!^{&T7chWWyRM(eZrVr_TIl9-ExT4!32|x5XCf9Qi!| zRG~zLbcWsRq;6@Yp0iu5H8}rQvHkOvc$s0-#@69-&@fBR#;L{XqDk$f^_xD1c3c$P zvC{W>Vob)~UPtEoxHN8uxR5r-4|chGj@#^>-t&6f%xoX|NU6Qo_Sqhu_FQ;*a`d;= z*H`P$tLa;)`!1x64E{6s=ev8-oso9iWuiX@=H5BHul$m&*^Aok zE2poWai>4H`u4}n?Eki!>)tM@&bjtoWwYCnv|u57W8J2OZ|3Z?v9q)J=h#y?ck}1T z;`(m>*58*d>&uw`W!2s@$6u$i&RMX!o+)^%eYAYzf?LHq@AS=yO8;4KFC*4Nx6`-K z{@$}`o8;ac5K^4+dg=;}v-6a6OU|A3Ufa6WvMhaPS>^2Ny-{&%T_>-dx-WT^+To5j z%O5`A)n*@JR$Co_M1-5-+PK=OixpYn7-LH_-SrP^f)tBUB|CNZ9 zTg`dDUVqlZ=2;Q5lv%W+jm=NX6p6p|f0$=>W7^kVrTZ%%_`A>FJg?}WO@ivX?}{Ja z9ax&P&iW23%X#MhKRexS`%Ir9;PyKHzpL7x=qr9r`&nM}{d?2WTd-t4mzv6|`$yOn zZk296yu-OM|99KLs{4svN>z9AmU~8KFZ$A{)HnOr+i(0kX7BdB$RhY>^Jbx*!Ug8{ z8R46|YY8Guc|8?LGQ+K~!oq7M5 zszBtf9e*25n4W!hi(Ddi-(BYC?#~71RHk^a+$vTpUSZ~~og;S8%R1Eo<8s@I!asJH!G ziEi0{EueCn*t3tUr}HLb7wlZ;OKUbtOn^yix5_sqS${O>onzF@p@ z`{=e_rm0JwCqLzO?+kjH`|R|tTywV#j0;#_^!(J{^|dU(?!%6pHGl6$+TSUjUCO%q z_8#VIrPor;_4Ica?wDF2&6WFQ(v18Ed)ofn{t)3=@YMIp4m-{Ne2+xpGM@eve|j&? zY{rSH-um)MnI_9a79~yEJlFhKqF&dAqc7_Iia)Af_qje@{C~>7_wMnvq0j%_4>SDum1ZpWoGEBH9Pd4*M6igFn{J+O#zkI-{r)xJwO)02pyf0`dkadu{zNUvYrU@s&1Qq(A(eVBd=&> z-@P{-*MoYe-|^hrI$3_|qn}$=&y6iuIxpokXL-VR%i1>K(R)j$CBk|#GXL9V=@y*%cJaxD z_g1f(TjK>X#55K&a>>@LE{l;ajNng<%+sr8k8<_S&nuWGLp(>}bn=~yjwPVMRG z8})CCq;%gDMd^1M7Jb>FC;3o2HQ(gWdBv-%V>aa1PGAW(>E~@fd+LUR;YAf2kAFXA zSTIRS-{$I6U$D{eT6IoH)N!??`aY7rFD)Y19`I!~6@Osyd--dwE0JwhPcC$J$1A?z z3o^9HJ^iP=Q)wDAgGy6_*9)^gt>)uZyh`%#`)|wfdED4#$#S6MgpOO`t-OjSqVbtAug&98(DUqiSzWfoXm=xe+mr?VxlIm2zw zzq^iSWEZ@VWngKsFFbiq+4@Al`q~Pn30@25#Ga7zz7WeH$h&W;?XFOzJDwl&uZjB| zR*KjElsZA-f9^D^Pe;x_@5uk@WOvDT57Q|%j-L-BH%+vu)8yWfmc3QdNx_0cb;`1P zcce2LPcIF;_VEV0Y{L7`m-y;$9Gwzolm1*a>;8%6ldC;*ZFMWI?YOHoU07;YndJK~ zMp0Xs_uQFr>}AdA?`4a(s4>-a?c{vip*Hm;%Y1vIj2+A((@&iXzvmwI$F1treGB1G z)_BI-JNLV{4ffG1YP^FOsPhICILo=!7|!)i$?HTU@jz z%vU{X9+0K;;`*Chvp=Gy>Hp?#cVz!3b>{Qc2CJI3N~=}HGuQVmSR=k`g`a<6B(LnO zsZ-zf2kUORpIz1EdE1-$;`RtezS}n9Q#5_{FTJnXmn0$L$7A=x^rek;tCgGW)R$~6 z9L4faoLcuT?q6~CRN3B>C$DiAw1@BKUr=yc^0juZS=`gp)lXlod;VcUkJyh;zAcKm zZ+VXi&NOa1&$91&TgqOW`fsN94lR#l{m52Tw^{4|^cAn!8((La=IotSw|4ogYuYBf z3pg(aeeXXPkS=)ntLdf*={NrrDJ0(A(6+z5$ZBH#%F9bEOBd{&du)NqT|M>_>vxxx zU9s6;ID1*Y`xk4bfR3U{%M(X*+P1AdC^_v6Z-&H|wrRJ1Et=|T_5b?&*}LB|xjy{i z^grXwRVyE%p1x~OvnzK@>9{Oc%UC%3LMhj!fUTk{c8T4ec=y@CnqwLhVs`vqaOCPN z$A?YUA1d8n*6fwKp%um|s9SK?pxaAf$%Dw&i@r>ELRT^G(cM~ib;q+WoeXNb587>6 zyqJCMqOI5EKD`ksXnHkg-linJ|3~|_w1rnqwJzQMbYY_Q2X%gdx+iCHcYIFKzoypi z#&mq{;Y5q|=7B*R^O8(FC)}RiEI2V__P#^M=Ur@Nx!gW=b^hPBmzfX4ejeCvur_9e!hi?}Fpt|h{a%X_O{(d+3i>Renes2^%rur&JD)>jYs zqZMnVt{h$Y=g-foIsbMA$o|UoesDh9^}=&U=~X7HkGU??esF)zv=ilDk9{zY37g$q z{#N93T6?AXv{k#WL?u|drHdAR%XT;;(#Nn~ft7F41EvoN>g=ZWRh#nSbk13>s#aqN zENrgW7d7L*BUi|Wl(j9q{PuY8io#s4i1laZWbHb7 z6AW>|Uth-QcyH)X>D3L{$f_uRtEf5YW$L1(SB|aQyMQh5zCgkAo(=i8s!r_vus8W# zxbzPl8|~@7S3P)7s@GI3at(~l(A}$YA+%`a4iCGZDaChPEem!pvnp`D9$NqDq`IE< z3WeQ#iCcQzr>rYkzPf)6`}XR{_1`<~980~w9A7*+{llg5FFnQ|i`9c~`+pL7XZmUp zyJBb6M&ZQ*%UuuOedD*Ma+1H!gPd(^PKfi%h?P289`N9pI%%PH$%W{uto1LibnGoZ z6jv@U+go%$vnXr(w1C42Odf52RyVt@uylQ3KiMNCpQaMdrL`ZwrlAh*gDT_ionV{^OzWGwVy8)dsNORQq!|I%!udk`#Uu{ zE0>$zIyCRrO3w#Ysrj}i)%$$9JM*MgT5TxHk^Avi%JJ5NzLR~bUy7uAS5E)*bEBis zjLiGZ4s#@qX?h#m%ql@3$xYIjte_QpD*>^3DSNxv3Ar zImFL#y$gDx9KPm?FWb8*UazNARd5P2&Y$;1vZ8SL`jfxnRv*nZJi+dj{rU50nL`|# zf1aIcm&j%-{k1DDEB~~4WzU@sKSsNbHTKn($~H>g*}@m(R82*?Cy1|HX`nA`rZVZ% ze1|J7RUh+mQdl&#tg^l@&2gH2C@0N(=bWkHCHp^JF)upAe=E@c~tWK43kZll^vOTjG|tB^Murg*$OF ztb4z`NZrx>NAy#Z-1WY>cTW_konaELQom}y{&d#S4YTtJ!y7!*{Znv7(K0f=cjK#C%=T_NVVxRL*K4JH5$;C(H zLYNBLPh1n&JFz6A&bF@FR%X}9o^HR4r3TxJPdS^ZyyxOG_uQ!>Ejv|hLiU}u&LiJ$ zxJ~5y7@57O?RD$#4<6sFUj5#F&LN=M$5CymWJ7*!p0YXb{c{(N+Rt*R`my%tS<|P7 zPDbl4*`Ct*^4#^RQz;BlD#5`vwRbx2%)D`8&$b!!6F<$#WL{va<9q%-+eXQ=*Io%d zly;u8b4m1_4G*LhUN_9E+leaH8t(t7ol6WF7 zWc}B;5U+E6>bIn`TwT^h?pwE^Cn{-rRr7+$zwepIP4D7TZ1Xu`74m*lU-6&qJh#H0 zSf=eUFkRB96XmjI%Mza#x^lJbbEkwUd!NpXlJ2z14@nl5ebX#)Rv_%2*$cyK%RcxV z5dD#$9wG7P-hqE?A@7cD{9q%(lOWb#l1B4!vqt zwIV%7DdSewg;$3+?^)gJyc=`CnzbEbOZ7FH9`SvgB)n%JjtCa5tCN8&gCtTz~M>LSDsg z<>ntw9^1A(EIGL7-PGob`DJHVX1E+I;5nUI$oak{Q-#gWCz?^aWaF;OT>@v*XE=PA zlx4zS7{DE(*~7AY_JZy6%|MeIR(ifIj$>JJKaaojmsIK8NqM$T0d6ibBI~&J=f9reV{rfdYo1=Y``txhJ?|Ig z-Cg)wT)p&&X{TSU-J+hACx2vxuZ@xV>Xztwt$E4c+;tBXUb6ntn;3jy_NHGh+SZ)! zy5r|0rSeVu_{-;97HhTe>ocz}%#0|XWNXfl_;Kl@Q%27<^J|tKuNIh;=<|GU z^%}QimWA_0f*cQB+!Xn_;jZ+FU8%jEGykiKi~ki|x4!MM!nw)!ct!M|y3JxQ%MEfo zqNZcTbwqGat9vh>p>t5B>^_-d;pkJ{riMvZzu()LJ%L@ib<1kjlKXQHGXLEDH_p9c z%G6R5FPZ<`X&k%~3$GYAg=~NF{DX%{t9sz{DdPX!{GG!+-51Wj-+fL+}?vrDC5>jE=(v>Uv_3&l;V|Ir=a;FLA1Q*?3ELogu)Lihp z=DFy`SwT~F{#MdI^{yaPFX*uH6EV?;CWkcH{T5CYdeN_V$ij;?$ZEz_Gx6_5|Ca5U zc{=nykLewbyH2r-HP;HJYpI4G21Gpi zRlY0c#FTB)(ckWA<$ZqpZO3Jq_Y!#OID;Gn166v z=EMJsw_I>bN(qe)IR#?Z^MNDL9*5KEAQF z$t1qy;@SIt#i!IGUbC<~kLI1>zi_YYg({8!!)5o@cztDaIQyV;-l>&S51mob3SP!) z9xhOGGFNBS0>$RF>M{Kst3zsUm!|#8imsek^v+ULw|L_&|IeM*wKkoZn9Bc0`Lx!~ z`=SOr|9`w>X0UB`*dNnV@^u0%sT^xwEZEe0e@RZBx750OE2Jj7bBXsXcB(no>whBY z@8_-Y&GwHtjI2Jfw#<1V(Uf-Zvslgc*E&QoS+m ztWk|bxhwD2y`NuQU2ysKq*GgB!#hh&UM$tFZ=Gw@sULlHxuDFUo)vcIPuE^&PL#^q zEO(~+_WnoJJP9m!s$~{w8{*fF+_gXVH2mDHX=|c;&ReBSTu}O~ zTJLgN>UT-wass>M zHHJmzlX4d)`&=-dw%hm4=2cf$<`>whGJjEAThwvjP z(mhq>HJ@@U_Z{ji6l3`_ZPvvpyQddE{1Ddf`&#elhf`cz+@9XHaq&0%zKPZ6db8}# z%B_2DRex6Q{lvaR{Ek80+&!MMf$1mj9k~ALdg{EmsUB6z*Y`!qXIdzRsypz<^#uor ze!ZGqnR$J?*xg^V8~-hPyvFgKc+kT5No(gk$_Y47^zq(_TP+&(PyE*(?)jJe+pFf@ z0|v2~d9P%jNggo2*OhZ3Xzlan?oBb3H*3@_pXc1X!%}cc=7sO8>#{yE4hjx&25B}{ z{Hs3-#i$4{d|W7J{r`>2`whw^(`L?kpnBjDGmBe}$UUK_Q=|I#FLl3~yy`h)zkh}E z*{(`fCwIHUzrNnldw(eQu;w-<&xrM1l51uj{I4grBmaFi%N?g}760!%n{6t_7IsV} zdhODRh@J$7D3v)qt;PXogoQ5pZJ5#?aLQRLl|jD5>FgRs;~g1Cj2-%lYk6LHx--p6 zZ+Bn(`0sP&9sPT5*#9qFaOL5Y8*_gDS+@SY<`(IPxBSl?Z4lymce*@_<-5q-m+5O0 z&uA%l>fLvUR1nSJ{V8U$eP(R-%%@lH&P^4!tVk^lmzfaWpL1-s;jIO|DUQX{c~@qK zh05Lx5{_JEDAIa;h3BHY7au0~C9qCcSz4{>N%gLg&ABTe`8irL=`F;i=s7xvE2P z#-{hFidU=iYz*$W3I_N1WaWR#mGr!9d-c}Y1%j-avR})Ts@YtdzoqOKS^eFl=b&h8 z_K&A;a@S>D42xQ@__foD`)rPUD{2ESUB8<*zx0z`?G@v1@1_?o>oY&1RQ`0Iiu z!rs5Toobi* zM?Rf?`6ANk-+S&Ag*#6B8#D#?TrAj~wcL6huWrVcor@g;_#!+N^>ypdZ~j-BQuVuR z^@kdVXH%FuzodM(Wu6hM8gcY&Xs4c^sC{PQ?2ErAS{|&fi#lS(Tyx-*?`e-*$EY11 z*G{kHm~G_|?dWk*Ec5QN+^qF~E&7+Tng>~G{1IHt8e=KVxNrTP70!v8-*Wa&eShBR z)}%WD$8V}cZ_825X^xrxwA{e+@h+=5hXXnC7Qc&~rc=gRyL@(JQOSCV{;yK&UR*kt z$?#RkUT3NL`rUIsYd6nWwY@FwbA?~Yfq!lXeSHEr1>gU=Ez~oOd2K5H)~wbtj(4U1 z{WG+iKfMm(txbBlCY1S`pzHe^QB@yiDxRG>Cq=Ql@WMQ20ih`eA$5n_GoUsKKWd*`Mc7H*`BujU*azI z>1Y<5diOH(_Ey(>^MVbxZz=XjR6crN`qs6;toq8xmxVVB*qCx6*L$6+T&8L`#aZp% zJGGM29`&(X6N95K)L)x9`IqmbgXXU-C#yc0{NBp;>Mn+z{C6xO#lM#B+L;*le-_X6 zcP?AkK3bXYS$)^ETXVzWR_)`__tyQCO^QACPK=woOGi28u&;o~RktS{8Zt+hUAb}E z>;dck-M`-~=w2T3_{&y)R_WBa_hvI|#8|yx&3Sg{eowHdJlEY*ypx=AFTSXX<^3$G zGnqriC1PdX1Hqq>H$nsh^H#6!f7s@ko9k=v<;|?U_RS1CPHP9~eN}z9_MMf{^Jyi^ z-4Zm{PSX=hWj*q6>80f^ZI+BaT}`Kqm<(nx7Ok}7m}omw=a$PM?pwyc>e4sQezT70 zs;D=^Z>uD)h3}#n%=YT~KPoWXVR$%?cgAa%fTd+;cPw#8?PXtK@$3Nm%Ps@vTcrYR zcdBPEeRlB93YBwq+gMh~3u%jNXqf)dE+=N4wJk%S|vUc;23l~#vH~kR^ymV6Nacgn^x~o%n^yLPn7kl~zE=a!cD0J@rB93L3 z_t#&}TCJ(1mT8u;nD$kTi zZ8W_5YeT8Ub=%nn#YOrLW~@}IjPWHmj6;n>v$4H%N?omzwbP zozr4w9!lyxd2Q_mhV-MR9a067`O3ojHJgfFmXw;y$LpT9bo%P-({Nu{TBG#kTjRv- z--5qi@p~u~HG6O6{W*_X%;f!(WA7%kOtgGbV7{fz>3i(1A1ZQRWQ&Tty|=x04nA$6 z8~^E*@WZ-*Z+H5Z$0Cj=QT4c1!v_UMl;saKy@x^?PR-r=B$nT5+|$SN*9`mQUlWj04g zd+Vp#SN&iyk#Xb=u7*TM_<@K`b$(=bMK|KD9aqr z_eW=bP<;5xOCX+>)3u|*bKJ9l3SD3Zq zSBA=lwSU(4%e{SD`?d1G|6f<9&#(P=|IhmWD*vvh{kqO^eD!{-2`@zN{i$#3H`}~N zPT}lX7L6GD*Q@0}-`sj{u5!hupZy9YrnNiOSFb+#J#a;=^#{4C__AOnv$qycO51k! zsd}>(w5ZyI^G2`z5IuvjP4|pfbZW1We(qG`bEmfWe&hIi+jg@>N!IM5ywj_mTQQuf z;obg>Yi)7kx>?+J`d&=bW38HNl2-INr%!U5t1G8?_1U*~yV#8~@@&u7Mpe&0HtE%- zl_zb(^h2Cad;b3!@%H{U@ntfVy16qNf5hERl9DpIw_E@H_Nr}ns~udlOXh83&b?{K z7E)wA^W@C4bC}qgTMdlA3W^$;Cmpj(NYN{JKKSYOvZzG(&v+2==HKhHp_YeVER~Eb`5@`@_qD6#&fp*OeYM}k#|C(? zea!2KJHXVtyd|L0xPi6jW7}pZmiEWa>aqLX5NK8SeWIz zotkg_4w!f1#bNX3m#w8045pplS$U;mLetBGC$^kt??18F|NVhYyGr-}IMXY3^{zzG z?6AkJ8x)z!tbLe{h$OvkyP3k|zl=+&M*jUP#d1zwt$U-!XFw*S6Y|&#&~p-rSgdrO4Li(Z})~#;Lg_Z~bm>;huHEwK7XNzIy4s z{^XFq!k%unhnxj0uPpX{!_XYW(sXFMyxpI$mpLyNA8?lR>2kd6WXIf+lxDYb?yiO` zX0>N(zUsN18lRXMuXbaC^07I*gH4=%@f}6R_0E+)V*Z2SCb1DvU9AQopnaKq|2Q>(du+Qx22Zw z*TUnOuN!w=_t<+rAUAGD;=fy2UlzZ8)qMTw{E1s7nZEMg?U{OO?yJj%Yma_f=khLS z#c@Y7_CTg>o9;Z{ccuM?_4XXHG_~|;8^cHsO$reb$LvR1H+2=`I&X@ zjdQ;6z~Im<-NWQS5Olh{c;?u#Key|~THMXLiiX2x3rZ+DS|EpFQPiBsWqf;T%S zY~N?@x%3CarsORtPPPB^&+oUllv0`V=*I^RrUeiG9e(HFy7Y(U*`=PVKF3P!U^20r z@OtNr*RRXd*j+C)OtGyv>i1D>o=NAUoJkH&Chr*f`~Tk&-t&6GnFn<#b4(A+7Arb; z>{!vgC9T4$rPi|k5sUxv?A~VjJ6-$#^LjtF3mz{YzT42_(Cf2MH_A6B+3kmoxmMD5 zg=c>jv?XVo`TO{#A1{m1+(jSK9X@9s-f-DUW%a{ncU(^IWYt^|9N5b~W%Z)Uwd%Xi zpRrPp*`mOF@8Gom$4d1+N@z2zy%+voPH#rQx*2EXzTNv9_y7Kf^*g@Fdj5EKa`(e` zyZ@H||Mu?tM21ZcouBV5cp-IRnc`8GD&K#L&*#ipe%&u&wLv4h_3f|a=>^Z6^fMP& zy>nZ~yM<9|&+anksIVWi!W)#^=R7{sfPbMRNBM8`j2U4fp&~+5F|qY+Zks zUN{-nn-gp$c+$G0t8{h8k}tDQ@ocI)@c)l)q{@Mi=MzJHzxd5hEf?`w=pMcCNz1cY zZQoz4ouXSl)qi&I+I-t5?pteHH5;wOUuk1PNwZ3*`Kg z6sg(leXHSf?bhhiXPuU)?w_s{)O6&#`Sb@%JElA^yy5EoA*e!ijZIekvZZsMZ)aSq zr?>Uo>7Tqz;`5lY9va$x+T>UeB-N0*aQ9(Jl}R?SF&4sioj%5@Y`e09{jU2;t*T%D zWtVYs@~_rs+jVt|==bk2_jT?*;`w>cEhwej=TL5PhlcGQ*Uz@nO*bDgF5`P(A9i)u zf{vou0y?Wc?9C~cy1i1N{k-O{ilh@t*~$-mn%`K6$*`2^y5;*^s(5&K&hENvX)SF9 zB`@~(Cxsi#vN2fpp@(D9sxbShJdI(C{;6iR)ZYoZSMk$CLhszpdt(BN#$u6e%)D3CXV1xZO+?W5a|IA%|0!<*}x9z^W;9+zijeWT*Vsj2 zKJ6@%{ZzxiEUf5sM034z>C5%&C(gT}9-i=B!MXj1SIzu2Z?1(`|9QMxzr%a`Ot*Pn z7noM`_TRSCY(8bn=4XIy! z78LtuO)+1%?b4O$M+ChZX82_17)FPG%X=9k^L6c2 z$(v`hKM8M)7XEnOEPCHF8~bIKmp|-sIh$v@{C4(JrdMBuW*_){@5~{cpGzVPU8nFY zxK>;Eqo82YizqW;FJ_Bvd)UrqOFy>m-YIzfg`H#9cd0FFdsjPMn%Vm9W$!i{|CC+H zS#gd!oRdDb8oHR2M4M?9U$3kyln;_|_^T%`^E2O=bzRccUrIGPS<^C)2p`^HJg;)0 zq>GLN$JbrQp1RI5+r2Snq2|xE7I(j_4Z3(X$L)P{TJG-6ixTf`yS3u1gjWKel6X~k z`U9~^`u);eSMSYNX<_rSwU!ZT2v9zqdWx^Oamh5+H`~s9J9i`f%b~LD8-9_wMnWb$ zy~%6;9N=6h?Xgq&a9951sabX9`dS_RyV@rFn0D+<-d(9S*}V9IOZK0a^uD~9zIETV zSGRJmXKsDnoF@PE%;gUzDN)~!YRY@4{GOTV!Lr3z@MsNJU8u-?UlnP&>|EC(%LP0O zV@|4tuHL=GErPXM??62>`=!hi?vdfbRf2V*hcnraPrGeh9A0R5r{u3dx~{o5b3D)7 zsc9UBd=IL4_dMfso+10NgHiOp6f=XK%hNu6eD( zY$*3^b3=pVn~-O@l248Y?6rQK!>2iSN6Xo&yJoMs-t0@5YjWji)zUNpo%QC2q&`|P zN<_U>ovQm@hlRCR#n19z*3`q+&tJTJSjko6BPJmB$;#h{B_hz#gVDyFx&6?;m6skD zeE3qb;7W71`>*@=7Tadr5Hi?ski%Pd#f6GM%^hp})FvPZ=+#|M+t$ zen*v7-hth_AI@u;NyK78urm4x#T6clrCJR5~Gws*md=?`8SLU3JE#Bic>*=P< z`7UmQoyp0?21eQ$Qt<52lidy?}0 zWjy13{@U5cjpgY@g}?lLo0$uQy`D{aKVknC=gmG3d9!Uf{H8}rO*Y;1%JPG2!QA5a&CIP1>zs--+}CY&;6u3Iljy^Tw#?md zLwQ@jpSZHFwAI~v1}q)Fm23NI<&Q}nTNKkP&i2J4-u3O_8MpO6{8$h!T;cNXr`LSZ zUlXh>D*rwDkTHd+eZj7S%&kh@j#j~yzXGhRyz1?2{u?g6^80za`tg_j>gx7$e+E3A zxV7WLi)Gj31#PCwuU2f~DAk`D>rk@!PO`Dtw*x9 z?8|m|b@I1-*4I7X?G`(kw7I^zzHs{9Kgat2ggrHsS-|XIy*l8z;YxK?2~Xy)83}u3 zEG;KocD$6ZzV~iRX>)~$`YEe`wlDh~Js53Ed#l;PCFR#0%W;z(Iu z@`-E3?)zKzLpf*8smok)f4LPde6#hG{UH6jRq9^KX-l^MHBAqEkG;#d^rM$&;l?-X zRDyJ;6Jyzl5PH<%M;UjxPNp` zVAA`vb4p_P)^1H_t7~Oek2cI$_EXnI;q}EB{R4+nH!UrS3O@Gg@#6M}!ZAq_#;=`! zhi+lm{bbd_nD$fLasAx_o6MFhd%Y)TwY}1-n^iOaZ`@ZYv-Jd@q}J@UkGF)1-+q&_ zESK?su$GIXdzPAc?X05N%~Ko`Uu;x~-Ok@)w)?PtjB z&Ho=S|Gm8Y<%5dt@6#WD{?pGWcHVvKQ|`L5_&4%@w){VwA%1smStHkzn*YBSUtA}B zC0i~?@AJ+UrkUnFIZnT({JgYX>Wk`Uz5hZwANJ`cUjMV}^^QXibvIpmsuHl@_vNbh z6SyljKM`4avNM5BrmP&%`{aVD7uT^jFP?nfhiDkylP}ud7VjP=C9;A$j`bcDXJ^_voPO^PS(- z{9eLZCBJ9cLzR;=8aQj8A6%R-|Dw4nYO+(?b!OvNCHz^ZC*J?|YSpsd8S1U=XInp= zli2?=uyx7fZOcqvPx~RsD%BEK7OmeLE3$f0uJaM&-ap68CClDbZg^Z$8ok~s;P&FK_Oub?08EN9ta;OrIDZ>b$T{GsVSJ z)a>cX)QzHMCP$2y?wBqpwB?%Hn}f|;;%g2kYX-D7D_hjDRk~03UckTRXK#oet-ZMYhZJNHa8s5rY?u;tIre2I10`EPTXn{ynRZo02t7@fr% zq*t+!Yu+9i_V25c^e((`nqKso$+T1WM6m|ZT(X4F6M~t<^^-7Pdzfz zWbX2xnKmk`+p3fg9A5UgYTkz0+VaL@bDt~SzJ33$@Ba*sUb&Os+g)OqS3IqKA38tL ze`{U*xqG)JF4+F3AZFKHum7>W-Fvd4qH@<|)F+!{g!(Q2CGp~Fjr6TMHm?q!Z2elP zsP^{o&P4ve$szOW-^-0SAdVBd+ZQuIrWWx7ZA6a+ySNk5R zk(hOQ?ZI1ID*kG2J$Eix{XERvn{D#8%J{9sgV$`w7*;TCS6dKRA$GRlT5@;q^ngs( zZCm$Ux%K#_b|P0KNCy-t@`}_*S~2J%gq+OJZ!Um*96a(F1DLwXS@(`IxvSzD3a&FQMITS z+HyC|WT!|TUw^N^HiJEZ>zdD-nM=5HE}on9@yv2*IbQqBYRx|?6^lD>EST(X_wm~C z)3=y)6IZZYZvW3(|JvVd?Oc_2t3`L-fAv&!yOdQxgtlDwhr-Qo3k{9*H7x9Yw)|~N zoRPq_?NhzMg1j%2J6v8|_`rAV=e2k1ejK>@=3D|xMa{!i_t}K6 zne*bLx%}5ZDSSGqqADT&Ck_NE?pJwyEqLQ2*`Qm8K5*OGE?s-M=E)UK=KiP8y))+i zUVd;wr`q|yPj=3}Q>nOidRXy;$+tW|Fiw6pw`$Aw?Ts%O6Ao=@>sY$Vw{!E!^#?Y0 zHK&w`A4|XUs)VJUt$L#LG>`-lg?A^GSmhdxXy1<@ozFy~=XJk%Xiat4Y^CPZgVS zQ)HRFUAIF4yTtLyUoF_RsswNS3b@Lh$)#GV+>V^Jvu( zHpO+NB9gO}E?J&SJ*Hn^z2g1OAIq4ep06vuc*h|9%89x0*FT$|bDr(+X0~kOeeZv} zwii|0arzX;tfMJu+H=1?c;>u|^BV8@JerXzf9;yh{*`CjPA*BQk&KAeMftgb4rzWl~N?MawC%=DDWVidUYPzM2y}Zq_RT>#Y`)o9ALjEC-QA^+zctb?+1T2%U=}=d$9ApdP~1liRGVL0XAIG={qDiA6;VH zX0lS{%9(YX(-WtEHda&%PD^5Pix*$#BdSn!?Ob~D!~QpBddfQ{|N6Oh{Q^gpOGzwS zKAkd@{lVu~6WMe=InVvtVy`pNkFxIh7`*vCXR@D=@r#*4kM-jh>?{3U!=2h4T>Zl1 zxM|bvWx;~2G4o><^d4m@jCx~GStgvd-dQiQKV0bO+X6oM1FxsB7qwfJJKk>;o%A*2 z_;L4rI?gxtMuq9SZC=T8cS?Huej9n-P~q^6a_x)fi{@tZC@-9Ca*~&Yy~(Lzj|ac0 zzV(R~EjyuE{I_mr-t(B-ymjs2dDCZUuESm$f5z)&Yh7(bVW2ub!FG}*tMS&7X;5& zb&>U+p;N@OvU;(_;gk!3iDJ_`{7&8sJ2}ja_ezj=kde#fdun;2d!87Z28tE??u~n~yJEuO>QBmZDs2j_+LsBnZdfmS z!C-25&D%ak6Z1P3iZve-1SV!I+xbGPnbYIC>b(@y3sQLn#r22U1S5V_t_^L}VG?`p@OSN9&Qzof9`yu;2_ z*;*wEZ}bd#4rE$vv@Vd$T0Uck-4h|>4W(kut4!t{tGe72+|-ai!!don0bg%i>;>mo z^LybB^3s;wi&Q-EA}vqsSKX~E&sa^j7j_3WXa4$=IJM}5^}khH1!_;MyEZkvC;vnE z`*~G@Tk>?x4;b)VXP#|6jc4w%1Ail=uDApp^7bvweto^pox}9ar<-!K7++pqUE`MZ zQd<7>wfN>8hm;-pd`k^<7Or8@Fg%qns=og!?~*y9^Lsu{z0C6b^plWfW&bSawy!?$ zDdMKeN2mKD%Y1#kxhCaoU9u&nx?5r2$D$|M`!%X&vHsmRBX-L6jMTaPnX;eLo8{)8 zcpX|N9V;sPjxqhkgi}9mTg59IEV5g7@bkPE6*7&-Pf9PDR~z(nnkl!@`UTY<#^=iO zCx)GVZg=A3blnXKk7brI>DXw?zdXOx|52ht!PBZxu|caR@H+J^Rse3Tu4O zDwpqkhu^-6JtTBpw9{buS+4ax(r&r&tNY%*Jbd-jxuRyT`*oXjmmYP}U2Ez2+GLTy zp%o7o{C)P?uVQt3i>K`>-JteHt2w@1FGK#eMOrRkujf6}dB~ovORqkEL0Ql7WwN%j z8})S*u7sO)Yo9h=yXNr;&$4wlB=`2+lCDYfH*mP4{cuiWVMkwrcZ9(`la&2IEZxa2 zAH!$cnkxm%#HO5F*65#9G5I3rAzgLdDSU>~l96|E80PEz?#PIGHr;AtoW&JMrF|;d zA-VBYnm3ak$!+|$u9L|(B0(l)*@>5GzFXG$hAa`adhuaC%WAX7%M*L%DomYdSM)P8 zc7yfiC0Y8p3Ek%kpHEL-zNDac^0srGnM{e+57=$1b6h4$-c?JN=zPdCZ{@jnQhW9t zU(Oh6JF~myk!|}{9(@zjYpyfi`7Y@x$~Q1z%Qt49%Q;`z@x!ghcfH@Sy(@mMXumi1 zkRiv$!dkVw?mJPly6-ONNLzh%(~bydmaWwmo9q{A)aObq44v4`Y2mla>I_R>Z|mZ7 zT=R|ye=VN3H}Hc`|N7X_&0&?yCk|BY-F0#ET{fYPs42RsY^w6pYq$kl)^_)(%STAh z%-ON;{@?HW|9|@LkzV<`;=_;6?HO#f9Luh-N;%ty$yWcmKYe~ZpS^tT*Q4`(2mk+_ z_5Nde_5SKFH=oDb{(JRVf8U>1tM9+H{q}S+(`MK%> zlgKHCy-7hKyR!C1sE3%`0kjcu>_SgHOXuCI#wZ&=uOuftut^nED4`Y}8|9|(r^+oR~ zwvsZ&KJu$xTy}KGH?~hZ-8t(?!us>ilWj|z`6a9pbgnlqEZcJFQ(L@!3&?F@{cI4tyvucG%trS)dfpPP3s*W< zNc(xz`(9YfR>uG1@_)19xD|UN8b4Uqg?*lMrNaE>qCjWn%gRqgp6vJAeezem(GP=1 zr#3jBzvWZM*u7Vx`I+*~yXMFC^ex{Q6Z&=5gT}j!z8UEGr`!v+jS+vD_Eb|25D@NjlFszq|9=jGF=$ z3$EOMU0uHM*2<8&-4~1-r=I<>`{Kbs*GZnOQbxe=lb4snLjP6Oz&t~mVJZej);KQui^-{n`iITOq<~^_s3et%dlux z3V+XC;h_J&ng34op47)EuPHILmfgjqykvFvmqoLd=qzcQpu>7`rmvc}$qcJ!#`c(->?0E7+@M)#m@THcEdTfgdT&$n_+TlQ6sq2xV#ocq0N36cf8TNXZUths*4H)fSk zw7+anS&(&yu?83&{rsXXt**)2g-l*fL@3Q7fe--bdo@wY^!Fcj}AUZsXb4G|&InQhnm- zm)@GZ`A?n{C(n14q=&3Wu2(ucoe*ATdi26i>8Mn#GWlCgn#VWn6q3|F87sbluY6b4 z=@*8xm-lD9vHlZ&{12O<;`U$X7ik6mS3buWU-S2?c>MvNZ~R^=e;%*|T|Fo-`|qUY zor0$cSIhRYNgqoI37D4g?dW%tN~K12mTwB5j8@&A^**5Hc8;8JdkG(3@%~xs&e^qu zr`9%W&wLu8waj4Bl-Kzm%Wv4Q@!PR}6@SBb*Pu{W_eL)F+I7nF)KgbohHNH4k#eA_(|BW2RzDZxYSdL!!D*9E}wi>d+LtE?!v+aw9 zUA*SPwe69PI}UxXVyS0pZxhPbk6@e5b!qN?2X==R@1|oHjN;J9Ry*R^$752i$|(hR5yHQ}>P;cBjWD$2LcWpmf9VzzBEwVu|p zdo3Q7@g8VtJ+?+9M#eET^Q-U0?3$TE$%^~}O`p%4i5C>OSY&1x|N3q8i{3qZ+-BGn zi?E8ba)obQa^|Cr=L@TZSf3?U+cSgO`OjYO5vbaKOk??Uo*OFPJ@j|%z2}zy=g#(& zbTLo2q^nMx&Fg*lJ@(c9Cu>{Hwl8c`?c5WB_f>8P=pX90-j~0iq(}S1w1xJ9E$Lt9 z9lm_)+P7)5cJj>h_Cy5YL-OQtKLP`tC;UIzP+?p`o4+P z&Q`mN$+p{$$^NRJA<-auX6v*l@z<~X8nf9%`i1n=4s6MJy*PIHDa8b*>3>+5^8+F_ zhHXEbVQ|$UU*q_`m&b26{4eFqk)0BzkfZheQ0CvXIY|?W+(TR=1=;r8+Ve*L9fw3- z@wo$<4)>!bd@c+6*>G})g!-b2N6FPf-zOdKV14H&^nK#>s@L1sWywxuQPX0LzcD*V z&~(+?6tkHxgw~eK|1kH*zwZX=xBb-je&2oE@bNpBn~7f&=I>dy`&dD~+1!Yc)B_}EprX^kRJ^N83d9LT38D+cXU7q~dGtKs}bj+zU zv4s+H8~QGDh9|F^dhg%F`PF-?j;RQ#%s5xn7PKc@EAzvSr>At+9uUg#n(8IQvHV-v z-UnQKYzuZQnP>Ckz|0$2a%XgEZtz@jub&w|{l#jwfD31S&zxQR{`ae$#s_vW_5ZQ; zO7y*(Qqq3kKlJRUnuX8b2cA!L{g@FrXSdN|3Bh*~yEI$l1uxEU(0`NH>VNk^>!A~u z4QFH)mRCCTU#yUqj@MtJCzP>Gk8$z0g9jH*uh@TLJ$J3j`BS3%y3U+l2hI&^U7O-cURkb=OT+Yj@iCa$;ae3{g- zT~z6@MZ_KH!tG>y|I*;DFHsz@AQ^^;zjD94%JSV;2cco6U zE_b@gidUThb2yH4NX|8BT5vBrvVCF?qn$1LrbCwtYM)g2wW=Pul3`lh-FLL$#?QbYBM}+`o>+g|8(6K-5m)y z%D-1cU~0nN5LG*!&+p=5^@Gey&AC2yPQUQlJfSRl#krrK#hs&AzpnJKHsiTd_D!`- zlC6|?XYj$}j|^m3+s~|;*?5>e%a3V|c}HttnONMtc^8*;R-RfslS^t^%>n1$gxLW; zju(1Wn9iumde54WlX>>o!|;FrB}2w5S3WP|(vbOB)i}9yuC7#M(JRAU3q(2?o(c(U z?t00(M&T)|<*%nTCt@P}FQ@DG^G|rp6}eIGQ)H#H*n_1ln$epN9EhL4Zm$B@U(MVX ztmpqV#fynND%~$`7Q=e-u0ra$<)RX8AC2xFzx(!@yIy#lue|iTH*rgHdaa!t_S$@% z*?5lU0_VMmxk@5p58th5Yu;GbXDNJo#(v#JuE*93$MGg4E-w|iw(f4|RvslSnMlFs zULP4Q>X;dBnKA#p&*S^k4O5M4y;y|Qn=;aFhxorQUbJN?Pl~Qp$t}Tq3I&I`7v7wz zcR=CPl35=(Qrv~>cIdBFz5J|E&S;y4m9$m*%%8rqZtc#G%4ipeElCxi#z1}{HVoRvCT=T?>IxIWioDvT*@|U*~f*~ zmM6^=de#(UwVYEq;n%ylJ%%CWzg4C<#Z}rcp+@MC& zM(GJ0=XjzgG|%BkF@UZs+euF>TK?tkiu8JYhA;q zSwE~_w14;NZHm=R{}=TqeJEP|bkCl5uTI-2S?&}#du$umhopOpwm(RcIaT%WWMIAS zsjahQPi708xwq3+^LWP(zqOk$L<{M3H+Wst2nyM@bFIYT9o?OcpXb_toA0&Z>tXx% z^W~UcPuZ98qxQl3r-v9CWiPTM$lHFFZI|KL8Qs>m*ymEuH_bw;vx-M}lw3_LK8Wvj zdKn$!7}zEJJz)vMHQAqGX}KBSU3GS{>$9Dd6wseGt?|u`qrMM5E?T&3*H)3e3t0ae z#a6uLw%M@iE9=b$!95qErPH>THU~ZFc>3h);%foZ?O9!4PCC$GXRt`wQQxc9SK{5I z|Lynga~K1>K)f9U*1{zS!? zHs4dc-|R1}KJee+yOG8UsraRrf@X`|`+s)F4|(r3Q}oW&J>0hcSVO=8Zl={cr&k?% zIFDWK?^9`MW0v~XebU!{^xxB%bFcB_o|Yf0W7pq_U0P~>VX^+Z2fB5ZA9Q!t-BPh= z*5O#r^mh4-=d}efKmI-Cx9{~f>%4X-rlMke425KCz%srI$Yx0fS{brvG zuASMFH~VF$p7egl6~@oX{eCRu|FuZn|9;Z^fI0k^o}Mde_-xQ8&J3*<(c?r?!AsDkWEklDPNIpAOGF$i}SIa!~MWMwrbkCw-;sK~nx#BAAjHni~U{euiY1YU`GW z$8aB#JH6rXEc2a5i>IW|lV0J^x>34=|4QDL>phi8uebVUdH7G{Q?vbdbK1Y$eQN@k z4I`fji?iRCw4cM;Bg*1dS#CPbTeA7aqPcp$zw@ihCYlx5-Yhq~{h@&Kz{XO;Y2sXa zC+1h5`_w66-+T7r5=LW2ThXi2+Gg}^7hd>+F)v?S=5$qOf7er`R3Ah6{9`Zbw{DR; zKU>47f%ip3SZu1>Ocy_))v5t(i_dOY^n3;HsSJ}-S0Y@W|p@7QD`fTCFg1LsAJDdV+)*svwa^UsSnwgKX z)|%b^zvo&`qTZe}4KF9GeHit>!Snu{vr&@MZqHPGtGze>>>@q(yF73GPit&047QaM z+Z}$XHs;j_uJ@+N?YDN#6IYnPb9VCUjk~`V9A30Yvb6E=U$zbZyy4<@y}^3-Z_mo5YnRWeSBWCT!9Q7the0H0AJxxrImnE)19% zP@%l`%ddh`N1q8TrwjJ6O-)ynY`)%;w2ot{<^1?{>+U?N`H=K{$tG#PL;m-Y`76)x zvl+ZKuOF?6vNAd?s_xlxWm4cBkDENsvU}tjE*^Snf5fuOY|X>iDOraK zUbbEOXm4_YS5^Jugr|vSmv?Q6^0c{l%tCk8Im3I?!fvLDMw6EHP&s1$}R#=PQTA=+^^8Ekk zuexf{hV{GOu|CMvF|wI>clXiU#qWxXSzo{2_A>jR$5#&i8M`{NN>)8|&s8elao211 z=06jGr&fbE6~kcZE+dJn@*X+jN7s zinkrtkAE-u->b=neqpHKa2AhdW2nCVX{)2@8_PGVH?NBA+kbXO@!|Lv3hp}k>9ucn&6I<^8Kd5Pp97x z?yrvdc6&|Jowe+%uJH)AHIn@#R@J zAFSV9yLtUaQ}KiE{?%^SebsON(@SRCYu@nwou2(troYb8e}4bDdYj6sYlWwlrvHsv z&z!Ct;golDedfw<|5chV3d`KSHj#f-rsS>qR}=P?$G=ppYDx~2Mg2Ab6>ZN5h&=KeEse^SQ%EM#uZoz2fBYZs;Nl1_VSkZrs1 zO_=@k*Ed<>u0CrJUf}A)_<==KB6f9Ch1=A`SxNg`PvlAY-k4Q&r6+&p&cC7ml9$Mf zIX+9$&uLMAF*Do!*ov#o%9~^~_U`+}@iUFZPt1CuajvWCj3fO5rHyiX-iMU$s4w|( zc%#+(nah=D6h({j?Csos$T4k$Rf1gWr)fu@UhS&XP+VR4+)b08N$c?KgRblB6MA?( zruT+tcL-hCJZb%(82>wI4~3s!{(QOkkT&ZCp4x@-DqFKpzSfKN{ME=^YPLR&;hvec zKDUeL%kMR{XK2k_xk?`mO1vgMAkgz>2D$He`&F02kr>#Z(p$7 z=H%a5+2uEM^p?wCxw8EH_IF*@J+#+D07O+Z*G#!Yg(G*T9|)ZuipCW zzoQI!YYr|e+Ue^0KtZb9aC!OL4Wb{G3O~0i&3LEXq1L};P9Ecgi)J$yD;#6Il2-BA z&{bsPm9yLV-#D2YZ9HdUp}in&{f0B^)|mcU)?;A1`SiM)P2NAF*4S+I-<2L);*0nL`--oa9-Jg5#$(HV?*SH$r3#`h$&snoNC$8gh zwsd#NOkt)a;Wo85Zch>3d%d|w=Y!SqA8(z~JPePAZ(V46ZSPL5F0q(L-`q}e*N4{$ zKFWU>-)m{rp2_igNup^fj;sedHIGmo>fWW`SzVTz~<32W$wZhq0V^yNv1iIt!@9Enc>Xn_c->Kfo;t!yZiMUXR|o- zo?bRHZ^JQ@r@XeTQzi2Re_oMqW>|HpTcW3@We#;uN7_cG{j*3DaI zq%yd!^OQ+%@AxLV=ac-srx$G=*xxG4w6ZbDZBkm2o}-$PqrJlKqQ-*;zLj!}?{%`Q zHx&Q+^y9~eAMDk^@8`^&zo){m>Xwf6><)?9D)_Aber|)8u^bVQmn=-er#kZUf+^T2y zzau{}d`fd{#l0sU>z|)%lsvpgGMbOg`NfN6TX=8ug&J+#9kuAIw4~a^rl&6+EbsgH zzbWn37O{2}p4l0T7MdK$7Hsl7UG2O4v|sA1yPaP5IG9!Mw+Z~15Z-FNsww@%QMVZ} ztrO2bpL%8QgT)p_|2#Y)^Dmf9(LB?YS!sN|i$68=WqFLsrRQz&_qS(+9Glf$ zw*Ov{WX=kSu<0lNFv`}PpLK8X{^-w{_xb~iZ`VCIbt+}{tlm$BWucF^-Re^ne|Wd$ z!Aj# zzNWpl^!DA^*UF=_?x$7V@Avw6+vD?VVXout-I5K~b&q}vFt65K)tO_UQORU5(ediX zw;Y_w)`3SZ3a6f8-gA1HTCbyW^S>$IvxF<(Jnm{?FYRb3xVFTDdDAS(xA!*A66BVd z^+M#B)$&gcH&TVSEYix$58fymec1BQ$>+k4lUg)BUR(0!_umpnOX&^$0(Oo8c`y45 zIS(8!uPeV;S+&YIM7GkcP`0;cvwxlQ6qUXIpNakDfAXKD`Tf&Pe>!*;to<{;U#|A! zQStfgf9A*A{(JNJ|Fi#pmVd0j_RmzP$&T@1Tb{t_KSuknY6Y-+Rcu;a?{>oJ?$(x) zg}=Wr?&1$P^Lxe#N5?G>T(23m%PG9P>0*2D_U||H{_0WB`JNuTKiPIl@z+WH2kJVv znEzAHd7#iXS7S;H zZjtQmeoBhhAKxt4Gso9Z!d?AY{~{Sbh)V8AHcugZQbBL-{7I zDNS+Sez7q9>QAYh%p*Y?Pgyo7|MK8+jnsJX?$)-JSLOR+%(pH1Zg^6?v-G30C7&jz z-yr1yjSR^P5K zu-P*;W_=^;&42d_|8vYZcd!4O_d1jRg;&y@{w~mWtbEe)(f88X<-BoQw)g*$T{o?~ zJ8Ylc*j%s5u)ejJ zS?j5gN6|&bxG4r)4v}q)Mc#Xk@gH^K`Et=V-InoDyjP+)&&}@&xxP6YME(advz|EF?TmURZcrueC2W( zi^YB&ady3xSLfXDP;U%fT$kkNKfJ0?x_mbG^hbB6e|+{xax3rY zZ5Aax^TeHfO`aOBn5|-vywx^p?iHr!>Vp-MXIOIVxEH(@ViZ~M=+D%vr3SCF5|-~Z z$nIU~cj^^C2Jz99_YO>*y4P{)j83YVOracXb6%X}#X!&~Tu9H{Szdm&- zJxqJ;Q)W&k(I(LV6}Qm1=jI18PMORUF3@&)cDCqe+l>obdS1Wo7QM>R5pzYL>um!2 z6+4z^ee18-T-O!o=zHZ?{yI#@LBy4B@x|+@MJJB`J9v>V#HudiSw_LuU15(`=P(|% zza?!kZ!OO}$G8)vDnQL<=6?d%r^V^>d!Xd>@7KL+*2z z*q+|o!{N!$x=^^n-LsCnQ>*DLW z8=|}dRP_>FyieqR%6eKKS6#$2Uryue_EXb581FS$pOC+z)GN)@tGP>hYDwN5CUf9r-zxjCPjjx`vQa3T6**1svZ?;JgPIH57Bk)dsl58~w9T9h zI{L3UwEEI@mb__wo@V~$^=+o+b6+|SynMJnuWjme=Rddd|Ge_L#i#Z(dfTg+0k>zd ztm&P8beYx#t=jG#A6ggdl>DEUoy*ZA?VEp}Ti*TNVYP~93vYWwdfpJ)z@fxjm6GZd z(fd|I>{j=hb8(+Kx2r_zC0tmrj(6YEsg|Y(jV^z0PB7f8@kh&#DejZ=hF8p)XTuWs z%HFXk&WvF9S+41ro6)6UVsyt#B9PZSoLTsTCo_-34uj20Hw%8fqdvdp6Q}F1!}>C_ zDw$+!xZlao5yOl7F{|t(52MmVbPI zw|-rpx!&&oZyGuC4_~V0U&ra97qqrld3oj=+2wr8?bemb%q%><@yfxcR&k30o0Okk zi%}0h5a3*qwPEG;;yt%514Dmi^?WMY>u~GWgS2kNZy6U~`8j45%h%mXW>fvYX#Dvl65RG8*Cb#;V1jh%!^d&&=S?{h+alm4e^-D0ygj;?ttSUpvxWIJt(%8g%<*?u#wm)rW5+K&U~GEGO{?)p*fr~6eQ zDlzd|nxOrWq?#qie!uPC$bZix{9b@R=W4ZD;n&x;AD_K*-(xdHPDf4gZqXG@4^2e& zPP4f(DL*?j_{5%l3z9basy9&YsvWMecuD>NwI;*eR8U=XOubAGX z<8%Iji6x6!uZ?S(~!zFSrA$-lm>TUC+1di5!n z`p5B^mTUbjT&t3Aes8Yno#rgPY@_22xgDvSi|RPP7aogmo&M+1w0&%!mR+I$ZcCk6KK1nCcl9UqwGxlHud0gq+<1(A z?@N)qD-FugiobR*+OoBD$@S&FXD)2DdO7dsmgWDqlr2iNi|lXYzMkKinColUv6)Ilz_Mq&VwYs8b(|^s;nL0aH?4y#wrsjL00tcn_`;&IM-o9JK z#`pWf>)C(aEsOD+wKaxazQ^lzex_*QR~?TYW0ucMmzPXGsI}iz>8YvghFY0<`?l-M zWs>=Fsz@rrCrbY>+wLUhocPO=3MPu?i{HMZI+MYRVNPk+k-JsTK5C_~D(>&S-I_i3 z2+yDUf40wDByp?KZ1USD_Rk~dWNg3EskuFKg-l4J#DPVEV&8ANF5Jo@KU3}v%VT%b z;>SDhtew`I+Q6Oi-#x;(%I%@TnG;oSCC=5FcU6T?E1z@x=CfZ4F=9`5ZMwMSTUsao08c#HV%JOcs6HKVuc=M9pt)#r?q4i8k&mx#+n1AP9Z!ue*Cn4!*tFS=7nZrPZ`4cqr}+0PTk~r?&hYQ z#~+4VKWnt*@|ASkl!GVKfAz8NKiDiOJtb!Gw)EV(E$y9&`zxb0n$FeF|5{u#hs2kODwORO5_i;_%JPXN>htu{HL6i?;YkgM@Ful zUg^Hkzo_|<{>j!VfA57Kr5pY>SZCN7-rUQ@m_22l`Vy(HXSe9=5AI#+@O*V+_#w-N z_-V-up@C0Jrk=mZ?81G$bn7wqH(zDGO6|=$xcktv(z%Q=n*%OiDzCEBnSM0Y@nlNP z;+I+z9FM*_r+T+Tl_x1`t}XYx|KH9Z^PZ~CRJu2?Gh)9>U{T(iWl#1=NF5Vfbea8u zV{*Lzi{>zg5BKFw0gj#lgJyzf|t)74vSV z?fv|^pm+bWsCfO=*WbKMWcn(rdsp%Bf=!F_SrVfB0v}key}56v=k4I$xepI$^|m@J z`P~1T-99&;x%lmskR#tJ=lY!Ww}`D)&$lyLcG_mUUi<7LOt#V=9kv`gWBcpM!aLkw z?^LahnJHj=u+gzM-Zs6%VdGKDv;%l5C_nm$Q*)@7;3zhq7wWi->DcHGV8;&0(V z)kaIcVw=EtemP}Et%?)5jv3*T8~e9K{)pCn#^j)+Wvgd-S$b)?eILwb~dV<;|{d&2AlDki6*Fm7gasPhObx z=dn|~QzNs~x|Y>Jw$W*y_X`WzRYcD=-4?7lWzhur!&@8$PjGFhY>II8KCZB1*0#HM zUagXk+0#+`aNhG!jzp&ymzgD6xD0(h=p5P9%s%nmk`z6`yUafC&imCIo~FWAC8Ven zqt|;*MmOozMh}Ta83&nP?Mtl@vtIQs(&NV)?sIWhPQK9G?rQnfV$;dJyPtI?WX+hs z+iw0ncirsoyNcPw{dZoy8sw56te^TcS|@O^xnJ9ZTl))DmIYp8eQtK`Oy`EHn=50^ z{Z*_xou&Nfqss%^RlfEcZUtnpu@@(c@aqchidh(WSHCvt@8e)`c%hv-LHSxnwL$hy51isxO-lv^c82(S4)GlJzC%D+8Dl5Y0@}Ds7-Cl1h0{LFP zjM=HW)BpFbk2VvZdGqf$^iAQ^T!9B_3b)w;6m=XFg!b&!V>rEBqIRu=lK+$oE)SQt z{c!64(rf4Q^?>f?kJ2W8n;$Z)%@W$3WU)%8HQ;#x-z{FYXd`x!BgY@Ew@eUE{qQY9 zp!8a6<+GVQlb*yZ-+5^1g30F^YI_7%1spv4to&5!qlrCgR|2NbyKwfsSHy0fKmRr# zUOX|b?q-GQ?&ck~KdfylzrD#Ru?u*$hvfk);}Nft!)gJUfnPuFkCJ9x(%_Yq#5<{a z>DE^@oHruwd`Sv@x>=LS;Ih=ERTpX|>8fWgOyzKMuS%G|`%U-;>9+Th=|b`kE-b&` z`}+OY^}D0$_UPXW)sUQc@R#{f#`TU*ck3oHJzI81y}xKLgMQHYyHiRJe|vY5b;9&T zl{{psh`f8mV}t>Z}h={H9Oc*gV%C+^ewQ zWY*)}z02R7WP6!g-Y&js^_i<)tUR&u zYOcV;eJtyH;~xJFsxf1Biu>AQG4<@phwSHf%-M5pyU@N`VLo{Z`a7-lx;n?oR(Bxc%JXm!@y_)ESr_bJw4C)RaT* zSVGfz4zAM`u@BQbA0JugqjmU>?G z@-KZ+lr>5B?B<7`&AQ_M8EjksIRAtH&xiV(w|sVXV7|?{NgiBtQ79;zv(M_jbAUY?9d5z>-2v+jyt&D@oe}ce7tz>9o3iBOd8JrS%2MT zn{H_^X{+xqbI;a}*jM?V=NTW~_E;t}m{@IhKz|M5tO1;8ecdPb( z2=lgW-{HRDM0l@K{l$WB7b97fKdd#6vF2}M(Utgh+Ml&(!Vjg2%VNb-56bi0?7a7_ z)`Yd_%HEqfu1}|Kzp^@oQ^z{VYR{ZS|7{GvU2>06R8V>5-Q+lDQ5o;KpQ|rv_jjMr zs*=;V_hhs6qC*YtOxB9cM|L0nw=C-TzHKvvuO}PW{jzu?xLh^gHusB9m1VuLe*Uwq zi7gv%>d0)LJZbBJ7t@@@)1=zF4yVt4_xVe_*22t(mhQd(c*H z_e3^#?s|Lk%a7bu#jcm{2ldU1-&gpqF~vbWS$p+V{+Etkw^iQ7fBeE%QNFb8hxm8R zdHb0D2_Emv49)MK6L?SJ@tk0XS+4d+Tw^|DZAL!CvytC@^CkIO@U zl(9b8+8wmo#L9M;eo~L{-(37q>hj1^l=V&3z$rAi&1jEz9YRi2YKB8Plr1efsg>&xa=! z%Rl}0>Ob0XIC6z;$wV!g!uq*)uQ3#<*c%tRIqcqjf0dK@zirox8O4tEszyFH7e9Ns zQ`f{cZpDv@dJ>l(Pw29~ax3k1*1=@4U*FApzDc-A#!Rsc=jgniz;$`%vBsyX3c8L4 zeEE9E(KUZneEpOyw)=D0cciTpJO0+=&ARNF2L(B1@5^Ej{;k8dPu+T#_4kR{Pm9^( zQiGU2H!Pgqlzi51Z=$_Sz|UE0C6;Bsa{1yYb)P}gQ7vx%vf@zlCxU9+34e->*QVv$ zWh5PsaNYHW`(i=HGu;JSw;kAH*H+px%kAPro-=8?pMEQ-JGdw3;R7FM>#~3!w}b5a z=6vC+vtK2yKW*u?c^A6)>L)5zozd9&XDZXbshvhY{&A=6X_t8gz9-IZ&(58aJ_q;K z8tAQ;KjfXXGsgByhP+&z?TzXmT*izuegttJVmhoRAYH;a;}O5wO)c-p+$WI@0uR1y zd>rojwn+B=SJy4qSF3si{&1MmyxRWZ=T5uA3yMDCMeN7&dLI41-d$9*{DFPX<2nyH z=a@S}k4hz#o%-1dkH1>K@Z_8It(~8@Gn6^1hVX1kNDxT~DS5WL#?@SY?b(E#ACy+w z*GH$k(tmj}vue&h34>o&cZ2x)+CH`Z%H=IQ6p|yJ_`xfLb+cD@!J3XL^WBrf1P<9u zDP~(THA2_)z?p5)je6m8_H${vycRh9RLXWgPm1sM-4(?zU%ogda=;H&r5DxWIgFJEB4^~zS-G~-ktvwZidxlpK=osKFJqm zloIpuMw!`96E6SU|Nfga?$&KJo3z+C^~j`%8#%8h%*g!Ymt3WK=Gf*dIb2OA^KXTA zzCBTLBEM%+aYy-fMGnRY{RQG%t27J$XPei@0NlEI~VPjSi|zIWXjZw%Z(^3oL?zD~b&L5~>CLLSb)E08v+4l51_S{n6 z^2$MdfzHOw8~1+o^NKohQR$J&%+Dt{0`$M+Z2i*AA#-qnnEmPLKeyWDM(w_GYx$JL z@9+3lhTdCpIWp}?|9(T^z+*{UP5o~#3tJH1t6Ot;6Gw{I@1mD;l3s?nALd;vnpDE! ze)ZjiiZdsjnVz#QDcQ-U?0;nAs;L}vV<+x<^C)+p)>#FUXJ7QDZ)7riV*c-j-tVep zLxo?>?{_WDFMjEFCFN3ZOMSm*!$0PF&#jl1$n42aZez^P&@7L7V!TChRgiB^R6u%q z#kz!_?@IONMZb9Z^}X%!-!k*0=S-XVMUzqL(Lzq2`JyZ_T<-d|CI`!p%`=EOub9Wb zq2bh1mz(zb?-(SH{yBN$p|ARSUk-!i=jMms%;}n+d+ujsfa;T9XQ~bhnrK*CEQ)?H zCsMkC=fHfA`DMisJ1>7(%Mf-^BVm24^C^M7;xmsj@v6U%oE+aDd{jWDe_G!!&3 z)&rif#Ix^@T;lk*`iOT*%~qzylX+*3-v2yhPi*IkXr-B3S)$X;&ebbcG0l*?uA?#c zV8JExAKw`#8qJA(awfe`FV^V#oL9S7hORm3ocQkOHxc10Q_Bs-?M``wg)HnWTN>>1 z!0?&x@x5~{1uQwLlG>T8zd~{SoF!MXxIS7HY6k{Xd@c2D{&9uD(EWm}-};ts6Amrh z>9aN1!s*Pftb5k0ZOYCbzZ{`&ZgVn#ZEo$Md^G_MlfYe^yBAC>wElFeYWJb+&8FL4 zXrEseroZA~uSwmN6d{g(4c?V14KtHhuNBzmwc}_D|E;{8<_`0Dd!DrIU%mE2&Qk9k z5$lWgGx6Pt6;o}jtbBYx{??O6iV@wjF=r z;x{ugLZv+A&ehwJRtSIilrVwy z`p3^w?HNoZs=iG>s|Cxe(%GMF80H*eg^;5W;t;k?q>X-IKL@i zb+Wd?#f@PJ^SA!qW0dIdUADw{`hHjUE!zshB=5wXP~~@HWq-Oo&bEw2$nB8zqRq#Q zt(dPdew9vpE2w1nPfDV(C5JVpC+q%Uj-K>ihwhnO_xzBT&VFawJC@bA#YNtmoa+*8 zpH%p*FIHD}tND*4Y1W?y`}BmQ+#O$bPrK^bt#erQ-J<{bV*RK82ss>^rt|XRGM{OC zepP)B+Vs0)HUEunj#DA+TX)tze%u)Sef82sYb%)9SExjoTuJ4-r)WFd>&EgXeCv ziYrF>YIC_4|hBk1H2%I!p~; zrZWG=_LFbjBo+56$L3D?rfr~*@+)tu*NGRbN6#H7E4c8s)0g@8v$}npr`-;Ht&4sg zz467Tpw`8k%nx6>(Cre;$@}+GXZVjpM|O#eO}a0py>)rpuhTNBxs(3z*9zOZp9|XG z;8kB|AuhxC^=iU;{xxU9Z{DuqI6vh~>L1>okL9+{g$rWcvPEl`?qg(OS9$U8UH_`z zyv5qDf4}*(+rKdE&YCmLN|7&<{6dcevrWBvs(7O!2{o0F$;Ro1N{(RFg`>tAQyeSMPT_T`TCmTgsg8ETGbE;mb=V($?0oLzCH zX~}&Nqk`J6$62qe|2gINv*pHBiu(iSBpSWAa_7R|?XwzkWNzR1FT6J*cb(drC7BGf z#8V&mB-!oP`?~V}jMdLPg@oKrG+evmlcg-h_RXrHdXH+(+SzTp;--C`bU2wucCpaf zRG&TjZ*LH3p4rvlcyIIF+gqwuo9*6wZ_nMP2qtg&(CAMpQgIaDDFCA;_PS7nl@G4 z$(SQHb9(b?pZu#+7epTQEt$l&_}*71r(>Q?FAs=|r5uX>(OZ|jt&WRo63N?N`<3#LH@xnbf{9mui z*z$PB;?r`ECMV5VTXLMEq2bSb!F#-WPAQZfwd{SecB0=u-BP*Z{|}svzumb^vovAR zuKeyPS03CF;y1W#UTPyyvFo#^vqj|M`ysaP*6hh~?^OT7FLO0zx4QmJrjHXdnLoz; zUADwuah|s>Lx%A$i}T-WC+573mTk2%J?ogQm}_Swef+?gul zx#|?f(hwq*{bcFaLr0!Ya?-h9RO~!Asp{nWf5QKigWujh-h6z%y^H$!c7dE3=hZpp ze<^%*wcQ_QPqWMa^>6 zSncEFc=l+cz=_J@P==$1j|^)cbI*OBv0;lqWwcMpXO(~9+$)mu?p)ZLn;E+C`A;q8 zuKY=97b51$o{;3I>DGD@v-^$gy@MGHcgqU;;@5rN=i{%sW6Fm+#%@7rJQvm)xJkOP zDo+t!n85N>NTi*0&l_ECTR-Nl_N%?V9N%BeeVJW5=%vC@$iJIEE4I0ves}Zy@8kA?4H|6u77-i$`p@1fvNb5bFz*&)LwM6X-Q^O-8C%0A zTZBEUdbg(IO3Efy`GW`7o$i@({J}<`%T(x}#=TCXF-BvcS{C=P;(e2=;2EFj>8)m4z&bCz!73j(S z?clFlbG=VkZj+x+EDY4TVSInlqM{OsL-GbfzqTHht`d+~AY#)-yv>Z+zb zwfMGCP=JB)^TL;|kG?5+?h|)ROcVGN`fgSH;_cD7KPPcB?d5sAdd~h0Do0eh>+Tg+ zKIgrtvG=vE$KUe6#|lznQy)dU`h_m3KWz4-Krbnrp@}thn$^pNPH)$#?ySwcl=}0j z@{^vz;sEP2E6+++9hJIxcjfsf8VLxD*uiJtdmpt zr=wlVTU;fxS7PtGZ~s|#{;t3DQ+jQ1{U){!^9_Xy=wm(gRPciWkp4o}$uSw(Htf#$I-fzFP(tH$64l9X$W~$JFOv&8t^&+*T-g z^`k5zTQGX20Q=&fuQDaxD@p{vO<61XeDU2a@O_T%_V=7qZe{#wQtSt{251O_HOz8ZcX}k|3|uFr|lP>_L;qE`N{Wx zc)rd$@%#jE&c|zla>Keo>mqJg;~0YMYr%r<^{_{rboFC!=T+ z^A^^IK4U??&v#4vU741YDL!$0P;peH@9SKDnf+4RWi;D%EooXW9BWpUMWyJbml*Uluq&|=?-O+tdm#sc()lIs0$9YOwqTM?9YtcBrmYuCdP)J z?QYcOs;mX}_m7^Rxo!ID+iy$P9DMoI>wZ(XYuwcd8b>1cW!FAA8PlM>o;@)1pyX}K zCb!^ckvo-)Cx?ChvUb;;%_n=k)@EIIkM8WQN}DEg>*>OPczNNoLPf7%zm@qDUU@gq zO{b8xcjdnF{WUk1?6`LJWXiJ~UR!yO%+kFMf4P?UJb$9H^#k{-txH}yFS2{IUiGV1 z!KE})rKxovp2eJr%rI%XKXH*(-KN|fADP5|%_`-sZG95CXe&E!-s8J&?tVKeCe3U& zy6JS}dDF4%#s-H-78JKdTkJd}--o zd##_GEU*7*9nj4}x#y9Gwz%e($}Pe4BSx?!Q() z)q8vHmhMPDhvqWh*s+RXv)J;3tBgt`_nbYcwS2}QAOD6qxd~sCZcN2|ion4amsDg~`qWL&(t`IKVSPOXD;<1cw{d~dJ(^nUFDw+{n)P?4wM_y0f`tnwHdenAtG&PJx2Jc|W&iC9*Rh{G zo&G%j@{5HA`p318h+jB;s{if3S&w~lS9MJaUD3U%wte$^u9gS=KY46STtLh0Ox#mv zpO}>w{wl)pqmNj2#4Eo3`F(Yce+~po)>fD{tr7lm_n_#>9{(Q^W!XD=uCIQ1U2~~w zda&EZV% z)`!1dXZU*DDXd@c>R}-+^~N0gJM-Tyzq4x5-C(CRDfgYuoM~M&Np7`%bwuMnqZpf8 zO{YbFoMTub6a6jqyzXo7t;bVypUr%gS5`8C`C-Ajg<#KVxPL&$x|5kd; zdVBvpi_ZGgeEa1VcV_RJzz@-{H#lBn-#&T$_isyDPL^2ZzD~UHY5M1;ylEfiyRHnK zw@~lt-Q4uhn?=p~)oywN#S9bD_5=Vys(+1_o9302*e%GIGD?K+Va*1l4uaNDs%{!!o z;#QuN6ZBwv$6LFrNJ2wRQe|fO#PxYawJ(xnBMw}A`1x?LW#N`H9h_TdI8^I9rm^1G zo*4OdQMc+O{XUJ(>U@`rKi2NLAp9$IL;jptE$y$1+$T-w;>@@k>FbtW#^HQ^T7JpY zpKG!%|2mptxcK(5rKcO%En7VVgZ6;#~uaLz4Xj$?F*bR`#|w{}lD=`o5h%Cwp??e=F^nYO={-$?$DTo z>mgeTFFkl>l^Xb(FJe98?WsP07fG5ePgta&8=`b2;q5KQ-w~{V2A{sQJbvgf^+L!_ z21b+RpH`f_|ND-c_k5eH);}Ik4r~bB939=aC*a!~uPOJ}HqPWb_N(Tj`5a>zv)B-g z_nS_xf1PzSTxG?n`gf&F-}W+#eH4+I^-xsi@v}vN;%ki7pZ4heSrc^pW?$d+`yT@zZj4UQ_Lw?EcC2L38%Gf7i;-ifNzPbZ)!t*0=+b3vMqCT`8vh z>~+NVuW|xPHaZU{cKgY{4l>Y*|5PC&-KHclS^w&>Y{Qtjo}nCi%eEaY_Lul~FEWsK zwdSHz?8|1Hm;3r6PTcm(qzg(qAxA2zs#L$uiMqQ&w>tgXm$Kal7OQ8}{{2-m_2a~H zz6DG2WY)?0);(UPbZf4y)cr;MhmE50zs=VFv}=C$T($)BD&FZ;_rDeNZ>zf&aANVx zy~;d-1>4ww`1a~Uf+xVR&n?Co;PprO4a@TvHI`#tzk>utlwXimUzpn zy?vqDYO~mj&QG_!J(cIZHum2A;GIidwn|&iy;!JP`dVqv;T{pm+BfB|wGV`+DKlT| z);hVwt%9vH?CF-33ul+ag!lGo3$S>Q1xn4Z_#o9H;qtAYA`Vv;~ zJL6K6enM4og4E~I{oHZfcg|;7t8S~3nZNm%;fe~LF1Ei{ZpQZ?R_xT<*LLnj*v)x= zjK4;{X1%ya>FLHvGB+|4esuM(pZYJ@|8MPz!*cu^Tl2%pF3frsz3}=h-_X^Qn?GOt zDY

DXEIHoUaVKJ?9-f#~-&sEB+PNVX;0#Ev>buK1xU2ZCKUWmn>s4xA*=TFF8A( zlmF~2AH)Z5oU*yZ*{IIO(%PMyd)k*rPrlSlsM%lt;qt|k{9OmmRlHsxwD$UI(}RWQ zpH~VfC7(Xxabb$Xsg-`$ceAcFpU|}G%JWmKlMb!gJh^$k+w+N^I3#?3y`93bC)%=D z=h5_DR|dV0Og~mGxf{gC8&~HoGEK9wC?~gd$z~>H2c0$ZUcE`qt@?9(bJIK}pRKC= z4KpS7KkY1JO!_X@IfXHKpKcn%Lxsih=iHYc|Ly*A^W@9Ve`iQCbN>wTx*((x-8DZT zNxtj&CaX13&Y54%ELP?FCYh{#@UV*|E5DLP)XIYi3!W`~yZv8Mt1@H!lj556vi&kj zQpIn)>)yt%_p*H;AZH#O9==2QnHIa)re89CYAf&My3RCuzHz2=lhD?Z^zffDF(s7& zoj28HJN%uPbn@U8{heH5db<`ly`14SGsM99Y_{L_a;uxmHcHrgxLC5<+CEN;UZeT$ zwcXtfqGsO?`d+%#$XX=KlqC7#?waSU6F+BOEH&qjxt1~aLRd=qK}Ds&?_d2TjQ?J~ zcAI_5y2po=r}VI>h|BQ)^pZKpvUI~~=|eX&=5C(T@`VEiviA zv!7fww-=Okt&;iR@MNX$iO!(3qG!w;|6eJZh8R@17#%pIlzt`t>d%cj_XYM$bAIo# zF1WA8N&6&+*MY><2TGT$Sf{}9w&9bM(Tc;54}bo0bK}hNsCy-4g$tBVIhx#1U-v;N z-nD1l<)DBa`CpejeiX0oAg6EqrSi)Duc3B3WDay%X|6IfFbyn`+gJ6<%<#MN0g+FS z8P>RQJ!p2ksI*Qgv-$6#nU6CCuTQQlT&;1fuU3MW|KaitRnJ%ZH|FVld2}YcJL%DT z<`BUJJLWa$tvtNk#7Sh`bmj=tqukfcV;HA0ot3?osoKuXbGE7Zq_ktyJlTH*6*YYZ z|FtDpzI?2Y-Z#-yci~Rk;$2fVbC!p@MAleVKM~tlo3(Mx!H2ecBbZk8Wp4ZP$n^h& zUmg$Vdo$@RO0j<@Z*MC#x5@s~8G(N<>^$OQkC)$Nj`lyi;iG@CGN)%*mcp%P#{~7y zuQXnEj;*41uAqbIBPmsr*w*`r8*+WpFU2pbD`1aXz3AP+tD;$c9e2+EVw|fGS0}f= zt*JWNl(8vrTGXPeVwKzW)cn4_w|?^3{W0eQXInnnP#W=b-jwMVv{bG%N^H`bqgiD# zalPWx8S0$z27B&Jkz@3k$sF_lxYewM`dZp=1h)A(H+d$B^Gyl()iGuA#Pc&Y9LP(|LY7Tn-%Kp6V5E%wMW+JTdX<`FU)v{OF+i+*YB&MKO>th)}7kKa^9C?D@S&_qreLNlS_Af%9IE_ zaQ|>rvmG|%?uPZoT;aI=1{;jW{)0^LuA>K5Eyr>(cj-0{kZJu#}kwk_a)Tj|=t zqus$U!}p8d{0)okj()SUzGkv%T}6@e#l-Mi*QWX>-@aP%`slx({Wo;iTwZzh$+~>C zeKUn$`f}#kCW_8+nW<6}cWQoSh`?K~lgsS?G@kzW^yQw3%Vxye_HMtYu(`_ci!=X! zqxGk5MqAr#5q8|Ub*Z$I!YlrLGq!BG^)mXqReY9Vg7~W3^!3kgSk6ay);l(57ib7gkzX9kp1yjAcX5S9<<1L|4343P zV;=-s-2eYCW6C>u*?Du{CtdBx(fjp;`%~V!SFdL!WuI_Z^gcL01swxjywHta!pG*trpDP{NzQ5!mq^UqH{YQJ+CS`{>853L)roT z%UZAP{m%V6uzL2jYB#01!A#~oGn#$gA5hKspEITFyuFght9280JPO*9#CVXo?wVHH zTBa-y#e4l6n`eb&>+aqo$l-W=w{P*&uUZ|&-jew@*0nJ6q?I`eC}-E_2+!m_uqQ6; zHosZpy^sUd#|~cduAUU#JV&@)bY{=T4|W=rs; z863)4m*xHa>a4o;mGoxC3f-#GHgVtEAZ(_lYPi8K>4@u-PyR+NmwumJwC2aWv!CAE zt!wQLS{+iJ^XKTQFN%BEtgY_V9hH2i`Ejz9?W^NyM;tuYa(MAgjF`4X^rP2W_8G@Y zN>;Id|M60hC)ag>zSyIqAJ0}77PVy_sW~WKkfW#*(Kh!XcmAX|{wp*$#Q)wP>BA`3 z;gcA+p2v)5>Z}t5Vbh*PPM43ayODKKZ$nK^GNWbKiU^OIMPc>FehPiIWNrSOni3a+O6UpC$d+vy!u#T z`+2%ZhgI@ES(UlGvzy-eWY{ga&&ktO=dROw^zWUV``4}d{ulV)`kP{Y<>ANf>Cac} z{9MbzYq^JiPws-{uV1A6*94SEYx()^ zloPiO)t@?A^y!mK+q*wso_2iLPWB!x!Ggy9`<&rHo-oHtdnPI)r?!uy; zGYZ}5@tm&O{4cfoqa0Ode-6C*$ zC@}fOgX^A(=QG8PYWFiv(ZZUMywy zCCTH;EURi;Mxl)jzs_y8{Gw*gIa6ZCqPF+Gwx4XLpZgNx$N0xn=zLzsb|Fc-0QXO~ zTlXm|m2JP4`;c$a`eV%QlU@t%JC)8Y(3H@kuec#<{gN*4oeI@;E6e}HDDrR{%kpP% z1l(DkV_9bXx>is)@!+2u*I!7?blrI9!sSZA)M=&1F07vBE;K*%lVw8T4YphSlYfV# zuinI3VCp8gVd@EY-(bD_?jq|~EO`@D(ztJL=;}YW_IvDo<&h#9D7{< zT3%-IkFRb2@Xhu33ITKF)8d+9Q@1Mfc4u-O(!Y90|ER*#WwMO{7Y}M2Ob#mvEnW0^ zqo~|g#=Ble%1`8}uenh1gW1zyUjC2lqo1W+b(l}i(%o9~>czuX8YcugRh<@>#%?w$ zFco?FVP%v=zKYH|-pLGq-({C-FXE`XBc<24_TtaS4+{1#cM87eZ^CkI|AuEDo>g@y z{@%T#)0AiCzUH4F1@C6-o>BarUR_YbZfg_n)`qF-mK2yeXjDwj8j|I(Fa zg&%ht-Q$m4ihqA~L-Wk`f}P%i{aX@){zyumRo^&A@OsjPoHd_QcHb{5Y1@#0kEQb5 zow_6*|BrtoXS$u+Hn-J*Jy~iG>(cU9HJ@g@_I%|%dk*j1P#xEuSL&WN&Ht!UQ*rT9 zqxvKv#_wS}f<+|8<8cwO`B8NY>w!gC)=2Z+{&Ji0yGMkg^M?$wV| zGnvI>Th442N;RHm`#k)Zb>oAhb#}Hk@=M=@whN!Jym9u)x|b8X^`>2tQERz(MXD$* zGlyqJ$lh%MRR-6d{z^0a$k=xq^`w5S zdRkQj%hY+-^yTW`OxP6g?dpbo6ZYQRl*v1-yLZL1{sy)zoyl*e`Q$#hHuFr|wXX;L z7E7 zLHfwvPmjXavVJ{iz#KnAT>ntMOFQ3}6vk#J)_lXZz6oo-g{a@@zx*aQ?97M2Mnmt& z+1^X|t+aKvac{Wr`d=)wo#M}xSJtc&TYN!(*7N8K&oreYBhPvqY}Z^Xy`cDrsr{P7 zg>2{l{8(CfB;|*&=52}Z({_E_TvXS|FQDpt=yuAspsyt*1ykhgWM${e+gZ!Z<&&7{ zu(j7!etuT!hqmMD&tLwV|DC`8foL0x*vyg&r-ljU$K5lUI?W@#8Msc1pERe)sitm& ztT(% zmyeiaY_x27&TX)bC0?>-y7k_)E<-u5Vuv`j)BmF{*2$r-(U3f*^Mc8<{GM3PUt#YxHH$;Y=5zC_W_Z~{wJ1uh2AuYzpELf z{DC`KC`x$BW$7=^Hr_tEuxrx}&$?x8HomqdYL8SJidusvv>kKEbqfhG{5w&!Wxg=$ zelE_O3+n?GeEkz3&F6JsbC5&f;nr1m%39*DNnhC$;FKdZLF%he^n{lwIwyW^yf)=~ z_Gzst$Jh1g86BJNuRX(eHAD9O0`9%-8ES{)L)6rt*H;=^RU2A)_{a75eLwH-$A0@{ z+|v{Hp8UVO$=u2}&OnxX_uU^Z&G*}@lCsXcuv)R4FK>T}>b47=TTcnen+cwkJh!=2 zw>DZ^X}5CBKF`yK_)0e}Q1U;wfRSgqP=;-KedWKuCk1Vf|JbRc5bN;W;qG0><*x2O zw3npk+z5>ME9U!sN#=vB*Kf=oO`BKc;Q7{ zkCU^neJJ!(BHw8aca@$Kzi}-4?xzJ7a#B3|YJHTf6ZSB8_HFLERvvTX%zzVyRWap zdZF)UyFWeLlF0j`jX#^kd{yMaCo!ozR&O%+AIcVy^wTC$@VdJHmpN79xQj4vmg507^J@F<(H|GPuYA(T)wd5!p{oZ_4?f^=PpRxc6hMO=kk1) zh41bx+%V;gnKWPh`HjA>O-`z_2}>_+D@^R};o2hq+wG}Jsfe+r%Ms=Oy4hjj$2gx_ zYHsUG&R$ulI`>s_8rm@_v%T>rRr$6;f|6syarl?Ru8Iy56kG|>8deo$6zo$+pO z=}&HHM{>A~TRdCpuIQU)JvumTcG?le6rPm1D#mZOa5J1Pe7^bJ*47s)KV7Cx@$)_} z87s5nlyP$C2_u$`+^0>MKV6>lb6za_nU~pSd-T};u6-%e;CRgUXU+cyUsArD?*99D z`HLr8SNm@l{G!Et;K1Qz24}XU){DU<8xQO~$=lXjb=-CG0)|ViPg7?G*uRlBaI?F- z(8Dmgc5@cYj{et{lF6-pOXBraShh zGJ~>h*ZMB}{$ZVAgyVVJ*)N34il^F4n)Cdi;jYW-D;IA)si%4%FH&G%f6V1G(Z8eT zv+a04^?vb-{F=3l5ou3)p1S2#MO5GAxy^1>K-+dIG6mhkd8aG*~D@6aEEka!Xmee$JKs{PT|Q_}%zq`rcTb)0SVB zJj~Ua^5>#i-gk~&D;YO#*IZb@(bs)Lu$?C$BE#U)#G+JXi)jiU^uDK^FR`4HtE|-8 zH!IxL;$U9p#mPLAe`~MtR886$u~uIr@ubuQ^@DSqmzKY^-qLX>Y~@wo%ngFMKiahm z0-qY+mvC3|X>W)=_2E*E;p$e)ib zlH<>Aub9szQlc=|OeExqw`r<*s{}T~&t_WP^GBtU3?uWSu(>2Y%KQI2f zIaBJLylh`z@UM?g4Uq3YrbE@y@i?>_8?-Zl|-c4twirz1swrg_tB#}81%Tw$h zc2`c1&p*}8b)l}fsz_kd#fz8kImkZZt)CVjRMHx;HX%jGB3bZZ;v$0=3%KL5UD|wF zd?mN^zN?bSXU)5w|LiI6M7PGS;=7lPe>DAK&|Apo$bYqUy~l<#6C_&Wro1y?V4Cst z%UZcJpV#P}w6WW47+ZVl`qS6x{=S}(lYZ2$>(@RU^ybg08%;qTM|mfQ>xMm^yIq2X zMf=C?_aWiWZpw!i?pajXU!NZJfh!?$1}B@2j)`n)y%#xd={4v zXKX7iNvslEY}vNaB24M|QIX`mjMa-3x5P9ZynH&cvQetuTxwqKv6-0(y!(xROlDQm;GY$PPOjZHHJ^plpas9dL^iFHb%%M zeeeR4Nn3I?BvCZTl?&2v5E+P`F zuYGO9=Bdo%5xn$)=gPHJDig%{*wn(mo4Tn_tuMXo6Go_Q(&`2K5_Yg36I>_sAuaBc zBCxUcY_#m&lEN6b^o<8g_a41+2;bE&pmre+Qd%U zEnkFJfdB9YLy2X4^9*Hba=!6Qd&DJNuC_T#*@p+Yv!y{ z2$ekJ?_JR>zvB9O|2Zz!)+bBnofJC5kEGEWMs{--`%S5L}bPBkm~7m7XLE! zA4KO#JE}EVC+-#TnRuvIO*t;K=3kW5G~Mm}=lvWzi!c4VxM$Ct=BiJ#_AhdKd%<{{ z-S&c$Ck_T!+2&VliSD`|W-?Do`piKkwY=t8b1uoW@lQ(Jvbh)sw}%(4+J{C+{wPVwrA4w*TxQ!d}|$h8&rk^R^0o>nbuL)G!=g@OTGEZBHv-h} z1*mf#eSVVp!{l4Ro8oO;r0w2XGd<=!D$JC0V$%+`rF_3sg5RdUV_x|_|8-1$VL_>1d&^`F#}M(xBqsb8)vdpJ2M$#B}AokwRlmEAV&Qrg@6AzqWAi4f}WF7bVKTRvx zoagWCw%`n@z3}PowOK0)_*QQ}yOe#FtySZusSo^3=E&!3Xa)Azt*k*6$kl+x}aHhd*< zN^@o@^X+B)Jgr~#?Uvj7qrVE-_D}vgBS-nqJ8>Vg>1waV@{VfnbJoB3&BZ|U#ga~u z`M<<`s>QbSGkomLeJ{==;^1BHq`)^t>_OFJ6`64Pm{z9giMP71^0EGV6&om8!@ZzS z?U~#~n+tt$f^%cSGB`Q-@ANM7W$u|Rkj^B&Iw3~2;f~`RuSF|9@Mf1?Ur}@P-JDWY z9qtJ_TMMpk|7Wd|Y*qEk*4ggmlH^cr)lYthHG^2{)->JD`&*!1<1z7c*op?9lMl8n z+I`C1+VRkd3ok_*N^Tt9Ebm|Em&tS9FK(V(PnOVDYa3Zx>A8J<{BG%QDtDh*UUk*Y zd~98+YG>wH8XWyHdF8ddV)i%Axf^dRV%T*lZCUGr!pOjufR_)y z>|C4p^PU-p=A@@qtVM-CHm)xA_}NypeQkhARKZLE50Rb=TI|cJ)+#a8@Y*bEm{j0< z{I$&i*(tw%tcw2mtT1`^{7GAut8x18-CH$LzUHj|#jRny$3HPJX0Qvyit?{t-+HX- zgUdJ7Utat?%^!omG;m&T?{BIRdHPp5MKShL{qxOs20}V~inFG8u1qx5|B}M|%A#Z6 zmzpo9ch)SwveWRTm(e}F7E3jAf13%$2Vbm3b~g;CUFZE1 z@L;{0+p{SG4H2w&@4nD+N_bbb$zhYo=d(8=V%>Fls;^Ju-R^1-S?MufW>M|h=UUU& zTb~Sjoo!xlEU~MJcXPm$B=rMfiRo%?TVHk`lww3??2bTnrlefG&^Fh_|e4ZQoC8^MREvKYc z2tHWUFjel&#^e6q{pT+W3N1d_5Wv1pq2T8AWLN!f=hj#(w6E2asWD-w>=L@pov6=O zer-zgJ~Os11;D6+w*0m`<;)M*ZxW@v9YqXDX>;& zf73j7v+&xkqOL1$RW4hM<~@(Qr10J9JYWC(Pr1sa*QHCI>G2zAKi92!`sIaGL+$nL z#w&R=<0KkxRnCGw$5i{{$zLtuhH*q z=9qs}OEtJKnzSf9eX=PF#PWOMO;Ec^Jpd`3<^3uNhuk zZna}%{%YKl8D@D@Aj5nu)R$mi)YYA~aM=na04tZ*y= zo1Uz{!k?)3Wy$)Y4=(RE&p8(Vsp;OD3%y5|ynCE{QD^?E+fRM&+r}~$@%2TRK4|_V z#B=pg?n@tNz_rLEVG%<*;K-Yuzc?X_9pi({dc&i8IjnVYNUDddsco-v_V zr?}+ALW{}qKO3V?DYDNMRFa8SS3NA7Wn-jsgoT}J!os2{PZ(E8NG%G~Qb$bOws>vN~uvy>y zWD?uw6&GGJ{G3>P`bOl*Pcxci8RKW@&V9!aea@jTPx|WW@Zvvui(R|2Jscig2;>Qv z`L(ium1CaS0UzId}d z;}z!vkM3^Q;+ec6BJs&YG5bHM^Jcvla@=8_)6P`Dp2P4d%Bk8e;>?~|k{7oqf0`(~ zo10Jlk>6fTj!A9H4L#3sRV3~{d36cPaWS5tN1`^2TE2JQZ+WFC%JxVgP&}&ghAY>f zn*KH+2Im`P>vzxnyxY|-M0WF?Uo0<@Ua^1SH=duu|Jr8lR_Chh?LqR=4V%ov{!ifj zaxRK<^-JRqh7T>Rj$Bw!{7uJc+8OCOnZS?>mEM2CUu{cB|6TZ^HuSsmqKkJgR^46` zV|rts%xmRJd4-KnS0y+xrY{qmE$jN3L1?DA_#NS%tqwm+<+=nC}Oc-13%uWVeaq@jO2@ zb;j<$oH6%MZTHVxHk+MU<}3+w%;E{({4rEU*k-zeZU>v4P2JA(0RjGk z8+s(y`c8;$e0yYi|J3vthIhSUCOMEoBf_|@m*UR|4n_tN23SY zx1LW7*Dcz<&_wgXtxN0gX+6xiDzf6wg~)Ke=|K#3@2~vqXL!av?~Jf{n&=sEN!L>k z8XF`2R5`H!WVjOB^z8kuSNkJvf3167|KW%AUiJMy#U8nTzHh)-%fYPL+iQD*^Fr=j z{+at5x0bG$UGw8grojqR;ptVI_Ar=p?K~e~9(})lW{Xbof6iv%RM2RsdcbMXHrMoojfHZ_T_Bh^RFjJ9y^}R_WZ;l={3bFlO~I{zrV`ygMIR0F?l!f zsp~9tyJcd2+%DR?!C6r{^pKU~*XOswmhNynrh04kp(~;$QnNTN1=FN)!HZNGFiOwjbGrQ8JE`TUB<%V=I?D(lN!2I@3dXMYVm^q=Z{xcH{V;9DpdN` zxuW{r#NsLQ4?bVh{@Cvriw>(zi#dasbmh$qC#}`MH zF)Us@BX-J}D=!^pmLFB)y(nuN>=>ME&^_(6u#)Y)8%9-Ur!5Pu`W<$e>HR}}KX-qA z{%_~qC#DuN^Z(eGx>?6y#mTDc@_#I>erVcSTh-Wk@%Nv1U%p&Fe$M>Hvg6#|O-6!m z^-iwZ{qsjw z0g1L>qW9XiPPlqYaQ?pa9}}j(`h1cvPHD{_$N1$k6Rj^4PMn=6^E+w5tJ&XT1D1a6 zePuJ*g5%-_gL!tVr%bkLbCl;)nmM~S`?G#5SMb(D`G!fxvrWD)bFGP(m00L5e!;xr z=vGF#J|&(005vaeo8@}%dOqa^+&U1)FeP@OS$=4N^UsU}QxaDv7|12PS9M}K=Pvzw zv6QXk+Am2fCvhmBt~#Tr${A}Y%NEZp!6=%|`$_lqrYfIsb-N!`H&e<}3?{Fg*%2<3 z-QF?VY4!v@SFXg#zpLf{%zUOAc0OZP+pebdESil6Z&;Pdc5GQ)^Jm$#2L1xhiixXR zCo>#OXkp*Q7W<%++4g}N&jiI^LU(dc{BPjW-ud64g*j(QV{g|^4eySvg~|K!))j4X zKKK5P+1-REN{lTZl2o&JTcVuU+gfjBN{hZX+oQQ~r*5hEuVZ&7&6+gZm~Hv7EZL}o zvCk(@nOjyq^YW_CXPQDLe{etM=J85*n)B_y-g|FZu$Ikcw*D9$+Q-P)l38@-IOnyl z;ON97kB;)lhwLj)+|s*#YV&N~Lf-|~&YzM_FIub~z0oN}?omYIzy4JZ75-XkAJOYg z+tP4BuIQC+R^M%*Xg0_9r{`p*Oxj$mJ8k}a%X=GhF|P z^1S7-G~Av1LrkT+qiMOy6Nz~h4ShN4s`DS6+pVQ?U2X;QgzyX2f1hsuAivC0wS?>0 zHJ-Vmdu#U!>ztJRk|zJ|kn`ew`F%4h7&+dQg`O^#TPjp=YwyZ{E&DHA>blQ;Ab)St zfi;$&pT+5I-pv@WhsQ!#Z%HVp`FH7}yA44J!VF2QKW&J z4+zIxad=iItD=5E<3ssVmIQ%aTIs?cPh3>puWQ7v`}l>6c9DHw-@I=MJj#ckPVA5h z*JhQA^H|za@cyU8{igV|wbwbX++o_!9KSsLXHL^WQFu1gS+2+IBU)mhbu>GSfw(|R%7cLTu`Zp)ny?-IMxcjH!QJt=0 zt6!!IzHzor483z=o0n{#+u|>)_3f6gKX~!MvMs5fczLSarp0ZkvQxafKu=Y7{e}X+ zmy>>luvvS2mfi8`#X`fjf(754!%72WHMZ}ym=w8f#gn`HHqSG@N z@yn7vWnbXk!d})dOd0@+uM;8U-8h7eWiL3W)o7mPL z@HVLJV)Y!EyZUVXax0hb+*d3xW%A|J+Z*LJ=X>M_z41NubosUidHou4i@Dd%SR8-$ zZrSRy4w?rpx4AYhP|C=E)KJ@;XU?Xf#QN3d=p)%miGRJ3OW4%At6k(Is_abouD9%| znfpnW!9S{C#-+z*x_MhOqI%bheLU`CWPZ57TeGLFW#)k|pWb{BzZq)(NNb{plhfG) zI|TL~3i{lso2ige`$eZ^i)8WE%Wq{a-;Q-JJ=ZYV^S{k`y)X6gDbqh3e<^jqbavC` zEq~@bziczVWQqMR@e8{r-uJA?c==E1I5%(OBSypaeYHCtKb~?-EY4wFBk$6gvsl-z zudwC%$Ln(Ew`K3{m~B_Gd~CaqS}v3I_iqrcXj?VoT$YY2!?Y=T<{s->@#X8?C0C`S zn{)GgyiY&hwlTA=KSxiOGs?>3+_aSi_f~v7@=uY~=ai|_-UVAaMGman`QgyYYZ7;Q z_j`Z)vpq6}Z;rX2ptx@Coq*QBIH^sqLlbv<9IwCO*_c>)UM%9^hq#+J*T}~%ulf`8 zP223`=^LBooxZN{_Er4xaQB@d-|s4_9Nc`fnol&&`+ohpn;+(c$CVW`Np{rw@#dHO zJ91~WQEka98--E+Pr?7o(go4}{` z*ytr67-xH1Hcz^?X6ggm{=Tb8dDpt-o_|uBf9URnU7OEb44-me_lvs3bmQ1$6%$L5 z*Vh*Hn`%vaty=j&nZdvYnI;L;-=z){)8q=MjhHS2YGN4M?l& zVkk*I+|t3HApY}}+V#yEOWf4t!y>EoChA?e%{TuGFN5~IYi*vJx`TiIeR1>T%M)Lg zKzHivU&s?+a~ew7Hro~}}>s=_Vx z21Rox{{GX}9mvSC-Fm{jH}=-@bMGZ9Wd1qx;^5?8A(CNw+>GbN%Wo-|Ono}3@PhHI zybmHy%j54H@i}v4d+5vs%eU`T6g#qG%flDbofAx~t{q~Sd%yqRr3ZN`)|%%MTikcg zXnI<7<;`mM#)Rd+^*O4#&#o?6aLIPV<51_Ex({Yex2xLcr6&k}v0D;mY`1BSm6H_9 z5&Hr)i7@rk6CP(6HWfEDwLExmlK?t6dlM3+ge!iDdZ=G0p}w{5h( zxy?E4)s?K-Hd~GdyYrbWvhU$)F)*z+Su#_Nq{ z6O(XEkHNxsrYD{Ezv%T%*Sg52ncgMwdG{^53w5H?!?nN2T3lhjtFk4iv~JJ7eeYJ6 z&s1njm~ud3&axd#YfHn|J#5%@;rO$;Ek6^__(seStX>;@{7Kfu#O;fPf`6n9U?| z)#ByiZW_^HZ}OwhWPiT%argVCs;ip1a|0ufdYqogyk+_yy&vw(-@ko)@bNkS$GKk= znWYooXe;e`u=wSBy9f8@{rmp(`TWD@-Q#OFKL6JeFK>UV`p<6n`L+M9K3;G4|Iz97 z`+nV>_wUJP{rctK>c0E`*xt5!QPBS1xv@R>w|ptN{QbY{|A%Yeobj`4{B`3(Z&0S= z;^Q9cy+8D8y??};U+q;6{o(c0OTP>F4B|k;2pRd-d?FiV` z(qiCvuuswFRlo}kjsL!Vc}9{I5euC4O$86PIh>jmc4;o}se?%yyqd2cS*mdDjl?}B z>z?)-3)7cyP84w9xy8F()VuJV-R4a-&I<&Y`^3K9DQAfnY!uMn(l_%_HPbYw2^|5< zW*X&D@yA2=Xevs`S4<4yD?EC1%J1YywyiU7GUgX8F8DH4O?kn_9-GiRaTeu9Ci6K= zSX1hB&zN2gI=wn)=V3)d?P`Hg?E<&P<37>qdlo-ZmUrQKb}r>{Q1f>G1%5k|%(xs( zm)#2Z!EmB#p5K=RZyaQ@pZVS7`^7aOo<}J3xma)44v%%GB*PcKui16KV;bK_z8706 z*)1T}TBJ*;ZvXLnNwp`1IG@}bwdA5jtcg)p!6Zd z>h98O%d`(Px_z2E#i`@#^A~l}H9lLPZ4c0%ll$w2_zznNz8@a{TD~n?AZAlp_T%*D zivj+OGd3|elpT`Wec}zvV+Yn}lkJ&yFTC|ssbcf81aH?C->#U2{)hK-+Rx=V${8KI z`>4%bgGKA?l}u+&a>y^c$|d{hf(S>|)EHKmSB{2HcDF>TKk@O^KK5}!?d0d&J@e+S zKD~)$=Pr$+<_`~=c5g~v(dlN&#-}}j{gvczzTF!pHVCq>aeYw0a)`R?jQD;BDr} z?;dses3(h|C)e`7lc)ady=~~gZFA`}-$v&*8%`NqvM5W-o7mRX8sD1mH$?BZ>SEWg z%M6@^Cof*mES;39s=^kow~#0H{O1w}Q8AfHtvN^Y)<4vHWVXFAbzAggj%S?G#I@Ehc^{3uMi_IDFOV>|6cKXdX-`uR%rGcS|$p`ZeE!@*v?YYzYwEmAs zpP!F^ulM<^kZG{D$bD8=cJto+T~CjwOB<|9Ue36+ouxp>UbUk}b^50ta?Xpp)o1W) zE6sV@%V1HqX(d`?xfin* zg{^z=$+J9W2d}zaMA_4r*1*%kCyumL|1wn&-*tsyZUV2@ZOfXYAN>W|SmLIy*z{q+ zt7q%QcdgycbEu}Q=EtL>FKleB|J+|3TV63^x4@&Y4_|5vi^?=I&UW0nx}4qquDjP( zXYT8ltQJT;m2u?DZ+;}2e5pv>=kUU({B~>gjz#r^<#(}OI(i_^$vkuI)a<{d6MJK` zT%zJG>@49sb$ipKpvBos#N~azUrV|Z^GMm-TKs$J1aF5)LaVJ#q=fp(%ig?p?dZD8 z?nO#*Pku_jQL36ztp6}P`Tv_T`8`hm{l7lAT3NR6|LMAgzsx^=yt2P3c*T+J3C0@( z`X86Ae)!x=eoxgSv9_;!-4h>PsVLT3T`R|$Kk;ep8jY>HyR1ET3(Wp~t?%ZNczVGkZ}n5( zE&IUJp4W2Ib?U3?T00iY-z+Aq2_ivjESA2mEaZOK8#pQHb;?ruG|-SP`#c> z`u3(hS6aiEb+h*WZkO`pv|XEa?ebi+zT6LHjJvXX9?o_1=)O_oX~reAZK3M9O-t(XH9mdEyAz7LkFQKW zIdunf$)ykS2N@q97ue`8djAsxb3?J`&3RW3^{x4waO&b3>xrBk?~|OD7tCOlnpC*H z&d=Ljrna>|dM6`8R@l6_j{>`PF>hUUW!LjnM!QZ_{d3zQT`bzc+mW6jzb^dpdRYz| zt;;-}lH6Yvn=hVSRmd0-U-!~1wq%M*@bz_v)H;sFcK#Gh4-{T|K+&FMkxksR1eP<2 zypJPX%AB8E%HJ}-^;V+(D|YJzTPG;?&)$Bpz1`SN$lohj=GU|6te4HV*DtgEpuw2U zku@{cWYfd-AEGBWCM|7=_qrb#zjs${`R$2c-d(8DJ{{ZmrS(Wh!1SH}cb#6wIZ^d{ z>KfO>sb&|G{#~5@@X_)$vGqHxq8sEDJs&UeV7@2neBQrS{loPCRwcJ0&WA4yJC(}r z)SUhxnrTDXtdxI&cHbB0eSiORQ%r!^f3fqkk2DGfIKRuSRj-~BYgX}(r||lMkIs4L zx4)mKwaWMZwTX%gU%h3q4osHl<+!L+@zLmnNcx+aT`|VYYp;1;XiihS_~3eva=-%R zPC1!Jhf<~OEEJ|aE)t8|6u9S9TVbmCyXeiH+wtwo>zDqV{O^HUHeecu5AmB-CjM_#^%ty)M?Ew9BLfZ9e~}UW$>LwRdH#zzCc75@Nt*IzR-5W> zafSx@NLMCBR{{QL)>N0T>&&)xabIz5ZW0yrT)2f@cJ=D>>U-2S+L@Le2?^RR@Yz3X z)f0uq2S03advEfX<(b8kdpoA7Z>SWXsu6Y0lXHXG8$QP$yUbf8o43VCSsXH2{5?Xz z=Z^B1cNf*aJ3P~QvC3aoFKBzNkMPncwFx&v+t<~da=u~yYK6VFV3wa^)7NadRppVo zYBJ^%zSreky(e{H%i-fP@xr~9ymxj+x6G`rSv?`uUgrFs$7iD@1h1a{aaria=JgS_ z|MsNkiAvm3ZQj}~!=vW0+PU+Kz{|yN8?V_{zpu*|5e+|YEOdFr(|0fS|K7BJbNTI+ zD-#!J2itE5ja}XP`t9R2!Il|cH`?xNdRUyiyEJxtn~9|P`&<=$J zTZO?hJyI&1rpk!iOK{wif0g0U+3F8Lm9tGwe#i?>&aZxQ+JWKO)<03-FDqX=8^*BE zvUARnXB+}WrEF5mKh1jGdg#riCdR^if!;~M94znF{$u=Oed6|I%#XqiEYglmR zWPT97!`mO?x#0Yqt6INGS0t+4%Qm`PoFX&9W%0oiI?U@8Y;LiLOk7}-@%5eCbobZ* z)Bar#SU*&Le{lcm&lhk0JiL7I^W;QXk))YtwLjS2&fO_vY&3h~pQ0^qOWL2E*mH?# zPsrTaMV7MTynp*qM zlKr&omAO~G%}cLoVp>{wV?%xYhx_@$?-T#aE4$q~zNKXQt^e|GYrh>0?|1(FKfM3n z?f?JhKmULK2SdZMx-#z{mH&UJGY7J&KRI~u;mvNw`q}`!cPIQ;S6>M3|NhPH_2GK^ zaC`nM|4%*7fA(|J`hPY7=|5F2f0ui9Yu6%!yWYA|56{-_I&-i+b=R(oQfGyGilvla z{bTu1C|D~yhx1G0mw?x;5iGwH?j2m7?Yx;~!;@o|zqUV~?jpWy{hgfO_FBh&?qS-K zpq0FF+K=SEJGE?YEgqMxNPm#lc5bqNOS@-GfgJPSZ^9oBJ}(ly8#MpTg?~#IrGJ&H zdN)CN$H#&${-(F9D>v`Z65m<4RN$FH*M=9tiVgqRG8!8~cGmw9|N8mg%a{K?{*0d| zA>#8TQT&VHhluCy{nnRTpD(`LEML0p?|c4!zVrVVUC4a@r=p~cZN~nr_`NsmZS8F; zD!0_HirZsTTUcb)^wY%dyZ^0YQer$&%hgyes_y;YJumr~UV@6h%l~-_H_tp;S1G2s zd!`r5=F~Nr*7N*1loPM2n?|iMGT6Uo)$7T3!rMQ8T(ExMk7ld$hC6<;{(8FnRSs`z z&9|Fz@wM?`+HB*0r|3Y50|FxBFVByF=5CU{3-5567Q< zmh@jMIA2fd_B9MFS4z0d&>vT zP0!D#zdC;L-{pA>uh(@%E{zEky`sBn(VWbK4~`WxOnLjTt1)hMQQy5s9tI6xf>@&> zH_i}>=MPW0WPH$I=Bqh#W&W60z3=dnI@fS+dH9>di<9>4YkjtFj`(&>3)hQVF3eWv ztukBf3N_yWJ>s@LoJ=Isyp-F~7eQgrns$?Slu zEdQ-*QdOtzT|Bv&`RjG}|7tJlHtqScG=#g|X~wBzo4>ZC@E+^VP%KUF(?V>%ZH=6xetC&;2aRx*b}lBfkbneK8O#ZnA0@PJh%s^~ho^ z1OA%kE72|2&7KHIul3LuxVZKC&WVd({p@{ZBUkgUl0Cns+eG2d1J$Gp2TvR+na z%QXqrhf$OBi!2$rbe*qrN6fwa#`oUCyY*{Jvz!w{Ub*RabGBO<3aiT+-4XG=e${S6 z7RN)ybMt)`9W>+o6wT7f$D3fE)AN?MS9a;|4ILRd$37Z!*3SCs+msX|Uuem5OKIA{ zxeIr$WonJek`=CwZa*A6`3ciq$Eev(4J$IA33|3OUVVAx)SD7p`^vy($F`#%A6#Z{ zepg|3W%AoK_a9#1o3t*YuE z*0rQM!~||EnACaXiN|TFat@u0S=wfKG0#@B2Bb7vJ=fcQuKV(2=Cxu=+x@MxJTBR6 zJMiGc96?p#h&Tq3T`Ws~beFu}T=G6J{^5cZ`TMRKJ=uJot$(tFiA%tGF`4t`SARda zEN$U)McC!T&X_bg-=QhO^j^ogYzHfUX1<@Ll=E-K4D|_L0@r(fihh&BQRk&Ut>NvNeEw&G zhYnvf(-%Hqz<6HP;$YS3i`~;y^$gse+*ranq~`kK4+%jI-{nY76O^?6pKw z!fZ|1Dxp29Gv2QD{8ZNIcm7G1?&6ibKGUaLZ~G#pP*GErlx{Eea;~$~_H^}m_n(F@ z{iEXk}fu6{eF_q);Rs++JMu?xDH%Cn9s3^yZo_+ z-d|e7&cd8#x<2Tb4Bwyid*znxG*RvGYP{LDg=50ymosv{D6bVWuD$v4LBb2Q8?PQc zy|Q4&$K-9t%)090Vnp=YEUlSq&t#?YUir=26&b!@YBSqR*Zm6~&-8kJ@MTGqx2q?! z$ElxJc%Co5VsmDeE7!URervz0AD4E-IVo7}3FlVN6G;A;)6A&NnI~vaVYpLmv;V}P z$2l*T<~yog{%-$=|D^|i9Ir-LYDZdmgwpC|<=*0|>|8(j>fd~=%C##y<~liCEo>XR z<@UgBdt>gp&rjMH_G6u1YvoTnfhSpMEw=))U#@0|Id}b?`p?@=+IDL_*I2k0yjpwU zDua)++5Zdwww+1uc((8A-@`vnt&3Q8!}XutkBo?Ozf<1CtqFfO>Gr2jDMucBE6uY% zprv%PcD=!>-P7;nH@urzcbHA)5!aEgcV@8Me-RjF!C0?|X5s;ziNr^;_TZ2Kv10T4{99Qs&Q}!}Fv*Ho7jl z$nkFRvWXwI=_e*W(73duk7eKK*w=A?=C6;|uwI$`rchZ{`S#y~+@;g>OZ$GvGUU(K ze7PxVKl{U$^Xe@*tNZsyp42m*k)jc$FXrjl&Zo)!M83$(=KGWH`chY84t(_9sIYGF zMk}wQol@^iHgDQ=_hyLPvOIkQY34mTF&WQfn9sQ8?$j=nIjj-?>4)x&JAL!FW&et? z4PBys#cu0DUuP}ud;LBOs|x>oI<3DiQ0h(1+13iVOA6kH>+U*ldMgpX=Xc7g>eTI9 z%!KC1)}=MCzNq9P)^tK^hj{4Ri~C!%XY9MQw*9-;y)#Ur2Ur`^HME0DEZ0eFC<+gi zDfK(}Q`MK~^noa}&-4`8~bPe{NiQW2;cj=V$+kbyJ*| zOOusCxw7+=>ozB=V(&_^cSVU*U$81-5c(gxZ~5=ssV_p9nv3>JUD@)%ckf>&Sth3q z+_SvY{#5_(%YV1mFufqw=Ejfdj848cvc8;;I=<(hUC!6a&#(A3?($wvn$AU zE4Edf34wogH=YepO*DELbA6Kfua&DL4}`wum1AApCNn& z{oMTC_4{8RtSxN+$1(ZcraB|+(*0QQPgkm*BrOC?PdDsExZ5!Y0VN>%jrzp3`1rnTL+4pvu~Z;z1X7l6pPlEjXbUEr-jZ7p1@oY ze{gkh=%M0C4_CR~Kk68;@}uSTY+cbZ#+7F`E%^CR@O_~6>}jvOclH?xNQa(ZZe`)2 zoG7)-n9;3K`1OI=;ty+_CkFEyylC@kdcW@dV&00ZH5Rp8v!CblDotM(dneB7f7QXv z!}Fs;zc)-lY1Q;PNeJO0RBxRT((-<@NabkL_PBvdQj!+$LMDk^Dqi ztJ_X6qa!2NabsQQT#umbGP^>)oYCjyoKWGyLL&??~ti!)Ldl_o7ntJi&at!wr}2=-D&eqQ$f6QU)k=Tv+@ol+~N9? z>95hiFTqw2Y&ko8^W8KF?Z&fWd1rsko#ObiQL^t(?}NV=ZTvz$dJ9fG@>1BZVEQg` zk6l`BtE(rsE_c0D{cSx=^Q!E$r^O!HXZzngxX zp7&iYF*F7{%9&v5y80sbEcupyS|g#nPW4`4@&AR-mUh)T6i7HrCEE=P8Z1F zl>7MZAMYdQg&t+m54e?!s~*+-d&u8x|3_}4*h$;-x}7#`6D9T>S*Vs)_+`Qdp?+}& ztK3Tus{8tzo}FxN^sI5^i@B6ox?sCTe96Z68(%!%neCeZR5j-p zPd&%;{B_&mqf5-=Eh4j8^d04HPE>Qwwf-)3x0LDJi`LcJrmO#bSiol~-ZK3~+0Cch zI)#I7Gny6Nz@ge|Ut3%6As+@iZsxy7Q})p~!g zw27x#PVD++{~k|C;F@*!mXTqIY;2XNdH2%0t;b?@6u$gbHQ(CeA+wfuI%ACS4|T_H z%>l_>-~4;t@@6q4JgoT3_P+kklaE647}eN!E)hsGysmm*wZ)}JIQiJ(tA?D_hD&~y z+`^)sVfr)O8)n|wA&Ov=yq-R=U`@)#ecS8obV%nMBufBkV6-^WVcJ?zyr zFH~MRem}T+r{mqV620NCBW+&`y?PLFUQJx{hmOLpBkP)fJg7bRZu>DEhw8n%|9^R@ z$)e16Lu5aEAcDcH*R&; zT&eNZVjh!^?Mt2gx(Bv4O|H8(N#tG}hYm9}>0kcpl)Ylgd#eMx znfU|$ajm+-UAB)UOXI@DjfvmROsQDgJ*l=}!3)e4{<$P$c>!F;NQs3gOmfe*z;|?%y4G%Ms40_bH$s|-y@K^8emmUF{#g_m}xJCh;?Ys^JG#C96$y-}3qF;`djY^Vcw)@A7fqDgU$cV&+4uj^(Tnj+VHR13?$+)Hkg^sf=s;d_n9t-tgHr&*>->@k~fic`zy+SPJ*e)SOFB>pZxZgi@r<zmf-iD{L|CbHXZ zu#ukd@ScpiSv-^PM2V*E(o_2~%~e-patslUF;`F{S{FZ=Fqi`A9A?JDQAc-ODGz26@EoHaRj-Pu>U z3Tx|AZvB6Hzs~Z<)A+c(zrM%+W47{&`joS=#Jbn!|6w)FhJdB{mu=nhO>-(Gl$oY9 zE`A)+&*9Ph`eUwueny*KU}K0SN2bx2DO^@O4*F*N&MV5KoDJExbYBZA32d_5=vY^# zzo+->%ZgP?CHiKBENgK!c>6(cLhH86Z@czRY&_bj<#j;d{>c>4TEl{5&1}(?q7AoI zBWJdB`kX8a+HktHnN!8Z=8DtJkl!VGl^nWf&H2JJZ(OP@oy}*rs7T`(qjRMBlho}K zmqaKnI{5Wo!~6wr^>nRmUR!S8yUJsJ&icr63Tf+$OJj=n2%V8O-_1Qeqr>&2w1F*C zzBfaT$)Y>+XWWiUY4=*R&2sMg&#DXWHGF1E_`rYfP4kM4{9UuZ@cwevx%Bw3{ruGS zr{c=x+G8J3*ewPkI-cGw=Dpi^@*&rMHU9xta=zpW^3 z$4d4zW4Tx1l^=Y&;#X|Ecwtgn$F{kfR~lZaXFkj_zjEuFmOG0sOiC$Gu*)p-yuEsT z?vo2IWY3)49Cf(0#+%EMfb^wS-gUN73G zwMIJRpY1*1ykM(m;gd(c{>fRJ8(8m7IB@^s#q05#xAL6%HgWacD-o`O9SlMZ;j2r% zHh1~x>?m4rI9D*k>LGi^hVPMH%a7jQRdFinf~jb?)uL_fx3`)f{~dQ?NqNOrnHevy ze)v}K)#jWe-vN_&ac++WozC*A|ChX1PBCp=nwz-ciLvj&V^OSrch;r$l^TA(mFd?j z@;uhZsQsg<>DxPp*SyNvHF;;sdDisb+t<$LSK~W<-~CO0c=*pH#mX76Z++SnsSWdPcn8J?dC1(#t#EpBM(st9g`~5*-hpa4C98)wW&eo1Etcq- z^iOQ-yG7aW6W1MUp8VebAkUW7DclQoYa?|wdr1dytiw$=z*fRkO|2L zj%{u0vHTJCUcJtMd8b?NzlLD`W;F-KSrrq{@lN^WGBdWhCGbJpOa7R9p7qPJtQOl_ z2)CQQFD%)5&caOM)|n5d$`8prUY*mWD9bF=`^qtbF^$A=5cZ={#EO=zsQo2T<-a!`w@#RKO3Ul=OisO$I3Yd#mW zSo0&g$U|Y-7tSVj=gJema%F9w3oP>Lys<>m?!|-4`Bpn?65=exm-|J@zmAKabh}ro z@X}1>S2Y)6mJ13MIbT@2x_;5Q>2@Y9?u|{h)j}=tq0=8MSszpQWSjEWfc%|hCmmNg zC!)08_qNZ`{~Iv<*lr3qblv7@ zuH3R+Zsn(6zSC{We&2q!^IG}2(q+dLjPBi@E6a9JQebb^Zl1<%7Iz9K)kRO1%zAE7 zP`&v6n;C0PN1vbmTcg5ybGwJrCAQ!=3!WKk8mH@^BSKltUQ-1$i@4*>b~^>%L*Od-B@O9{qSNO=*6W$ok)PjEZWDg+_p1KT)#}n)y-qB>9{P1xSz)H3Nu;=pSNws5Q>P~# zo3wII${WKQ77kr|86L}QL;C~sQH{G7{o+viw!%6z|vH-V^qipCGrp_n~L|#D+|*)nRMy+AY6Uw7fL8A&0fzTy*cmgXVur585}Y zPuX_-<43(Ri(|Iv&zVY>`YDtvlA`LMd| zP3Hp)-j3cAvRDLvPh8<8#NG4rc?_$by1T+c(dqdo>mG30Yp9y`AMIFE#GSoS+Tm%> zA(pdY5thdt8I$909DQ3l_28jvd;VHvB*Ynqo#XktN!#$um0dbdrFl;?Ic98&PX0D) zLk_QmoAs2d&bQ6tz84B=bAPn@^y#Pev4zV|MX=qU{Ca;cN5WKl*RWMme%kVFQz}y1 zZ!G^{^Qn5#;_1297awrWM(g@$PotjiX0 zHWcx0NMt^8uRT8f=_$5Ju8IBuHOm{U*co_CljA;GeK^=m=)h9fM_jt+e)!lNtH-tSh?-#q#$ZWCE zEW<3ZhMl$Qu)_|8FsX&R0)E|dF!)%rD&bM?B_ZwTrtKb*tB!>q%FM$FmcX;QBL;F)e}o9N>NzRnu~3RO&hu1>0IbSXRj&Qt2sx)9!b!RMRXTG&=+ zy*r zyLZj*Z2!0CB5O}yE$Oo={~Z|U|2b7qzfW-qe~yeXzxw6)V_A;BR$Pnvk-A09b;Fj> z!}+DQN})k#?v!tIe6VQA?`ny1?tqg&IF>$pU&9u8Nz-yp|FX)>F0- zdD^$WKL2~p#6=#+#-T3XG(E&kEP5wLDKOdU^Is3k9 z-PDE0cN7WtEKHD^YNmQHW@$sX#X%Ff*Gsy;{(1UkdOy$OpQrc#{WS6C`+A2}AG9)$ zet!_Rxpb$SqoKGK-pu%W>ZZ2~(#2Lyzr~-N5xVh3 z2;bMYQ$E$*n^JJM_eM|7&35_2@9+CP|59*Z`;Wpj`(tMkepnuO;<|Rrfi2CkcR2jb z-8#~*@~xV@LcHeG1kXbOCO>%pSG6!#TKs#n+GM_CmH3H|JG3^w-8ubiSuL-VgRS5G z)7c$w=HBmBXw=@ue|Wc-?~GJ%r7Y%3pf9{NFsdoYX2AJXMXz3oS*JcY+t$K`_04k zpKjTOY=|q3Q#$jG)#GY@_sx!?cBy#1%$JTiD#~;fd zH>bPzZ<?KW{NTvQuKKVwacU-nc3D`5J|J`?n=Goo#ga!eYiPvTq5`0@ak(CZ1z6 zil_NAFMGU4X~lx>LuQ+_6b>9OSdjPkyxiO+&F$6I|EIjIomso<`SL%_@^%K7Hj7VS zPFMK(&)|0as!M-euc)8?Bj&Q2^`+O8JvEzEZg@(SW_eBcZn=B@t0_GpD$Yx6t+F)4 zY(7Zux+$U7E&bBeKla;~pNs9kZQG{fzsCC7OO|uhR)&wC|LJ0{c=7VIv~#@R`zHOa z$f9E`EIJ=O;-B{1Ioue2f3xbLW`)$VhkN($a&?yDe|~CH;OkE}+$R;D)RW~C*00L> zmzJFS-tNxUEg$OMM#vRaNk$7VyLd75;NcUod`m(?;PG8 zTgqod{?6FRquEumz2N<-FIkh&B&A)d)Pd`4sUwZTV_yu0= z&I@ioTeiK|Ibq7)&n(;L>_7jU!Dye)Vb)i3_t@CkS^c}G$yT*I{e1i$i<&#xZ-a6U zDy-NZQ(YU)`8Pe($9(lH_KUZ+Y*uyreY4b%{T=_|DqD-gFG33i_vc1_e^fi^c7tuz zI`;pwud!V@d1dQMpO2lnt6v9cczvIiv}@WE8?Q*qeSGY1iZ0$d{Q45#de6LV+xOfn z`}8Db>(;YBzI}V~Gv%|I{&VrGw->1`dM3jg$Gx_`tl-O+-OuaoY__V{h5cpZDixW<#UyO=-z(x>?8;4zq9P+ zWaj?upWd#|pIf@>mOPK-%~SIK(^*NM+@#3AIxkFJ?#2>=fa-DDoOz+od?v8m(TV;R1+2# zx6D5It>Vw(2kUz`=rHQFZ%Ec#sGgQ=c*kg$RZd;#%;-h#+~)#cuk`9<@%mhy+_};- z^5=Ku4dlYJ6{@c%R0d+mc`O^hK`oW;)#4s~qG|QWENXsDNdq z>U4XRFYm%`RPPp_-K@gAdcH zS;cyqjFayF(f`<=_j`8x3r_HF-sF+p3tw2UULTX%f(UrS;?3 zg=tX}jtKqJvkNK;>EgYzOyZM$oY>LVCyqz#vUEE&?P>k8P2xY}eV)6XQ|5|}Yc5%4|Kf&;9~68Xs;%d?-{!wR%r<}1{cX!?t;S`i!zHJE z`83(`M^=5~BD3O8N4eFXZCE0*{!Y+|XM5FW>R(HJ70__vZ1*MSW9M}Le@QMpXE|R* z>dA{eJCaW?KWtrHa;5F1$K=(HKG{b%b$CY|UT9FZCq+GfLdtAqld`{U45>Sc;+i(j zTs5&XSa_TC%)V^DkZt$2zbc-$oqcBBs=C=$YhtfYDLM1K$e)>|=JopJtRc$mZu-;Q zY!!Ny%{t`5YIkK=to7Etb?w~Idnd1}hOXJ)uf6@USmd8=bC#z3(mi2mbwK-oLD8m+ zYuhi0pEUK0-LZzxA#Flp^o{6%1AD%)*6{0AvMZhG__RC!<`G`gnw<4){1ezVP7z}M z%4^QJp@R3L_)cBRopMaq_L*;*rn_hnf2F5-+CKi&VyR|ySvq2J30PXaOU<&kMkZ$dAU1&I~+bbT|#fY zoM(Hph^$Wjjo-0+q4M7HO`a~z0_i(Xh=!es_|ALpsT5ak_qQkV55K?D{&--?|F|^@ zDw`dPtoeE3+x9+4t7^GkE`96m#;Jd{AK6~_!*Ji{udD?t#HWRK>P(o#z%zRz)ARXn zU$d-Qob`29ceC=rGh6um)jA?y-(IBf^VPPfv*|}RC1xEyyXzE_8c#x%vsqrx{L9nX z+xT~y-G5fh6T%SPk}3AEo!j8K)Vl9VZ@BlUxy`sYmFKJG8*$U}osD}u1lVF?C-EN@ zk=8!wS+vdYO4lxDw*^sWHNIAH%JrCf_wHI)D8&C?ZiXwny9^tLd3N*mdZ&~8**@NH z^t3+7bM!dRPA;D#HSyQXvz0ofrStam)!wapw_CGrO|5p|zo_k9_l0+b99qu$ZwbS( zLw);aHTQVfMrq^8sowYtBmY zNiN)e@R-^Z&fQVQS0d+rTU%vYQu@6jQ%>sanRSk@ikJo2Kk81;NRNlLMoVdl; zY=(3xmy?_3w0jPUH%!8_gF>bU^8C6X?9Fm5Ijn8%(TrQwaZLu<+L2O1+jG`*zCXP$ zzsuRBE$)TlXCtwav>TsllKy@8-?eyw{{eH|>icFnbBlJRzVWm9RVIs%t=X8Bx9sG&M=ufpLm${FXQ0OrBieJ4sS~FTmJNY z&!t&^r_a}_<*Ytvb9L$K8NLT%x1C+Kw#u0Mcm3B%0xSQfS+Cs79%~rFoNF)6knX#GqwdYu?>lb2^;*vOTiI&uX@_2>zngY$-}~`i_)9A}!GrzT$$xB* zroO**p82cgrpIaC@-27EN^T^+=J^sGwf3Oq%(%mi%u^O*3dY7Q?f2dLN_OwB8o}N3 zO25Ah-S{V9)$6Kd$Cv$GKjU0|?C1FHfAj0#Z*GsT6T9{QO#J`c|G(RB{V&`4^W;Z| z$@gDgUYy>(l4Wv3M&*weFMrtIU&0?V8Jd2{4! z?a%ea+x>p`;mPATE6YEhX9oFCZE)${I(gcgouBqDEARQ3EWfl->bAk%`?r6W^t;|> zbpHG2)9uCS`t#<`k(HV6TlZ7Lx1O`ZY{!GsCab(}l5IUzKgoYS_Fl@!vg>ZlR=| zzCYvbUbX&kJ$+{R%Cbk3w!UEhAT>`^;Bs=5rsDUDyWjs^WgwEoT5@9p|IuB~?EF@r z{<{7e`_;gM$89fI7<4@RVYJ?o=@OsYKH(R^pYP~)MgK1R^_{*-!s3*P8oD|;*KQdN#V{e8!4+XpVK$40?3 zXR2SWY~4R$>DoePxp($=f=|gGF#KCN&#-Kpk(#NY;`PQ(4SIshrk&?lti<2= zKy8;~(Sn5B$$F;0ny==?B`G{GdV9D=ZBh$+%!E^#ZiWSKdGa+?mGYkbe#2k3{+1lW zHG_r56?eX?v)g}dnflkNw({E(?ORXX3nqtWpAvUi)qZ*N9kxi}o|FWr4H98&4c(=}P^e^nCNom08nb zZgTxu#NgU_RR5ik==aNQ3a#hNV=QGIj*8eya5Nr$b9>LHNnC{oC*1vVJmJU=)Blc@ z`JrMDIkWk$KA+IN+9+whreQ3b*sBGpKQc911ivz5G=wWJ&7XR6SL8_^4rSw1re5BL z_%@60=iDNimCw##?-1tiB`HU2fLDlVeS9DrF=;v^l%spSt5V%*mL$vd=#HnX<_DNT`e2P6@ z*V)c@s{WtVTQd!m^SVjG==wFjNlkMg>FcG?{gG|Bqf zi7&yQcbycS_C0#7tYCJJQ7u=}YDsyEd&(W!EPo$2vOmlJ{X;+9n)jaQZKI;t3%tMY zGCc?spI7lSK}|?)xkUa0ozKx9bvLOh+NYJip1$SUo`Y6@KipT(+wlM2Leo^G{x|{m ztKxT+E^jsD>`r1ceH}F=V{Pl9WlwCDE{R?e%~1FKQ{STcP}L4cCFM1dC+wE3T*uH6 z<5jUIK5^lWwQr{$PdRD8`?GyjmG6VM##WLSo~Q0?I#BsNX2H}~0t-S5K5(!GUAw-f z<-p?5GcuE;9)`*Wf7!8Tt|pg*wn^^i?iR^+z@1Jwwz8zyCNA3d+zy5vpR(8y9w?Eu|ra=2b z+oxA+{(V9q(Iuetz#&d;vN zzN=j}>08|oLt#zz{1^W;;x^@<>l1v-$;;uqD#5##!%#OVXwCmQg$YlK4m~yQW%!h&~pA-4-E;!iH?yiu2(biMB zFyvX=&Gq(2_G*NgbL3|~m*XhlP57TNSEa>2d!BfG(W47bpH}1@oACw?o6_fYYT}s!%g-zanP#~@ zi}AF77Pr@Q{d#q8o@?7f%d#JfFA>Z+|NoS^ktO5S*tWdM`2ri}8{N@Y6zo-JPTDbF z+Sf9${_u*Nl25K|jY&sNXa3uKG;tK*zzZP!$DtW-T-je%zbk5q6MP@774rj71mOq@_ zI_FrduegH#^RFIqhhrjmnkGvtn_bA+EMp^cYH^}^k1>nh7DLmj?t-fCGiSX#o^$`q zqcE`!UYDJ37iv}{=dVBga%&}5w^V>``fTaLvz=!wKi@QCdB`IBkL)X#cKU65BER2o z`;0$a2259CLx1`$@|`(dFyeyM#TwT<`{S0(0-8^l6z@Gg(8%d*Xa7Vnzi5-6NPe+| z(5H+K3D4VRM^63vdRBT&{9^vak^DJaGRomU7tKp{kX~TvmwY9CWie)Q zWiNVT{C3Iy?rz>J|K`R{$4nNfEv@Wgil)1^87t*;$xpo&_IUasD`~s@D(h_5MzeIA zOOyUy&Aq<$=b7xgQze(hOHb5c&--=o@nLm#{rU4!jn4MiThtn)EuM3K`rRsZS*G(Y z2hL{;TB|xP+ZmVkB>(ub4@!G=1=xGuF`5b9kvMc@kyzRRciUf2E*_U(%=_hg*4Mku zK5KK>V$#=VVh_Cm2=xaQ(0ioqh%(?MfbMzDDPWw zN@`_0`}O=6-(^hJ?^T{wvtrkagqA&DKcsYjY>%lH`SGU2=wno_=O@92%kL&^OZdKo zMQ?lKBL}Ms1?<7*Pfp9k)O#NEerex!S9HaS7wd0ny$G6jX!Y8r`R`ng7p*v-EGiwk zV^PRN(@U1pEE(78o+%#OHfO(w>Him=*NQ7l4u?M8yF}d7hruZ=rn5eCbz1&>^C9Bi6W$E5${$~x_Pbv`81x9f-zQ+@98+i`aP*0)x?3Ao&6VWf2`P&N4wYwi+; z37c4QbGe<1RKtbW?09^y;K#n3@pgYA=1()xQ~l|_YNpY$oiFvOeSY*ly_xKhz_qrlD$ibbF}#(^bNE10X5;%mZhKzxA8uUkSh$rT==_A}Zz5YS zANOAOTX{d<`sH^w7pe#a?l4t8zJAK0rONx;j;gr#xtlu9iPHJ&R# z0*=)vPdsBi(|511UX}`L|C%$~QXRqz&!k(QOjF>G$QhXmutpn*yd%&VTx6T&_;jekG^5 z@WqWwJ(J1}Z@((H_#q@Gro5=>xyaH4=DHR35I^me_OL1(8+tX#F*aiYYG?MaUDSDbGf{$5k~UzhXR z!;LrgvB}r*xXBjmkZWm`PF2*IA#`L((8;JB4l#GHv~Crj#NXI6*LTj9w#10;t1`OV z&--h7h~He@T~o>#wzsBm`@XjP?(Hx38700wW8qu>L~VvJ^JNjI6^E<;R|VeH3#w7y zv(NEhWT0tKlZ}<7jfM3YKYsszB^8f$$tl-ohc|Clh|P$$JbAGF-$pL*8LXX>v*&aIQa z$%kL=m5se~G^^CrGGL8*vWan%i1W*1c26o)*C^}6hJ4w2S>Slu*Ok-WW+%l>KC^6o z?r!}IZ^h+Jm-cM)-pCy36qv8)k;`Pq`p%ktS@0j9F43!9JdQ#Mrfrvs%2WH+Y&mKe zG5193p^lsT(hU@jg_mAVoH1or)UBlJ+k#rQMsEI)_ibg#hZmZ+uYI&n<37E>Fv7#4 zl_RQP_W5}6)fFEum4u4sPhXKUzc@~_^-hq^y$h>5b$t#!ijX>W=k}UsOMEoHrV+uD#*TH^jqcPAP-Rf@fS)AC#@fV2E=*Up~uRqRV+oA?TI zPYNUoTO6#Av$eOguKZ`B{QccW+w$w)T~kYQ6eLeF*thlWzpCY&F4oU;VYY+k=aMWN zzsl;&A8EUmzif5iQS&WIMD9()`^l3GHq?drCZ4V=G5FxRGWfM){^1NB8!fSlH5@5_ z7`T^TP^z`L^6;(6uaoon{Q3^qCGa)bv;Vud>we9R{XJq8U%ou}awUE71X0B=ZQJ*} z4)JWexK}mn(iAzN=RR>CO#dG3S@f-F=;RseYWZ^Y5CjBmAddOTB8B-x%)y!!RN5)p@<} zkLR1ju6vtsHbgGuvtRxv`knK-cXkg1f633-`pw?pa*_O%%ddUfmf5l9*G4k`Pi8!7 zrn^)B%Zl0<+m!S@OR_Y29G5tMz2$0oFn%Hbgw53p%sHlSU-{9mOS?mY`|=A(IaZaA z-PQ>+!;|CZzMbyNRCZDIp7%pVgD-h3-_E>`tNZ`=q35^5pP$#)9MI8?==45(oAJXL zi_S-}4|SA-Gg5tySf1C~^AppY729h&rJS6ut*(i(Ik5c5Ja=W`$#Kqa7J4sO#K}5GRj;jh zrqH_96H<@1t1zz0Z%?dvEcL)kxiU<7z5AX8#~gFRK1j4wI9;EeWm)t5)TA?0qb^+3 zNImO)Y}UG^lk`7GeyJ5zIUV@Q&gjmiTLF?P-iy{vj;W3DT(ZgP>S4o_e(SCGm<%sp zI3nN3wW~{X*$al}1&sCE#I`9O+P0_W5qs%HtA|#L3-8xF=nLDr$Ykxr&E-2cF{j!5 zn`ZK29`ETz(Ja#3Q+_0!+GTZN?~W7}!P1%Qd)#mKO{wYS-M;fkxf16IUcGx$R%bD` zTJ(J3I@@w}(!&LJDhil&wqMYAt$J>X_zj*(b)Pp|yt;0&wRNx3H_^16!F%gg*7gN| zZ;wW!@2nA)D(V3BD(qqMFysea9#uTlpO zy0db4v4N?xV&`j%Q}4Kj%N5-Z8=6+<-^*!oIf)BJNeO zdHdX1Ql1sLTK(>xw`=}yTR8J$+MNg&XZh8UjVap-S1tKE>qmt3V{Rs%ul6E}d#?Qw zmilrkNadX`$L|KET}{E(t6%&yhzU>4=uuXBa3GDNb7hjpvi+MkeGEzOw-ESsc*;+Q zr2dERYft@Aj-Qp!YO^kC=j%hfyhm9N)heCsT=Q7X?nGinkipbjLXbRwEq=+zy0b`-^#A+XoIr2itCm0_kKK{ETp)gYx~SPjU$Hk`PJ{IH^((c zOuX6T;}i1#H`=kGhq?lfxE`kak^KD|{iN}sFqH z{IZ!ct1sv7>HkT~Z8M8DSah%6k#rjywHl7Zsk{-Wzu8nbk)T z{euw!lF@o^EDj`GHj?j{Z&tTUJ zAB2_Go{PN2{p6$plf}HhZ?noK7H((=?VH5UbM`bUadN1E= z8TmWu^R+$CZ2OulY=8Yb+OO`mZ&g9av-I4E9QjwlQ~!QmEUtfe(F&v-WT z(Z1(tCyu=8M?EzK6n-q^hK*QN-4#SQB}omNgM{}8w}QhV#Z)W;67 zuD@!py{oM$`|$VW@mri*W}f)4EF#wOZ_wOt3;g)!xLWQwKH=bMp@j)9>{qS-zAU*U zZFc3lox6|Dw&%HLt$(?EKE+Y-?}g@a34{Fia*W#&3WDsvJWgpSjjoV?Jjs&FUea$nW|vm?r?S$2umJ3li0v~y>!R&HNT!HXky0sq#oe1Bw>&pGC@pNnOf&(8cL z)-P3e^x=jba|172?y%c`Kjgub)tvz~yaqxa4aGi)o@`a#75ed=L$l#8=53ds3O-F) zAEnu8`Sq$#}hMW{+^Iqd!XkwV^jMy)gNChR)jUhtU0r5g_zsgvYg+v%kHDny^U-Fdsc@3+{F~W;KWgdgPB5N z$2hMoWZtnOo$HOcFFohp38k{Y?I^Zz#=(i zZ%%1+GSA5y319vx-ss)gQu<4GyNjslnzXZfO|=fa30@(w&S8m-oKLVqr%=W%#(5&^ zIx2M%BgzshVm~y!-@$9RO7MP_lCZXVP{#M?<*U;HlE;1=b z+t=3e*XPZLIX!f>3wqhxCN-@t_K0Gc^E9{4ye@ykv&_o}19#3}q!n=`*W{mA*Qp=h z&W8Cmw=l1sJtcqo%71>3d}GR887+gy}P?^#uBbgpx`{r)F2YV9Aje+-FRKdF{CMKx=3X)y#@XrF!T`SZ>zt^-E@wynHgr~T~3 zeoe(IEI9`lG7>VvEse`p%T;$DJiy~CX{;2M`f-9ylK+P|1^a_?q5ssjM7?QP9HHbc zd}qc1!_!-@+?q1=_YEzkzWTlKd}_i5-8z?l%@bu0`8r)OG;Gmbg+0o1)ow3zJ<55A zO+!kzVn$2y@q~SDJc-IX!%s*}IeS5?=P>W1S&wy(PgT?1>Uqa^+f#w!pZjGD^H}VD zsWSg*no)l|Pw7WP#OWjVxK6)eu+r4n{%PmKyewJCqZ9hfMfaq$Xei|`&0ZeY{BB;r zm(#3sr3^Vax$D9s*e|I~UR9ZQT82gB;-R)fguaI|FGA7-j0iJr&NlmAC=hj^R(tBot}FOu5}B{d+}h=PvN3a-E~~6OaFa7`A}G^ zv^sX-(uM;kKA0cA7WU1$rJ*%NeCuD1X*d3cif4as=PC?TT_fN+pRu{GR%)Tv4~Bw9 z77dPK*9CTS78ZhhyE1g2p*xpl_hs?+{uADeb_hA-rNh^Dq|U5(Gc&Z{qm?`NkJ|xS{_8(1PEn0xFvzRqoRPP^ zl9#_UcG0m7Ob@xTjBL}Vc-Wu2_GT~ttu`+7=oRkqt43S=r%xi{rq zE<42il}E0CY5CSG|8Cf1cQ2Z8F^Bi^!$j@HOK;k!OYZ&KQr}%FyH4Mpafy_ofWjX& zZN{@QFE22kICxrhn&pgxj(ZoMa(&p;w$1OtD$U-XvL|!J4XUJf*07$dNOPILH0ATu zXHF4ZUiK9`6&yI0$_6bswEFC!@V84}c*^Bpg#eijxYxuUluUo%!jcO7{BzJ)2WJ8vpmy#QM z&0eNh?qr>98=mMtb-`RSPtR_ND%U94>ae4{eK&bbEp+c%XiYE*3)rh{ec|H#$pv@R zn3hzQ_&uEQ<=YSI*C`N-ha29m3PpZv(@6hwv^z5nYX9yl3sOo{%orZE=IkW;x|h-=iE7P@8s#n zj~73FKeujUdDgrq;_dx2%N7Zpr_}=V(?s~6NXwmT-X`hD zG2zK}i5;#V8y{}hX|LQ}uxzcj^g7q*YQ7yYYDet##n)X_3)rK5<=ThWm;5%@P6=3H z=u{(||EZ`haPQJ;;d;)U9ktA}w|4(xyjj%N7vH|7_JoVV?!{ia7$>wd@6o=(IBT6p zp8wCy8)qcneJgoqM)2or@~cWuGz9KkKj(9}1lPaM%M8M|*-I3?k>$TPGyTnsFO$9< zIV-U;fB&|{Z(KDeZ{Idetuc!6VSUBrFG^loOnKXWKJs8{;eJ+{GDEm>mC~0;oqNkB z-D6vSZc?KEZf9X`}mCG>YiW9g$f!NYDw4>g+EULBo!u&^rDCq8|W-K@?j zVP56=b7$Q;f3ddHFtqKX?sK6xJl^fv-;0}jm7em7_$^Yj_*i@(J%#Vs!7u4+?3OSH z{3*S$Y`0o}rQYN76LikpYuXhh7u(PDo4@3AQfQd*hSqcMJ@%y=%z1I+gs`ZL zDQ_gJ=;5n#C0z1$*I6TY*q2y7 zw$Sj~b?JG5PVsB|KM|^FeJcwVI=A>P`cpB-eQn?V+;6N&yC+OI@y{X9r7<)rY(ii6 z?9Feh^iw~qTCvbijX#D-WVX$F$2-hhqwWdLyYr3hQNGCL|I;@sya`NR@9|6Q+&Y1) z6FR2L?0WIJXL8x<&rf^i+)(-Lx4QPmtoD!FN~X4~DBa8DXyzO|)u?`7^fu3@W;K@5 z`?8ODJxn>9aOV)e@+#4MHLHUaZv-j}|5Zd^UAK$1MEsrzmszO$?(AzPe{DGSQ~k7@ z&moh@t~Z|ZoF1y|xvgmbeU`VtyD3FyosY&vdp~ZUSgf-**;jGn$@ZJ}^W08++IRnw z*>uw$wP{n%nIy?4C*PfNqQdk2MK0~I9M`@3>Q+|8iFj`|{JrVjn%;V@#2xdLY}+<# z+&O*VvhQ&VX|5ELL#NV07jI0^-oX`eZe90Jp1Zd3zdQVOGqmK+M1455Nay|}#Rm1i z$rJbcrT?^={)5BwR7+U;6X%<(@3uwlbz3KNc=9WeNWW9A9Aae!(;58L`#hPX=UECr z{t{WI9y$HN)wU3;2tgS&qn@-qGrY5IxR!G3t7dU9ivOFo=~-i+%%70j({4HG8=7v4 z&wadL;*0a;rI&6BEcnIr#pT2{Pq|sTcPD;6`n$}->-;&r*rR8zNgrrWnd7PRC~VCF z?d6{tZf?odlD=-c!G5XLqk`Gp-FE^T!#~l@@hBZmPF%nWygjb^Uen`9HrOZ9f0t`M>G&-@lyy z?Edum_1}&z$F?l>%jffTli&SS7E53j*Y~ae{CU}&eeY&`-}e5$`QP?0D%BGX?sYOv zsS8Xuzq)3|0;|(C$?wgdrweTLo|gKlLa0w+QoH--SMME~O~cqE9E)C-k=cQ9V9=boGEdKcQSDN3QB^B|JQIit-*d-p@d`(nu{I4S( zx%gOt_6EK7k1P*u=gnwLG`qiSnWgfl!w>R#*vlvXKii?rvx0*om)G{gd#TVj?8{B#w_n=cGaJf$ zJ-#+>xm%o+S%Zw_@!VVW*%hkOGbMX(_e?&m*>~xl{!e}RuNx#^Kg#;(kmxOVOCp&0 zmVfUI_9#Q1FS-HW6U8JSolpCjHSOpk?&Z4}D!f+y@LBhM&Wh5=H_lNSb@N_daQty2 zFK6qV7^iK{AL6yduTNNGU|z1Gqufz&Kve1&^Nomat)~O_&s*s!xTr~ry{m?maZPpa zq3QFg1S;N63zFDXxc|_LsB5uF#S7W)1?FT{oL<+oscp`*V>(u~dWMo`rTXMj7a4bp zuDUkW<(Aq0KEHssTYBQ}h-DTxJ)ZC^IG{58>|aiJUvm;X1 zwFB0soh`n(!t>I$!=f*A)&ynd=&rt&-d^;s=xxZ3U4|~l+1{3fO}v~mZF+26wAj?! zeG_{;HtNQguL)6kw__>ClD7x{C`@CSvH7OipN2_|$9HsPztVcic-5U-cy72$X7uFT zB`RTjYecQ5W=DS9kkez+lA3hgUT5=Tt7NU+(~?;HH$Iz`Pg!d!zdc!9 z5oUZUEOFl9v%fxRJBlso@TgcQ)^Yc#SLo%^jq8qH-#+o$>1Fa=ZkjXXLj3MAZcY82 zG{@i_cjAg2=Kn5Uls4+^k6W^QfpFZ`9eqFz+bi zZzx}XU9-)30@J|)kI$#pN^7m(p(Alae8KVgI*cAqd>v<&K9>xe?!rB>B`bjK_rd=@ zVXY5?H`ka&FDwt+BGk{kSNF;H^S2kdUD3EPFZuZTeUI{^!cya|<^`50e{e02t++Rh zLuH!=OTZMVL#nmgw^WFnZ8`VcYqz{xp^3Mqgt+0lH4J$ITUT56vnaGQ8Czwg?GkP` z++FyJ&EiS&)&E#uB+ePQmJ?HZhh&wJ>}jC-{((u$e;eCQrA*(t!T-D3$B4K z+S(;k%tPd+O#Y*ouTZc4W3ist`=yb}2M=_2Cm*ef+~lrh>N$VQ-GYvPU+oX4dwUlx zn<`gc?;v?(*W{J4@22_o&gE>=>s)u>#m7H#E{pSa>u#t>Rf(PbDTpyyto+2=!j&#Y zN^d4j)jiX)jMwWz@q`^`ZcY+vJ-(D^?{5he@xpf0)qF=7( z{in~1+70aPM1Ejpw$#>{cYR;m(mCyP`m0JzV?*1z}q|9Gq=o1VUur} zoBGxC1>=+Ie62*IXwI5X#u|PCDhp!nAC;QE{?XfAGvePd7Qbi8escVe+S}_3ZZ6H% zytn#!NkZ^)R*SuRAJ+c*lHcOBKNx7*?#vWph(bC)$`yZnMtn(yJ&CGqdC3vFuH zCHcQOH~1spB=h+!%u~9*&N>_Z;$4egv}u{o!Odr9mu_TyyX@-}6@AT~H`@w2I95Gw zExDR~_-fDY^mqJQOBHk5?EOxzoKZH{xcY)=`%0U9;Wtd9T*g`QywY9y?-#MN zFU2ZFFQki^^-S^pdN1`-TFB2eyG$Q7SQs=NNnty(v+7LF@~nH8*Z$*}_~q0+ZlNa* zJ(EtE^$ikYc|mz!;U)|uH4_iv8guDT1#NA9Ov$;QQ@Z(~`pM09a__BEru{Gd z)_2&P+wZrYMA9>+2kA^DPiNbHs9Rv{{9(?l+YfCvvduoK%l2gbs;#U=LjLw;b3ex1 zm>{Re&9*@DN~XaYPR&xml~ei7U%NVM%5+Jk&c-6`4a2lk4}jtmiw(+mpKVu{dPO!PpQIp z#doYN!TJ~LxtvqDon9!`%Y9jKP-Tsc^q(tE0Xbrs$rmquNQlyy`hdA<^2QHG?OZ?I z_IT8?ta6Ilu8C(h9e#aPtu8Q7S)@n5bN5a&{`%-Wxd#6e{CB19&Xaj@qO$u$mu~j~ zU*id1670QiZ&>_(`GGy#yG4bS*BlqK>Yp>q`P8wCJ~OkM!d#4^Lj_Krx3CstklXZr z2ES}CbN0)aM33Dcr*iw`95s=Ae>2CqS?Tjk<|sbJ^vMT`r_A=6WyJI-;)ZUL;(o-JUgXh4+R9LYgn0C45x-Vmp8PHaC;HK=P~ubQo!BDeaH!a9lOJB|*K3gN$ZrW8MlxuCV#^l!Q1 z!KNz>TY0zM$=i8fTm9dC6Zxz^`x@iwg*lfq9lDlv$**+UtAxs^(y3y1U(4;@S9^Kp ziJbf1+LmuO%$AyS#`|`i|DjV|qB$N9BMY0eO#B+>R%}R5(|z_c$<$DJSIq4f&Pg96 zKjfHK7_)5@S})<^Kl_7!yZyI=?D415AIzF6bmU8Iz^*@hav$_}-D$2~u-w&sZ=}ib zzgvG7oIa48kfr;U|2^Z3XXXdF`2S6I`4cO6<+gE3>%BN#?pO}%z0V2)6PJ`$_nw$Ofs13EU@eDU z=gVbgt@+}f8i9+FtR_pnnX^n(FP76b@Q!=F&FBAbcKC5xY5cm`YP&e=yhv28*b0%R z1sh6I?bhT8aVIs+uo3Znxk<&bsr<;cr91O-0`#6*FehX-aC&E7aD7(#YXL)}d!)R4 z&)zxA4>;d9F1T^zaAC6FBi7q`KQeq&W^R3TVwMiap*dZ5En4)qT=GsVe(-?*?w%_R z=Z{y-i1;8sVU4Um%UY-3-?!L{NU0_0_H;Q-{q@kOT(u~F!7hbu+h%h$K05!NX|M7o zfrmM>RHcNoG(YhbHz_1dotD1x^7W{V$GbGwPFn8mtj78J+btIN!_p~(%zdGp|j&f%B|H$R?Ezb_c` z;Ni#Q_r^x4o@VCt1{z)Fc6(N4d6uy}oIj)CatW_I%$x_NB;QgM>d3s`v*2XL z#)$pOncq}4T{_!u^-B4U_>%c~KAUcy*&8hToA;Pm)q%ogTNTxr+@Hu>CDu<|*O0p2 zc&Ewp=p}n<*Lj_?b$R{H;!4QU+0&lgQ=PwZ$5e6q-<3XC3WW<~g$YXPK;! z?J_r)-`nTQUA!9ljm>`Js|VsI4B1cU`~J4vV!h;l+l?{@!*fK-VkXN-P0eD=J~er31s{=F;G$~FJA2Q@RK{%O(btx3|JUc1G|ecReX zt3$i2&Q8xh=-(X`m&Q?dLi4eRs^=C>TNO1qnZ?;Qp3Il$nB3ptZ#VOePd|5&S2NG6 z(wxX+E|F$dx_fg3w~DN2RVkYKd+B`EZ6&W8gxhO2MZ`Oc*1m0AaK>o**C_p`emmn-_x`egz4TYs6< z$Xzv|%}=)&s$^ae-Nf&-X2tv#eGe%WrZtzDBP5ivZ#eu=RG+?K(z1z)&bucT_DL3; zb8wyAgl^Npz`w^;5kNoi(t>-xhe z==Q383%_)k<}0@kx%FSvo)t@HOq+0C`mf`b%N-1DXI*(tDj!*z6}#AtFI%mJCw*xc zqvA)WQ|@;r@4t{WH}=tq+-}*^k@qb0pPb_=;9IwS=}bHRzPb{hP)^D3i@$HIo9wsz zcJ7n?o1?^o?^*5jc=hdT>BP5H3lDGFf6w{&pVwAzZEHV$s+i=o=ViD12V>v)duA+= z-}m=v?ku~ix*9ggl|fwYPwkY>zI^lX)0>6s1e8h*Cw{exefz%t*VE-M_b(5xH~(L` zWBd2eZTsiHt)KX=-tgy_&nFMBztsQz+xKsm4!%q?G?HI-{HnALn}+C(FK0zW1m0glMx(GFF~7$F9Ee(+dOZy1KF(>s8%kxOVBV z%$e%gBz`#S=H$i8+b29vyz-;1L|cE}{JsjtJ^7BullD1(&G;d^#?*ah@uh-}+Yt_3 zoKwYRj#a))S3Q3GV$$Xv`fYcle*JYix40#tQsMf<1zCr~x7cyiO~2ldF+I3I)-rzS zOTpGZ-PufAoa!9Bo9l0evt4?n&k8(ELe9ir zGahpCdrz3hS^4H=O|$n@{Z&Wr@+Qp7=$X5!Bc zXFax3irD=@L80g9dh16gKNj2E{Mg9MH+@G?v-Y_&y?s#`@{g)}4Yq!hTXEh^K=OOH zJ4;f_^yojA%ItI1+xzFum#F%|G09+$h1I`*jKZ_8w#9k9%(n>IIWMEMs7f?%nt%t# z>PDU!J&Bg7`I;r2pFbbI@{hamg_p_6W1^?~L3m!_dW`S&c3NNc@POFpGj%DHV>}1@8UT>QtVHvpK zm5KG_wd>8hub{1iIY}(75 z@+{G_n!7e0_{Yq2RQe3Bo97(Q(~ed*-e%2g{PBC)soA?k56=>|us?X@tf|@ymN*vM z3)OMlHSbi?SVgjXLsq|FSY}pt^7sPHcboN|7BRncGH8y75VwE&D%a?#LI=ZzuW#FO zvzt@W4nH%$T@df7JTZ)oDdv{g{Nq1m?gk{M-&A{X?cUq9y(s(kiUCZE~RK@$nm^B z14;2`lLS;G@0cIndPnlv3tow5e|j$MeiM=tA9Zg1-Ys=C1p-Rj9t$nx^oxpGHrI1r z^i{2U4)1Qa)E~FyV*J7Cq3m|cCN*=L+2g>S2TN9HyDoaRr(9{i{`#|J3wE!V#&C!G zfTy63p?k094w1t1V)@^VuY3GGP_4K#>iXnv*FB25@@0IiR%@oMON2^1D2m{v!3;&#~j!)_m_T|-^6bXXT$V36xr^4%F(`3|3*Rh z#9!wXu`y;^TNutZ7k)~-RH+nwt@`JMxL;v6+Sff*SM&OF*LI!prQ6$PAGnwHCVlVa zy^=9P|IYO-wRYS7wXN&qk?vQre7Em!ns)n&=_SX4JGHkb2EYA1=gADs@UG=D(vngFFZ`v)Ud5ib@yWI-(X5Akx*%(o=y61K2mHSBzS>A8g{#D<8 znk~T5+9pn7n!u@*GI3|@W{LMqTE$nGo+CDO=EJYjh6TFI!;Ubm_ZG{V<=vB3AvwXQ zi(xV2)JfI3t5*r$pJj4Ks=u!Nd9U9(ucdu%iEWoZY}kG0r-;6xnG4(Nu9KI9A1-`3 zrQBRR|IorcYfkT68Gb}DF2^ZGk^QQcvwf`o8HWk~52o{6uJ3rPaoJb-2XEYA&B7$H zknc>~e;yoYWPixU8k~{f@j&xa>ctalr`>n_6jw6EIA&%g|Ml`Wf`X@~w%$K7IrU>o zL96_dy6AJ(eos|5*?LzC2Tu0%;Juu;J@4#he(kH}n!k2MZEu-bvEyy8_veK+^7-?e zv?ZHQ{gGRcJz>wITE2(oH}@XebUt&Xdl8S)w#X<;>)pp3lAI=*pN^ROZf5YI^j8we zyB}H^o@%bV6Lo#YucO-Ox8Ij7-ZK4kY}{*!rlRjg^EWwnmZ}{*FLCqKtHiZJY_mVF zznbu%&x_f+NFprP=66~C4*!UAZcFJ)OT6{Tmn)%69M|^0&W*IFgJ9i5_V_}glpC%f~ktP7XIj=#P!?fCMP^3%TrSMJ_BJLgUElCpoF+18t+ zt`Sb=vAShv!+Drbt>?&relu<>M6aY;yok>kgdP+Q&Emu}Co zVgAO`Z)Yy;`7~rs$@Ns#JZ{mCo4nRlzbTtIE%SrOYn2J#jt00i=d;Re;8e}XymRvN zL5{M1t9M`9eq1{g;PxigdWKF{w1k6C;|bXrUuU`-oIkNHA$E_Lk$u+Ay{0GJmvi}q?z8{r4j=q(?H)fnFUz^^)q{llo72}%emE`I=A`E1KC82;+|y^9mo(jt zjGI;b^6A$#5iE}ueb}4)LFz$M=kl7Q>+d;O5)U6@xE$-&%E{g&AgXa^Wl{E}g#r`q zN}b4cS@Czv{fN#Ir$cl0%jy2F(pUU@{14x@7fHnKcA#d8*?(GxKS};dEJ?q8y`GE4Pi4$dY#acffcxia}V6Vlr2bbhd z{af&zW5Vq8Ox7~dq_ygM3r;I13OEY1yk%)zkS=L5-Eg_whSiJi=JMQ6_PG@Q>0Ygm z>^r}YOO-O0RxZ`tP1ZKsXMH#nVk3MnW zneUoeUt5pf5iavsmT^FK${8^O#`V0~+FGkPCSSNSWrE2R=S(ggE}Qk6VjXV@yxSV( zZSp7Dgy9Pl<8Lt$5u>9=XCK&q=!nvL=fcxs6BrVYYCP!QuVqk~FC4`q{`R5VQx%oo z)sH{PUYk*ok<{k%VcDaeS6tyb*VNUP)GTOtBB--VTt7|t`vmKbv$y(wR*0<;oZ$0r z&i6^5y4lYbGuVp1HQd&0S#vsDAX0SA-WoSojjgry1}V0DPnYyQPG{U>7xegwKL=N? zx5&?|$3Ze#2EG_eq=YG30D17ywM~fab z`8KfKchz|_A;ey;i|yFs)8czrbZ3|w#4MEO`*PPl_~Wegr*|HHSMdA8*X#EVIcr9K z`I7xw(B!U!(7tUFpM#==jvmfryyNvj__?0ig-g?#4c#|zyuTCa>9i{$!TijMo3#=; zab52Slr7pcg4kCyJs#d0?M4Pums*b@lG^fv7ULEW9-j3o4^;byv+wgtahB4 z7%aa0cMYHR)2+uo=i4NDZQyz!eOv3p?yZ+_%#*!WqVM*@_54f1F7W3aEH#d5Y)V=&wP4$hJIutc8 zX=XB8-u-p!@|2IU`JNBwEwR>LIQQE5i^*3+zWYjghB0xsz5cp6zsfyOfJ@Ey&DC7@ zTh`YOr%V5-fM566K23^vwRZ99146PNc=ZydOw-lB&LOb% z^-7`Z`a4PzE|e9i?fK5Qd6(8Yh24L<@&%qw?Nnpp_u8~&mBeI&$UU3b@^*Um$$ki3 z@GaFdSE5SjO_JU@BL*=K8NFJSKZ*N3i6*_1%&wTa@V()^#;jGdxW3OQ$%>iLCnUrE zCqZJN!L7oGe#`k?k0sWKy#f>!5EaJl1q}b#+IsUym&t=j4EG)**$NQDSyGGvc3ylBs zpZ|YuRj|bp$*9io_p|x-S^xiixV<{Q=H>JH`W^pY9@hVF{r|VU&i~&lZ-1J#@xuJQ zHDA6=zWiR!)^);ZnUg+QFMA$jf4h?Svhg2pEx)F5<=&kPLUF}QHmU?Q3S=DSTP@(S zf~QnaY{EeWgO*R(`o_nP-3hpSO*ykYsmlB-o1&y8TYRfw((W5v?H4EU@2zlu_2o+n zbHkA`vorG+cPx$c7Y^TpRP3vO%oq+UNb*TA!5&QaN87mnBP zrM?r`%W(Tf$8VJ@^A9>0Jeu}s`I$?F2lNju6ne&ZXyaLfV}G(w*6|e{oYUyxR>!Q9 z`O$3ty4Xj;4ecg}EhD6&n)PgM9OFOA`)T2_$Jw7F?gVbJQQJPfYtQO?LN&axj&p3x zlES^OZ#;hK-T!{p`GsY+2UQn;&+y&7+-BGvk0$ah8&6~{D?5t!;OFs88EAB~adtvS7ndd&TN;sbQ$ba+>NBT=e2GPrx zbuL)tu4kW>n$WmBXOZSTFR!qmX+;_4>Jry@3zkJiZuyYi6qWZgsBZfDkJXpA_C4P) z-|V{B**)^>>4k`h+d4GhP%phqYEZhIyoN2#6M)?VfJ9 z>`~0U)OReFFMbAmVS5^M?7}Otu*ZkPU%1R%*TDME;fa#5Nz&49+pmAJe*NObR1tqR zGhLxuP8OBi_ubu&q?~ZfcWjkC^4dA(-SznS!BHX%d`r$>UN2eYXt4I={R1CT>yo!M zE&s!8+$H&?C~U2zyUCh_O3}Jgi5r*9Hwo8@J<-shH)C$wZT`yrmnwhm@|d5ReB=7< ztglim@ydG@f;tsBC$N1wyfIPap;|F_*P9?UsSi=w*=~}R!Pgc%kX_!ao?x1?oTH&e z^TFT8W*Zi{&iGm2vwGSp6V(s8S6FQrUmOU?*<2fRf2UiL$f^tMKAViDZJGA(T}P7X zwm8kTfyEnNS{cmZwb*cL!PD6_Ctqp@EMi4+dJ+${+HZmY9VBrtN(0) zpOy3Tsl`fjoX<#i#0u(ekQeJd@NsIx50}Mu3NMUU-d$q%xh|;H^L&k&{X2>8O?TXi zD~dTUUyeC)=Z>g_>6CQ`vX2NXxp{2Q%EenG;(IU8i@YiG$dv8phW53GKIKefsC3e^ zIb2d3JxlwId2r)u;e9LQ_x%#!pZ_n#K#W7#$!}u$g{#MNxX!3Wlt@2#=Vd%yyW-wf zd&Xq-!noZ0rC+7C@48s?Iag}RGkfvP4{fzXk9=VHrFX1)o=`}a$?n7Nv|cmR`fgWs zDd-MTmguXFVDIw&{33Y4(vqWZ@}2*AY3eiyzsQK0;d@01mr4v_4MkImU12u=nOSyQN!2vlZ+;-cI?sI_m7jl8}1} z@7M!Y|80-Id2!Rxk5YlTXQ$r~J?Ye!nDy~St7-I__QE=j+XoqI7F>VQe2ta!o+s-& zNA|g|CdC=vn{AR2F?s5G(Y$o^yOL$%nYV97u9bFuJ8Sp*Fte-ACNH+Px1J;6_|fll z?++>ahQssb?yLFu=*fpKUmSnscD*V5w@fQNCH>f!D<|yZlbvpH@3AiBY&N$!pnI^` za^krSYS*6yD#xn?dM~)b+qvfgvynt1b0%Cy-BTf_FO zn~*kt-prde(&{zW1s8VPUbGQY37^AKWVWo^%CO~*rF&H3C9?|&Q8^d5A`X0sxP95M zYT7#Xve)uQ`WE=hlqU9XsXf4}ctwS0-sg!m6Syu5r+Y16=-RH>-gVcw#?5B!av6QhzeL5~|HxSTeANQ00Ebk*Z7MeA91^cZw=r&=p?vN5b6=rnNxAEM zrZ*}|MEG|SjZ`Jn~FIV5&yQ;=wp`DGAXU%hWXG@S30}c~kyMs&b6rqdb4;+J$8RoSjS zzjmzi)5^@esD5Ln*xUn`+l3o$ef+tvspi<`vy&dZ-oak9V6)}w3Rl1Gn$$kyz|d1S zp6EZQurd2%7PFzS>*t)0zYYrruQ_GzdZ=mJ?v9tu;_UtZDn9&u$oyoRe1zZY#sp?L zTRWQ>OD25R`}=QcSDp`xs_i_ zoGbULim$x&;;+UF;Un2c7o1%;b&2^g8>LoT){qHtPkUrouX?NIAKs)TKDVUe=P#|= z1Kqz4+})Q}==pmw)4T(QKcnqLf3Q!VvPJQk!{QpRQwj6QO zeLu(g)2U_EvFkLy+`N4@HE@sGyAoMFqx<5)Gn?4^)_$^1_1%(pKe&hagZHcXk{$;| zZC;AC9W=U>nzeZEANAR}_Yb<}v|G_46ykg?1>_4v?+ zSvO+uMEl5uOxb$?;wvd92A4E=`pKpO@vr2?R=--P@-r;@=*N!^=Y*GL?%?x!-0|$O z3(vhaVK%7-x55`X%dbe6S~}M||7LLKz0av_ljgdS<>%x-qCFng<{~$JZfez@(1`nd zmURxxu8lGa``=U;DAi4Nx#}tI*7|g6Ntnywwi_?oRxiEI5qWu1`4MZQ=^O0jA58TB znSI0R$BnGlEQ{X;X=-asRG;j?B9RzuUl3gof6CQ4GSOYT&OonLG1}YSL(-w|TDebF zmtmT=Bvb#rRnHAfI~mnaREHG`Z13B;vBN@+o$rL7YE%E4{C~gi|F8U4|M}CS$^U!o z4xD~}`n-Mq$Nz`x_x->BFMYngSgSDzzU!9XXNN-geqXmn$+pV@Yaf<6lSrpmXa~h5w(-$??7B zTvGRR#?HtIzRPPr8(b7Rx&4XL6R}A}`z8D`Q*P{1vfUrIe)?p8yPbRY%Es%OJCkRDUTw{FHl(X-djj&UvQ~Pd5Jav_aXo>)qL1yAGxVWcx{^nVpDrd{M&tPy2=R ztT-{tV-*3@*4AkG?b34;OskvaI8E!1EU(Ri#`Q<_c4-~>x+&$|T$$xro7OumTXXCC zj>T+xXQh%eICm`CvE<8V>$x{Lk8${&Tx}iHdr9H^LsLWN=CWUtPV)#APc?rkV>0K# z^4aqihg^1Fo;1h3u{-6}gqXgy3>l0yM;wnCwf*yWy6t8|1App?lWZ(bKSKLw)$M1A zeX44CSMkftg}FPd_Q=iPX%TO{b3NRnwz)C%OK*@rmgJf9U>aWiP)T zdUEQSLzQ+)>~D=|*)>h2z0F)t%FiA-Sb2Db{qIJYG6+s>^fl-|VxlNyVNz`1%x0F%r&Yeax}so`Oz;Hf3*xrBDpu!*Kds`uy|IBW(>5df+4K_8 zlihN=7VYPaWWh-7e>k8-b$Z;O`TqmQxayqZ6m2i=#NA-sEABTkU0QiDO-xmk)5e;a?g-w1B-+aa}#+2C@V;GcUk)2eqUFS+Ux`evq~c=z9Xd7-=8 z3{HoyzhBETf6{u#_nbORt4;*UYi^!yemd6Wx8O>b<5hv&A8u#GUq1WDJ~^~GQgUDQ z_0YdxuWhw#`>|`4XvOrYPhamb=|82u`VfDVtCLx2f$G-Ni`joq@O^%BjgfU>@l3vH zD<;G}&$#o_HtF5hJEAY8H+}0lGDY0K-|zf`nHQ3eyNw(ZJwir4wZjgt`=Oqv^9P8VOE33>^@aZ z7yHl7l_jQtCEW?>M9~|FyTSi#enjWx>xoC7F^tZ#=)7us- zKgudA@>bza*!I;McZPGkpLkKt;gDv)vcvi}3>@dRrgMcKTg`pwxZ;x^ww5(Mm)N#6 zuQ|?fuApsst8v<*P{CZ@JyF;0Fh(g@{JgY(Z|bBN&MWWlX^48XX&ip}IAPfdk?X9B z`=7pay?&+Sq1~sJKjx7V3a!r=?bh8txMgM8S+-7T4vjf8SM#zz+Vi9G9>3bpX^(uq zp2_Q)J^%T$?(SzPQo@S=pL!Rrx@9K1-@@lvNpYi}meKSt*3%0l{@GOgx9ptz`|k6p zjJ7}4&$wlqw(ao|v+meFnQ5^}zXZt1_NLGmRrT{LZ`1T0Ox^Kvk6c zghpG$`&AJVyPPjvIm(s0a_!WVMJ}$yPXo)RJW6M;mpi{TYfj>uy2()7$aoemQlP4la54yk5 zZM_xxVS~2g{_Pq}n}Ut5?3NX~sMMoleEn#hj)I><>T>7Tm7;xjtMa3bjx?JkMSK)< zb5$0d&eheS<2ki7a817ArP~+hEf<(vrPurIr2RIwP01|fK`w%>TG_9Ext_RRuz>Tg zwfw1k@wf*L2KRm}Jz+hm?`U>R#Rl)@`;qs*+}XLZoR>v2Rp|7w1845pg!{S)+|w^H zcf4j_7UdW(5i_$iy|Mcm)BT#+vkK45W|h)7_<7IHrgPn84b~@5vJ{ta9E{h$pnODb zbDHpU)uSh)tnDt$@=pob&FQ;w;n7V`I>l}HO!L=yWzRD|=9nE*a7x|yz!D=7z z8!zQK|Gmm^-SKSX)sIQS3Q}@$ay_^u%-zr%%qwB`Q&g>@CdkP9=5)4Q&dGKdw#L(D3=&zF(S*v!k?S zjQdKP)=!^4tJicv{`Hkot9u&6o<7ox6n&Pv+VEET)Wx2Hhdm3vPn_#_S^VfLtN3dv zH<~WkTrR(4>0!3~tk%V*4bjRDy$#L56DQ1ipHw`x?&Ht!-vU#CO=xGFnQk93@>Ar*+C}-ini;d*t1w`9d(_ly58*dnq6n~iuAAZR98-Zdo$;v z;T(}mQ3oSUdlf%sU;8)9^}X%wo|`k}{!Cvpt$0^k(wZp=k4saJ?7V$FW$MCNmktze zeRg}t0>>-a1v5{a+&lkr`k~z%&DQOaQim+pU*qC%6AQR-^ui|ookEEo*;~#t3$Q+Z z|M=&3Cmz0QuOFqIbj(jsyq;~DQiPg52jO{PUK#eZo^P+q|3mRP2(xpvMn% zUun!7H^?Ek!YO^KV(n!ve^TTcC+tduaV*m>dqiXWFV%L@Kj z{C@ZI@%#fD;yWw4muALKtK7M2t^X#;K))7=TSiN+=Q~&T-)K-e@U2ka$RI(P+i-G3 zMUj<)#NxcvoB)oQQRWF-=QQ$)r5#E>d2&L3#L>uOY97YXpRKcUCthSO6o_S#G2r9+ zdLkjHr}EI=nLFnc^fX&aZJ%0t>Uf)ky@!nbn=YgJ#;%txVw}_6GS6F1JGX~{L4KCB zWYl5y#hpQ6SMRTyv63-4H>XwconBA9rlRn>-H8I152z|0d}0*l6ZmSw>?6Y7AHDu^ z_P1~SCLlMV|*b(3;BxE_9ce&YKnbK5Y>K&Ec*RFs;o z#%u4TG|%k$%xH6?UA~UvU6_F6+=v*XpcNbc^KSNUPW%eF_SUAQa@ke+yCZRuMTUM*-LLK&FIMFRa$@kWacub=>i{je26(T$@tF{ zrDfr-nr3<#l%;IdKd?RJ>#S)@?)j`2uG*~5xc;PGE`EfF{KJH~oF}k%q@z?a@=jG?ln=2z*|Nr_I{lxdX9>re{Ke>9p z&y35gpC47&{L$9sZCPG@fa68SM83My{$E>uY*{2}BcitV_>Ki%^!;u-KF|Moy`{n`r$;osV&tfjMK+MRLDWU4^;MkDgz7FU1*r{A%(4sP?CaW+-o5Gv$Wbl&lF`xm9JaKM5-pJL%AIDZlQb zsr9N~!BSg_9HPS>-)TyDF>Q^)Mfp-y1NGVolN6)(sDG#^GoRY`&*Auj+~i5`j=U89 zuh6r{-uhbLuH5_ka%J6J?*x8$$*0WmtuA_dMVi}(`+eKgkFeYpv07%l%XwAT3g2~~ zUuJK7GS~ZB@!=Z9lWu)WT6V;oe|aUlb%*a0orQ6>Lgy-7PjnttazB2h__bNvw90}f zSI;WgsC_)K;*rN?`Bl*gq8BC>>z%yS@YXT?NYTSkd-I$a)(^^0KIGW8t5yo7T=rbA z*j&^q_sb)7qxyPD39AK@#NlQZL7X| z9iiO#_gqzMX(p!AkH33(LA$4K*~dx0ou^6)Wa=%Qq5SXBsXJ9>lNNlPDUiA0(6_XxB+`7uNJj3Ymv<3!)2^EX1 z4d%XKs$x@muathBbDy(z%}O!IxpE(!sQRWx_auwnOjJZxIkvjb&G}5`kIZk{`|U~wCmvEu-F-adlxRbzwmF*Wnb3N6Tg*$-x#fz z{>^q`(#?qzemVbQCua9hCjO~>1p_xtt5vD`ZPj`8=)zuSD)89r)TJK-R= zDqGW~`y0>52b#|Rn=qrcEo5tDM}TU^!~07$mo_b1bo$D+HD86^nJFo{%m466lzP1N z>t+AI#k0Gw8eKU1lkLm==Wh}?TsO-ITdewYc+39ChKkPc9UD#Bb}_6z(Y>30cJR#u zRVSj)sB*CE{_boTpJkA?`r;QpwR_A3yUf)$vz*CXtNCeTHe-6XjQK{jQno3y}LC*|^RB#2<_FcPYWQ^CMTj*&3(=I+CyPmVt*2kFfQ1 z=Sw*Zzsxt)?SId2dqbXMSHcsOhbcd@5>f&xog*L*MdBO{`@cJboVDc{iu1cX7-X5jK7k<3C>~o6K0UV z`-1L&CRJS>yHnfmy!H@EboCAj+a?%$k@H=Ye71+#l0fI9S5F*$+Z%GJSbg98o;xAu z!q-o`#-3#+?y8X9!1Qyqe2S{Ts}sG)j<5K-e=e)(+vbCXk%!MNzuWYD3y2RomcHngvh_!gMLPw3InUpE z!C%(ho|yQ5*BAGD9kX@szYjCXXIswP+}UICGThzQbI%IBGkjONH!DBxwUY1Iu--oB z?b^hMhUA-@bgX}RUDVhkz4!8iLi;0M59oY6_vF^|_+N|PhU?$rnz1f7H7Vx$$I)4xugvmZ+jn30n#A1MwAI3wDRRE;|vhwotQrhe53Jd=H z_~5c+QMc1^?Z+3gPYS#3T5wxy;)k16lY+F%q!!vV-cK-^61wn|TB=1bN0dph=82~b zSzFCAj!kh9JGCxRNLiKa!j3mZ%8y4`7V;LJAJI!R^S9H9xH zcj_!xDr4H?YI*mJp(>Lc14H-(<)q82Jf9z2cVbH30k4+2Kg(vT?9*5yt@ZNAhj}|Q zIlBLEGl@@~RN)~1>O)U-!;xhYlQy)kj^X#@Jon2ti{rho#_x;EzpU9;sOhog!@}yU3H>@o4VlBa?eKIGLng*z3G)=B?lCP7`e}xlNH@dP3AS#CB^&#T@4r z*Y<7Zw|=hpk#hTk>KAUq*O|xj_MGqRl@m!ZD6?XrVSbO|I76 zs=2?kuu$NCD0ffaoUEzs`!5;gGi?=r<-7juo9A;rFIZW7TCeCJO89ky8uEjk1wC2{&rJIE|mR9eU`!=umK=D20w1?GMPj5bW9p9`X za4nDP&?DZyu-{7Wx19MN_u|{qdzBmCZ@#nL@;Ucm)7!COuWs7xJnPE8DSS@gN}1jj zEDCCIepaUpR7;z0@SfPVb3sb$gdcN_LVA?XPgyi$<=4uUnin?CWvV(a>6*r{J2zQJ zCr7aQf6^YeVn)aIo^P347S8(@PU%=AR$AcCcXb`1x2Fg=P5ocs`r|^bww()k75p>a z%P2^<@Eu(L=n}78>ZX~qDj&LQB`$N_{q6D0M;&22`3s)6%Pg6-#>YuZr#8$p-1-;u zoZuylhi>k%mR5eZ{ldRZ3)NfrnV%;09KNB(8vCnhLa0{J`iTh}4r<)$EegndJaxA0v_~y8>zh%dtFe_=;-veOS^QgAwcc)VQHuB!vaYt9OE+I=@}>$-r`snI zxaXT!@!R$P+p2$TTD@{%OqS5`XJ6hFUjECvTP287*H!3wuXUW)`>ir>f5nv9&+NUv z;W&?5)bB)_Z!d+6e=iJH6v}J8u~YKl1m}%g-ka4uWO5OOQ=Hl$-L9c)fkKxMR0zZ%=Gx~ zZ87gZ^I7Myc@@X7)`+siH@>b=%6R)Abk~wMjRzQJJ^H47g5`VeuW5~UmT#7B~fywO-E_@op#$IPW%V)8qMGxhi2g8qZEerbpZrxw+_1(^}qDhu)rj#&pxK z+we$)-W*#$^%W8qgOWcett>X)vhNe0?L(h~Y3Uyy+fQbZ?5|7-5Y{ffcN!F^P6XAc3y=~`{ zX)AgD#NPYxH*9n0-<^C?bvzG$xdkdMI?w*g`Ls!P2VaTz`B3*&J11tpuUo&ix-2p8 zeS~=aM%V2I;-6xV3miy!V%OouQ?JBe*2(hg`BMH}BAP{wu6nz=_UJN}FL>%TTTk!Q zwbuEeKHq$#ovxntcY!pUmdMirZw%6O4?kFVCP8EKkAQdGZy#Q;S#z$dm}~Fr zP`l-9|BTmv*d25CqI}Gpg>1qn@3+>?;jfeB64?9S@W<@C@9gi_wOO8;yzck;R=r8_ z^O=skx1ZM)%W+`a>-T(GpBxWb_D&Aq7R#Kg^+4wIdvRyZreE87S=i4oTz$eaz3u3U z0}=jtVrR{bgXAYipZ<3I#%|gERCn%)w=)-p-pH2`KU2<~`26j$HupJG55CG}DRp{w zL_xjHfj4pQ2W^k=R*h+I9)DP-u#xFUF4u4AgR@;u9i4aX^6&3VA6@emPEJd4S>_YX z&$`2yBUE+s!j$l)l;kGUUy1T5J#4!qLrRn-jT{tBTmv^+&6=8YZSRch0?*tY71T0v zPxnkV(W*0J*;uL0cO!9Ea{Si(hnLT6DB5qZ+D`A7^76gM&+HJBQ`9VSo_=P_(Ur>k z59mb5tn}P)r(+0o*L~l!_)e=< zdxXHVs57Vcd#l*$_BT&FAug)gpnkCan5Xc;gKi925~;I=9M>GYFQdl6+jP6f(sD-W zj7BAeJ_ecQd`B|Uk@AQQhC2_@swwPTBjJ^t++EZke{Su=W z{ZZ3=RHRnfkUaU(g{T`=ew$Zy#|M0TmaWeoy*KNUw7GGQVac!B!U=9Ou33n+%ku1DQXB5BqU3PEL|CWN?$MRsC0)xsAU$fq-o3ZPn&AIBQ^ZjJKo+Q zu;6B}N%dOJ%g(*`n$4%U3Go53xU~}!e^pLcd*@*5 z3}ybi>yE@6c^Y>8ePDIFuey4S*e5sNGNEuOll0fkmkgKg-Ev1y`|bN&ck`(;6;@oR zKj>0+TXIf!1gFj6Rq0H>?_IdyH^IXx_=@453v5izeG;LDcl`{D&Np?`6uA{JA90HI znYA%oNAJ;gXQN-U&A%wkzr8w0G=5*`{I?#vkMdPsahbc_YaG9_BoR|1%(zh z%xASZVJ0nkRAM(rRF;nKe0>4!7mJ#%`%C^6u*iFJT*6tFrD%%4*DBryp?g1qv|Qf3 zd-9k4#Yce@#u@HYW<2Ff$~yS0y4^@-VXu|XX2yf3r8oY%`S9h-gWuboC%rgkdq4du z+b4du95YpSPNxD%k5>x69R1ib-=7GXv1ISI%l;Sq#Ezfb#q-f)&TTt~-y9Pj1;u!% z2;8$t=6GM?xpMQQ&0WSCK`WS5S8RG99(Q{W=ehV(AM81e*+p1R|CA_|uwtATb;GhK zRZ!yY=_7S6k3A*#@89d3xZlD);?PB@d5X99G;n9X-umuxmEL2GHxs|z`o+y8b&$PY zb{Ws#&y7tAw~pspZJ($2O+Y9@@^ASPGYi?5lMOvNpX|Ow6YH22FKOl!+~l@SW67M2 zT|5h$FExEOe4U|w@t%WkN|eWK7J)+7&)Rlca<__W0_^iomHw7!I=F3{5(nS=+kGr0 zMLOS=m|Y%Ns`bB#`(ThR;F6P?)fn-fUB3F=&3jTtigH;KZWQT$IK5mf<5;NEiOX3} zKOH~S=+b&cW2-vf7q2zj4{cE9$=T0flU-2z%)sDt*bMQ)Ru7lYpO(2?kqa&^=sUWp z^5e1@#$I!4n0PAWKQakc-C7o~bA^Jt6E|JSE(rBVyLg7}fuQ25*vZLRtYM6s`!8Kt&zj14eXV8l>_6vHf5~RQ zm%4mSylMUJ8w+lmH1w~#U@CH%@4lYQ#?$GWXC3KuIcy@bdHqS<&Pi#9-bom#S?ZrG z{jozKMzn}|cS1Y+Nd_xs358RR-direyF2Ah+sSJG&W!j7b_EIT4$mz056X{Ta<+)r zdy3?#)Lpo+{_)D->Bs&_S)JNpbYIry*W;Tf4=#4@ytldh{L`+@FP=U7x}tH{^b@2FDt%G(G*Ob>)e$bJ)`K`3q}V&;i+7_&(p;0#pb-b)r9IS|6VOu5&ETRbc*>8~3~>hV=ik@7coDd zT~MbO!(uF_x6Ss#l7-z@wR#%N{5kh1?i2EhnR@BV;>+RPa+RjG9@4h2EUNUkpS(5y zmT=%@hV(tTanrfYCs*xAz4I@EeeV~ejvK|Zdd0+db$l&vy}9CItNpYajyVsmB-~+a zWV_y7{J3``^Om(Q^^OQl3~Ni{FVQ*FSaDp~M<8;Jz|51!3_Wa=oh-D={Ds)EQzV`o zKJZmuDeT3?h6~xZJ(_QJdB(gDZV%X`xc-oT+7HWf$+deU3#KpyXK>DLlT{K4>N&Hw z;f?(S`?D8j2z{22csM;ukxlkv!Ge18a`i8fc_J6q`@KxQ@NDB2UxkPj+x4y=I68wp zWwQHBBhRF>Gg1^3PTjuHetfH5`o~xSN7i4F4Q(!~j!Nf#dQ>~xUTRH!+a|y3n|{vu zr})ONeZ|bm{}BTE%w<{=TJD9Y>hNjCJcvDJrpa$AahIoaisDtSb>+O4?SUWC zkmtI@569j!S|7aPMP(XPCYJq}V7MaDD^ia~nWJAyC#!f6g4r)hef6YH<2J56!*o8^B=QJ9*_)71NDgX^dO~>t9}B+x&UGs_(T^ zc78T%Pg}m^R?rtM53P84Gj)nG$CZFNN{jexD)n@{ZvRz&a-b^GFhXv2yx^@VAEwI7 z*M0x=`#rzEMrrxEjt;SD412e}4eD%=Ry_Y=%i{2PCrv-tM<%-mFt4`vxpMnPj`ux3 z&Q%I0rSeL5eseOCxSMogo7~LulL6(%Jm#Wi(F8n2j=?xf1#g$jnk(`8@l?2?Fh&=$8> zTSqi~Ue4jCs*GjN6Ansrt%;R58~!e2YFNj06|u6e*&A#5bnNyY*SVK1_t1xl;jX;m zIpyVlF09!7Zu#}rou9t$nsZ3gbLRJLk4~1n&3tKinqA0IY|_(76)%b=G+a6nuJBd3 zLu%QBvu7R}A5l*b_e^MF@4lCH!ef5(kE~YKN!u9yneC2ZR5#&1@LBA2D67~O%T|ST zGq?~%JP9zO#A+?_n6e zeb8{TBYwA=f~>$1NBykBQ+rfgB~pDt4O>`_b2y*M@bLS^ywhg!#*{K0&%-~De=HJm z@T_r}()!|1QD#xQ;4_0~=cRJ)>{`uX=R8rUFUEFV!bY(*PZh(YS0tLw&%7oVW`B)q z`DJFtq*lfw+-CWv%dY>gy=`%NHLHepWV+b-bc+wXaSQ+Vx<^_(y}qWqZ(>M7W_MX; z!{fb=U9ZHr{HQA0XPUE;^Jli)(o98*vp4tbdh~gQ0k9WZ|S~K{X1*f*2u>CRMRM{AM+P~ssH!7+ zFn^bq!0X@7)!CP)yB|-V=yzG?uKd#K!|O}GMjHOV9=gxq=!Iq0AFRFN=N$b1gMa<2 z`WG&;FAnhO&)w;H+T@0G@wd9~xjzzji8rl}6A4#+_L^buf{9-bd50{h<2#Yi^G`G9 zU{-AEiz21mo2>a8W?khn+LF5EPGs_fk5M;Pt)H#Do#jBadQQy@&eWXT1&24E)m>a- zp2J;pYT28u^WPqeJYraIeO2F!Z3`BOOxbUK`m1dA63cEWb%v%sw-v7#m#`i4^;nT| zPiM!zwMzo#RxNE1Wc*tZq@>#$s&_5;+lFa{otJHVauU0oH?kalf6=x-XSM<>S3z3| zZ*cojhMnitUcc;T?x;|F*tcrZ-mJ|V{sc1II{HOm;q`~AD}Q=Uc=Y$yg{f}OyiV;q zuJLBt10})UB|Eny7fKpEzxt*0)scq{4-Xxll=yGaiv07tFK^MfBmMozdB(qnU-G)D z@}nL;OY&Jdd4kI0?hnPcY+jq$CwzYJX4iyyr@g)>nOWVu<^H@l;jW&@?FBD3 zZr{?!_vTu~A8Y zqy|Koy!-VF@AUM`tQx!M=dH_d-R&ZdXGO2caCL!z~0m0-Vt_#bBejk z-mMj}cSRB_H*7oX-g~H{Y3briD{6Ar1=Mn$%h31Zlb5%(vd9kGdjCcNd-2a3tDP9N z%59Uje0o$`u%%2e%QY@JBg$@eV*neQR@pYqx_RF-<0qJ_s55WNXq?Tp^zDI^gw0>p zE%@TYx6?^hFljbRJ-=T2C$~+@@DD8fAS9ChZic^K47jJ$RK9OHt^JV$r$(NlE zChALA@4wJgcQjv}>w3KMiX}h7Rn8rh{bjsgZ zF#!&{8~7dGcrFu5SrXNo;TE(`<4XSzrF#{Z`*L<SqjVoWaX@Sg7V}+{wpm+fN%R zU6QG@@@l@!*52DcF~wx@2j7e)`npoqNQt{S2)t`|!8m_D+M;pffy->^zgVT#9}D;9k_M z#h=R8ZP~fu{K+fFzlZ+$D=5rxIBL4X4im|PEH^9H%C(CW`St&pGfSwTGIC-2O%ujH zm#&m=|9$0sUs%SG4u;Y!f0=h@PMp@^n-^*zcVWYHmvv{{%}+EoJ>*d=d$^}#y70k$ zQaelS_In?3<&Qo7wqlF1j@kweh4P6hk;gX0Xl&2^#CB$#x%tmS$JV56n)A0oed_u0 zRFBZmN~cL?Ukd&nGm(udnf=iE>g%1S4zsyue=`bN$?ASgwsYdu&mC!{yPdifxOS_A z)fGQJyVJ8||JIzz+t$xkKl3Mkd)}=>mHSJD+aAhk zKVKW09yhI8_w|Cg^Y3jF*uCQ7{lDwV^cOtdne^qA%>B5nrxLBLl6E$?RE2z0i*Gvi z%J~c9POWXT1=%bsn!~nUejQcz|M0#|mz^hhZ{>1Xb5vU3kNKuglRhoDGe6OPvC-S>nyGkWcU%X2xpV~@#d@6P4b zK9Y4LL|egn&t@$pCyyBnJ^vnPu^v%b=3#v1{^PFC$5!8Ye&Dg3jJ@2_~;S3hMIk6FI9%fy!oN# zo_}!t0-nA?+wZ&CZtLY9nY=67r93LC$bHF+eKudam-o~s-2Lg&?>uAXZRQ-yN$1-t zDg`e#zdjpks4_$DL;Ruu!)r!2b})TXo@8O9|15USpPgQ_`Ga($=1iF(94@|{e~ZOR zmZ{pJX9A=%E;c@1G~@bE=6nx$r=m)l{!rx_cKi zRVo=OsJvElFC|kaqf~;Y1`Wal|`&BHg06eYT3sVz{Wi1Ou+tsx1@9G z0&|ZnI#f7!-^BH0k6R6H?9#|Hi1#rxe#Dy+%Vgge7!_?JxXIXn^T?HqwEpn&B`x2C zd}gQB38-*$32cq`Dwuj*g55XSKqT;?;DWca(jG`ZmvUlU&v!fGTK}OY&9sB>`EETp zJIO6eI+QES;I)zWLsgdWu%)w~_7p!%G*j4p=E^ydJ>@0|0o$(%6DI z*-z0t@8b8E#ouiko|-maUU+_%O~TW=z3hdXCmv)<^XAyizh<)E1(x5(f~7A7yVDo7*Y8O^lh3u}!?U@&&V=7fh&JD0 zc%!fNjfCF8L+=ej8t&~n6>iLu#UwTt;g{tc zOBzLj9c_eWv@losaCBs+IY#C=C>`vOZIN!?OC;m}qo10M>mSZ& zT$`|djf$m%AJ6Q^bMB>CEBbHUC7|OT<&*2s7GSmaMx0D;kl91$>N%zg_M20h16sZ;-PIu;W6<Zz=2$%XzswENk;W$_EyJp24Jzl+}5 zdT^TPt-{(lCOmU~@Yt5UIm@cT#1$GoOPkT}Q<6wwi`lHX?>)Ayzg3rb#3A4=N8Ys7 zxv>c~+t>MB6g^m*d28$J-{LG~5?zJNcWOSDF~^GEGGMW?`|_J@&Yf#r>n7Qme0-|B zSMp5s9In5rzi#LW9`37BnR~_5W6w;#Dy#GEB3C9S|9+mgqPDVdYf|GJhRH`X9bA(S z6v-a+dS+@{an5xJ zb%*BFy%k&8Sv&d6|6N@-%!Q60n*B(>MCOFU)`us1-(T#T#ISvfQ4X6?>Qyhr8C=}W z`k~P?*o8s$h8I;m3!a z=l)+j6qS`X_s|h#8?Krc&mR2rE-A=ke4G}3$LF`;@`^)C6Ed%uFmCJg_n65XyqJGU z-@9{@i!!<5A2;1F%RjX`J3&m}*ZO+S(gSHS%I6MguVnJ({TLgxN9cue@0|~v77y=v zn6WMIP`S$a)qrb8%@O_mbEXG#^ccIWnc-yca1~3#4*{0NrCz7j9&G$QHJU?3fn?L+9!;9#n$%oam7kpJO(usOh!5;Tx_craavbTDVw)HK3xF-6~kx2)x z?0cQa*KBb6+wq=zw`J|+vac6ka7#PX!S5TR!~1ai^v9ML$|L7poM`z-L?@#)sOr|o zpZNh39Ugt;S@cfz+uH44{UXHI`MEM()jH1Xo1d&YNUx1|V{?h%t~{#fR+@OEFALC1dYjp>?MmCn~r z>do>!CdaS!Y;Ex>&wG|D_wQX5T3q&~Qsu_!`?a;7bFTk7v^{6il#W%)4!IXTxO}&d z{qD-tHFiv&?f1x9J>`0QDql?RE93p}ikmN`-W|A8zMA<)L;Eq=FRTJD%!;S2FYd@n z{r2T)pn#Ef9eSW4Ap4qo~FV)>iJv)?R^{B`lBd;R;RH9TK#7_e_-ojaY~LFrtiNbE07 z$Ax}&vEr*0?z-GPp_la4rMmNp$KqOcelMk$+HfdcTKVkYtF#pbmvlFNKc?@r zrnybv-tL-98qJQpdv&tc-ZlGcI3*!`#y8k+1>qf(gUQYBgi_7KhQ8ZBl2T`UvGx+1 zVE6ys{Ik~@&hlyrRaDI2Oo%#bZvNs-i-XMLCjy&-6XLX3KKU&bZ%JZ$dF{S^@AlN? z+optUe791eUE}zqprj-Zf7_CbR~*acSu8muu*iF1QR4n-kqac#Cfrzl_3P=RS5dX5 zyDLpUc`RJkuuwT*u}DR!YUcy5hBh|gH&!hxD{hIpO*?$OgQ=bQOYgKC-A=DGhaVny zMJuM+opLyHwC!?8FYDTz8Co?Dl2m9<&c=$~^URdka z18GUtMSE0pcXC__a_3@={pqFl<+;KMYj&Yz@wjS%xf{~X-}_dzt3|8Uh$q^98~-FVY~dZ z*`=oIKShQ-TlDDVgYBY8PAd)O+;!Er)(fmQT$*y`$Ih^Fr&*aj71MhRH}7D6%pnlp zt@_OQ@~$8s>FlftN9FI^i7(lG>gUHZg4Y&Ic#_Q^_TMzq^1-3b#5d2_zNqdvwZ4kA z!Daa#nVU9ycP^gT(_J|$R&Ao|;pHrHYr<`3Hy`K!6n@NOQIgNzt)F!ibWhIzyOmjX z(_Gb4=XEbKBy<@0s!ZJT_XTsS!RdLm>lW~?4-87Z^fKT?Q+Kvi=Ax#Dh6k-bOyoGy z-2W<3KTH2s+SWW%qoXsw=?O+xXYsF5*?PEU?u@HOh1(pp?7QyXVOG+JO`5gkr+8V> z`;NxVjDr7H*cqnBZ%bs^AGzHAxLciz^q0Wg6?NPp3sb)3PAR!%0cRYGo%3iO++}LE>y9L*OY?piNkiMbTtylR= zop7`BlbR_@&c-d7t@cLoa~6N2}~yD7c?*%F%lKKJN@ z*K;}7$E_8+rM*1oxT$~C9lk{z%NCxPvn5Z2>3wa+t)2{_e#(MWr7Xd3Cb<#TIZ!#Og#>uwR?DAUr=r z$y@r6Xs6GUrBShq8Vq_K`fcy@HfOQldpS#DW&g2lzD^nMZ|t7OdnLer?hn7@M~u3+ zE=XIsF8?iS>VNbC7ssp9eH)pqmpSLmQi~}&a(=tG^R?3Y^`Dm<{bH5-eND9eR$ZPw zPtA6<*a)7v{KEG3`5Kd(9+@A{8=Tiaz?`~sc?lQuWPx7U+xPlKGbR{WKZ*5>e7*9x zvi+My+hk`Qe`_*bd-C_CYkOwysXA#Jf73wb8{@B+dzN0_#(&Rdk;JW6FQv~ucBxsm zC2?9s*TsMniC@avcVtNWYCF`=`MAdZrK9Mn%$wO$6ZZtFzd!N&j=k6)+lIKP4e{GP z)HMI?-(J03<-3*NB(Gxkx&5K>TeRxuOv;I%Eiro>TU=KMH%&P`TYKYY#~ry&Vsp+qDcu)5 zZc*y0XWp*xNT_z-KHF=>kJ2Y^1RlN%k1Bq-cU5y*o2~7=cCWubi+DdyEyzl5 zz5YDQ^XisZ*2>LDFx1kEcW%n9h+6$J+u+Z=Bt0*tvvv=JR_ac?C3J!Pn9VF*I~&Fe zL2lk6msf9@c|L91-IhPr58dkxUhu~4HTwUbS9R;I7T1ceSwCJ~eIK`X)n)b{v9-T9 z{(SM>Nr(M+X7UC%sd-`|`nln+7HX-TZYmEIzjkdJ`^vsI?8;tlZQMWd+g>G~6Zjr& z&=<{YIaB_k@eP^h>FvkUQyM=8eQo&c{cU-(@D7WdDLK!6&rHk_VbKvfWWD4^<5J@k z`C}KpUzskkyz!3SpKpo#U6gPB>YFk>rsFT`(NIx`xpnuR%(0s;qndHrNNS~zX-Uc= z*UE&=%S#@8-m*>9!tImRw%WIUcD*sQUuz&+7VEc{W%;)&zn4oF@QZY|&92yNvOE3d z8qHaUt5eGkUTEDddr#s9?>g4qPP(5sPo&2+c(2>L`=Ui|hGEm0OIkBG?pwg9DE;}- zlb@T#)2Fz-{rGS)v&lWj%tceoWJ+2brrZfRlx%pl&Vc>R&y)U-PM!%qwBzQkA5u=8 zmy4IBen>fd>&x-Zmv0_?eB5Jw=G?q=6TYHI7mr7R{AcYH%&+#G;eV~ADSr89T3A7z zo6KpB`_qrg-jF_}z4^@6S|N_Ut7lo)zA_MEGuoELnCHd3Fp}x~#Q!W2)2?298r9|g z!#6NEp~UQZjzf;%EXQazHcJ&N-A>t7y@^|1upj=HvL#wiP%j`o^4lc-4afF4vd45q zYp5`Y=*e1N>YQzVU+R);bHC&FAF&7OZ5^2x-{oE1B;st6Cv(BEg^7;$f6cP#KD#zX zQ0+}AXVAZ>NwanpzmqSTv(3v}#5!u(q`0il%a=VaV6JxGQDxT7B*(23x>xN@kH2H@ zj+qM^w3d8{<-E`MC-Eff1!L9+J&I+j2Y6p>DE}$q%qBkL@2vuvX|<{6+e~sNT?w3( zzb@~@cV2t8=egDP9bvq(ld3*soOoH@q`m%NfCWeXLA^%SBSjK>PVCf*{LjTZDSP%$ zk+;i#GIbYLot-!#@K} zK27e)H0~gR>sjzc(p$V!9!BBDlrm?2JxPgB7oo z9P!>;s`pA9SecojyXRT*F(m;VzSo!D zJ^Cuq^Niuknb%k6e%hWiDQf}GCZ2>PhrXF4SU!&FRrR4D+=I58zJ3AUl`{m7!pWw0k*ph=AUQ9VY&FZjX z!}>JNQ&NX#25IkH;=5O;$bnVqMbR2RGtGG?%FEyVJ$P|vWToEXlH@sh(}P(Ks+_s> zB<=9?r@U$2aZ9eZUATXs=WNHx#=?SiCb$0zCbwjmmerqlsWee`#xunT-oV&HHxw?dUb0UB=|c z*`7W#d6&kgsV1A(O}o@~s=oK+e+$))z2Dp7wx99qN?F#Su|KtNP4z$Bd-Y##gzGkO z|axT!tY1WiAPk&bP zR44rD>AnAXX=bFbRqU6T*k%W&k}HX8_H3CD+tz*}y=J%G>MY+A+U@ps^(_~#I#{w?dD`(B(7MJc*WmQdb<z<2o^Hbd4AAEQ%_@edGj#D+cW*bvC-@p6X zr11OalNaaDm-W->d;9Fvhg~c8ZhbP{aKEzTPKVbbY_qN&$zSS~TYPSTkll|b7MVYG zGU)Jq=ruc9VAHkn{QQ!e1?;yURsPO#zO{3rfzl@aU5&r0P8(dyykC%bdQaw^bn)~# zWshdB-B}}4s={d_t}?-lvoJh8`ntlZgeiFu54JXbTNX9j_|1am!=7aunDZsmxJBMp zO@G*5o%ogUeYH@j&`qOBKl)x+bRCo8wYq8l{_>M~VgKh&&rxtUwaa|XaqDVA%`5*M z4>!IS7p#3T<)3NY(n&YM)Yfu+Sl6!iMstaxtaq-zUEqy%;?vdrRjcoI9)17XM)pmD zam>2M#jk^}32c1SxvzFx?(*avq0>IQNlNxVv%Gz1fz3^|ODFx5uLk+Cf8QM(T^q7c zX_cJe(=&bhyt&x#)MW6-Hr|@ZQzjvLR>8(t=h-HKLRO;#TcVl-KlyIlWw7axZ_G?X zE-6RTOEq~*iwx}VJz2AT^~F6=;f`}Zm;F3+%VlGFOUJ}%&29&}t=7qZad`B;cF94v z{n=n2|}|L3{UvE9&*P`s;NLn5H%_n7&=$PQGtu zNaLJ29R1y!PR}Ua$K)ww)0ShbnyKdgqTlI<-sQ@P>sj^+)+mRyZWiY4yH*3 zh|c7X2D39F7h6vXHI1K^-)Ne~Yq7%rsdPnn*UjrM*Jd|g%;WSueCGM7IqMDAGhZ|d zFwAb{-nl1NjE`};$W^xrlTX*T_#OYP;QOC}%Z-8GXue{GS;T=I+i&k_3Ap!FH~ZL1 z$qyXN-*e6%KjCr7-ppRsGkg11@dVxU#wounDlL;Zf7Cb@ER4(%c%ZNNSZ(2h$}By{ zuez*!X>ElQWq+|$xh;w74r83kZlb|ERpk}SlM7S-ITS_O)c>goh&|uSVejZZyDB!$ zv6!W*v@iT*9D`fMG?^K)tN81CWGCn{vls6P%d>d(ljpz$XOFf0jCGqIeJ|f}neo=L z{U5Jc?>_lnuj|+<rTg9>mQTe zUa-n6Iic`vcmCh0H+Hp2rLXyXWaY|sZFjlWn$jz5(O+V>{cN4JU#&o2b@NtnzlP6m z_kJvx^uo8dnXU3k*&U@B=3Uwv&-t#-P$}DSWGa95s=jt#Px+413|CE*wX?pJ zWh!4fRPZTKwrJCX6VhA6>~dCpR1r(dyu9t5ma*aUKfmKHy}MboYqR~YGR+K$_9HdB zwe%VTVil(_9@2tnAi87Z@<0OG4HC1KR50~ zzR%~g-M{$AU9DmlmD~Ux#%8-_jhCU8p+1)qCaw>=s%s%$usiSt+Xf-Mb*H<9f>zDY zj{kRe*?NolqR$SROx);d7F_dEak5D37apkzAEu;n?Qi+w`$DPsl*TQyuO}A?U6?%U z?tz=U?RSjUzV82aSGmc>gRw!u&syW4cjnx8H<`N@ZwXs_e}B{xUZqS`M*i)~SvR!X zSjy;%e3*O3I4iTdtm~)VnphP^eK+>U${$#?TNxW_W2&yUto|ppfp^X76t|#TLuX5F6(`Vnkd+J~OSx~yT`Le&~ z)iMsL`%m{~y$v~@*|5l{O~I$F{7|UT)sGY97hIGVkMy~hvu8VtP(MRW-}8xo`3|_$ z);#-@d$Qa?=Ra?U^FG^iYn34ur84)3Tu$|DSC@X}j9(m|TlTMO zcjr?%{cOtGbkE{jj}{58T)M|R>FcdMa!PNvh}`vcK3Kb(XScC+uzuR%;7^>_7OM(d zA761?v_qHeljiZ)M+08JTYWBb!RogQ4tB0wnsM9cKTF1L; zzi6lCmPJ+<9IjUJ^H!@^t#u8}WmP+8p=RD&^0dwB^Stj<*B3`zEwf#{Ok<;VD@nHwNo1{Zs$6%MNj0}rgkdh zXh6q0(^4VRW_RzZ2F{NbkIaJaS|_OAQNQ-*uF}c94n>d7-ySH(=cy8L6&7uCAEX9}L| z(LS`m;Q^!L+)UQVH?{WrJ{Dx_(S5()OJmN2!lj{OCwn<$~nb~?S z=ty;xzsokxi2DaFGsy_o3i|(?KdEj*&ZF(MxsFGkMz7S4t({x*{nN?GhlRiB%1qRo zl)C#;anllYk;RYqZ16G-;cK`w|BKuVPx}`y3sh!)3RPsAo#VCB8ZW*VrL&+^U2Ao_{oV26LlG`JnwaxZ}Rq08As_G z-5pBqwoU&Qf9~EHVt!3I{EE^pUaJp1hqwyOC0;UKn_+CUN@sej;66hanVWpKH|4RG z{(2a3(bwh=&#ezxzry=nYCX-$Dm#S_Es1SA@%QY9?iF|Uu3L5e@!Rg}dF|Oja~c}H zZWqwF%6(c`W#^&VXN#}pixwz)c_z)B{QEZVM3W^>3h$z4yB=wqf5y`d{gtu{JU zS$vFt%)3kdP4A9dX1dF+>6%Wi@MSwz&lMPVRdx2<3_r7v*2koZJti$!B;=G`<&}2j zx&HaMJvOJWNH^_zpWeQFIs1M2H2=PZoM+Cj$PIsR^M7^O(f!W5#h%z6W3R1izs-}C z;=sJq(bZT$=3b(Sd2{FsHbF)o>GR>&ntBA8m#H6$a9I1omr-QZn*6%`!pAz~eT`oD z?G^b`T==PNjlTJ}(!=c&9CbFGKDv%$>y8Q6KCPUW*U=o3|G(BS>-foUzK>aB8xFOU zpPwWC<;5QFg#9^UjX%^JJve6DaeSI~-|>;WkdJ2U-9z(@9OLG@*~ljz7h1z|TQEi? z>q|=cJJDx$nHOKYm1$l5x%#PWl?mLV|Q-pW|r~t)aDC-(NT3hS(1%FR`-UzVd<`{&|YgC)@)=D!tvQe*pWNlD-YzMN+Q%&T9f zUHBq(gLlr%UGJ7@+)kXedy#J0>O%hmX}ZNFt_$B>N!IZ#Pgnl#(tR&?YWdN=Jm2u$ zM?-U0*VN~4cJ>J@{$H=_Eq9#vUY#lDgqtTm0P?TzUU_l6BVC|E%tpBVR9?_Wjt+?5*dH@_+a%owd>7O~&_s z?y=3~rd;_mZ(CpbGdJvse5tu@hoQc_m(-G?GEez-!>28o_YA@nZceDUylCl$hq_ zYU|?Gssf$Ii>K+dCIoE!b%3!!>5zis)tR>nlpIc(B)5I!dJ@F^^nMm+s?~*%9I+V( z0>3MJ|Ld6aal)bIxqL;f>Qb!SnXxwhqVn-OgtabhExRP|*b}Ayvg&$i^W-gN$*${n z?yInybZKowPDn=G`>Rs^tVydjUvK;UP5;Hcnel%_@47rrt*U=rY5e~-Thr&0o6T06 zrxo&YmU=dnp51m<_RG9qx$9Q1UR^18YoV^~<_{^WT3hck?K<{b=lFu{Urt9X58FRy z`-~|;`nx8n*JV#pzP2doWnK8jNo$Q~=IYL!xLNlDTgTnUrDoq&TW>InzRheJY^vY% zG;!heWgIVJ{?E=xUFdta^!deIOU@s$IHUV@{oh}UymQxo*dgw;<7NK&MTZ&V-?WCU z%Te{5Wp?Dm#RVs_KR3)wo>~}Cw|Ux6qg!G^!apvxO?e?C;&@4(;jgFYU(d_?zxZ)g zOpz&zdan6TJFIEWin?5v{@Z0f|4)_59nQSF*6VSKxAgKARo@K%y(_&SZG2Gd?ZbWV zFMdC!y8O?)@B`V8=k!&}m)`tp9mBExR>?1AZn^yuy;Co8G(NQL)KC7nZARV+%e5*s zXPBIfW+{JoFJ!8APOPBRg0J{F#{;{)cX*1gOLENeHgNmDYli;jq^j7Zd!?QKb-#J2 zVQXnKd&cZf%TCyy`4RX0hSCkrgAIp-cK0Z;rQf`r*&B5?FnXG1T-|g-xumoHIsvgM zC!OZ2L~$v^H$2*5C~{13tA`U$?`Wj+d83a8{RftNF*Rwo z88BP%hH@S|!(pJx_E{?J{}!+OlN{NK<*TopGH@4ehhnZv3t7UUkg;dX3h zD0k1tD8a($gK=+E)~x=u>V3o+m(Lyh&R<+3C~)Ut8HG5xVacg1jW-s}9b8PHS-jHt6+#@(!IJ-y1NH5J~yW2wl{>3(v zN(&E*+(_HCG`j6a^F5(p-MJRs{UVRy-BTWhlBvoHI6Pr>KaU)q*){M9aTZCZ{GZzyeF|O(wP0}+_-ZYlYW@IQ)@k2sl3f`#_ilt-&e8+$`?vUe4goH z6>_k5$C{Me)mM6+Tw2hs%XLEI<1M8N2A0Zs8yQ#19h|~H@y7k`OB45AVJ-c==-UPN zcVQ8cviVbj4{T#N)7@Xlyh`CvVzqkhZ7EZ}DwgeWi*qh**|~ppl5UoZd`{_)b-_xH zG!GtUE)S5H@^jaWeQg2rvQjIKby~2l;>e1=?jw|Glaa_P>%OkY@xtRTJ3~beUGK|T z6t-}Qd(wHi${zyn#e?4GJ5N4)Prxev#PJVpHx?#~mRF`tHGTBQ=ZI;Tm++n~A>}`X z=13j9dft;UcX~#5*(Cjo_OpXp?)p8f&^A_QtYyATG!whk9jn0cJ*FJ4goZ@JA z{Q7*UMpj16#i>_|w_kZ}(N>zYah*)t&po?}egrdAnksX|i3&0Pu<4lBH{%5lU%#Tn zrTaxQ*K<5zzs6+FYcYF|-dXpbB~b!%Cb|AyuJ(o@qus?wi}m75ra3X!vp+50!^UxU zQpTn=D_>qc8tky}y6eUkC#8>DCqK;fFJyS)_Cj(uV|wMn1K&kGY)%`UzIZ$C&63N9 z-b{9T&zYO5W#^}SS^f8>?{gMUvHJ1scErbPIs2OP=Wv|nZm+C-Y8d4nm7T!)OZ$o7 zRmZg3{bnN3>-^l()3vLb@83L`;K$u)d+_1~<>!sd3PkoqCq*7$J#gH@ZrRSY zJ2Uuq8?TFgz}AzwNIuW@*T@#!s@pey)UliOyP};BNu(OhD7e9)X7iBorqsnmSx2U=u7%Pf z7e9)Mt(mfU`_(E%p*W7imgg^uF7sTLD}Cv#hidj};lI79N|u(lcgkkXKXz*lPvns_ zyJ{?sye^4x>t95$>FQF*NWO@>*}tZJooM!0Tzdte|HQ$tPFi@{-0N~ zd|SkH&&qap_jSW8XX3?9BZ|p9L#B7hn4FD zPfVUm_6aOJ!n>ANc(bVX>o_-``$x;t|E`#>>v|)7x%|>kkzp4WPRvx)~o1d9=9TE&r_`JF9S%~1oHIWie-&m?Dy<O#eXpZ2##I z+R3$kZGI1{;+^Yq95yE3UVW8&V&932GRhiBTWcb$^q0onewy?B!UvP>D`qrz1p93( zUwL_H)LzM>4}Q(s`f|^leQMjxEs&7_L=bN6@7PHMZWZBy;;V+$-I}P-%LC?{E(Hzf*luL zzm>UYx?z3ht>)twx8J<8SoT@VrFnl-!vl8bo%Ni-)f>EY-N7E;=T|4V1ubKaoxjBX z*qpjG_hvrGi#)lyxI}2xUN7zE3!b`PiCN^3eoy4uo(lm}lV^FH-Y?H_6-Py7Dg zXI%TiZ&iDB6Z?H*m5Xt$zmpiZCnmQ|nDK3{{b7~cKW=iAnCET$Y~FT|b<>-;m9h)f zSr?r(+sey%acYmUV%dVdU*!&j)vNQ`aBS*uEfkuhq2t2yEjRqh_O%c4-wLEnOJRMO zl&G|9dYZR+_oqjEKAY0o1*?uF-4UL_y7jJk&mO^_f`$9m{c&;M8ht=|^Mxxh8PbbG z4P!J?_?Nm!EB<-zpg4c$-Oc-drY3v*(QPw2xP&Y8saWnO>-iD~UfTZmXZ-xupXJ7; z+0(YV2fKLO6nYZ+tVPb|@hpCqKl_^6t*>he|DS!W^y02uj|nc)Z;Z4rUGNnD*S%5U zHfQ6Uvuu`Ajc=&TzrAjn?Ym80AG5#8m1`9(+_f&a+#~RbS7+@B{_sZ(3;yr(+W#ta z($=)^SurpF3$L3xy~873r&j9mp3WvmIhpW#r*y82{|J`}?i_!M=^(lJ*_A#KFR;x9Cu;WkKml zzR&a3ZQtd*y><8GGudS3TMs^!^NGI5doWj-{g1}&52Ef8G5@^GIN$oYG5s|CmOg#@ zwWXW-_w4v}+M`V6+-{kbFZN}H-TrptQ^EVy}9sNjJ>JMHTU>l`@K*8OXYR9J#7=te!h2$jBlN@;m5f; zlh>BG9b8u~(RyfmpO6Z_dR*SC6T9b^EXb&yAkgEf?!W(R%0gBLdvU=Wp^D8Z=lw6N zZf#h}{z!60nBMo#8$M=mxS80-{`6V9=BX8v1$UJBwqX?724%eS7iqOd9X!wUu1JA&J(o0=z1O4F}KC=;r!LH*75;%srMTXd~mKk zo5d44>#D)JDFOV22|}u!^(HA-B&?G5tWZ)quzdH|(4YBtk00Lh-FM##v2t^vfPdEa z-@Fm}H^uaM8)r+1O3w793x8hexA?Ms{=5sW_vajbBh-7mY|9?a>5aP4)}^=gCW{?P z{aehqXy5c*hE9`|xo)NudY7O|6g?P z|Lf!H<9L7DmYvVKc9geev&NFj`G!6!r#W;QqeRWGnAsk-n8Dyvb*`yknsk_T{L}E& zHI-{umfvBIvt{5-ZRnNi|FtY{?`97U73P)xW*N#(tITTlKi^Uw!VM!tnR74BPSC%wGHSP*8{5@gs&_AQepB8TDb~JNRWSbX$_~Fz8M=)V zE-~%+bX5DxHVLOk3Vwp2Ywd4D=v=N&j%B%X`0t#PoP8e~7K$@Iy!1hB{*3N~I)*1n zcC#7P`})1)A1{BaYc@M}Pi&fHt$Dx}UD?S`UOrm8a?Q*0`4{d4d)6(PovAkO{z3Jc zpgoySqVvB`Qj^~)TA6Z@qapmX#e{8#Vhj#ubY3*vuOGWljjjHWF5}^ar&oU2wPW|% zur|{#wfdQvp_!e&iv|4+03ch!Hre5 zRPCFY_3<^|B>&v`|LL>s-^+i#y}Y-)`uF~u|G#Y3m#_PI^Lc#D&!_p{zU}|lgeb}qW-{G-c`0!re=WR=3m+am9@wx4!U!Bg* zfd~HB)YYZMD($nc^JMyXW2*E2gEB&zOQ)}9GAfE)$NN85V(;#($$rI8-gy;#GrnW` zNSuL9VNt;3z(;&`w-sJ6eUwVLop_Ad>W`eQ-m{n8XOHfgv&{c=X5x-DChHfrs@6or zTgU%XH)so%bN5rxbN3A!DW`~OwO+32n zeOl(tMX$3W4U|62a`@Mg@1(*REHvxq#}{wfpX;B$)ckn6b-!+jocDJ9Q#eQGb*4FAbXWEA+FW&t4@WrI|(;pREk9e6m zNS9MQIr{msvjd|J^l}P)!P2Tw4~15rKkAz|=D4^r3s=-L9oRb2XZf>rdG~EHRM>CG zaPBDK_6&$`dnwD9w| zsxuc;`xG(@C&(9A+;Tk7sJTyt`8MdxEcG{;y-QZ4rOl9Xdm)|kaplex&yM7W1#d_@ z%aCxf;H_KT%8y@WOF9@IjlO(Zre^c!t-en)>s)sPzX%UI^EEXrx$A*$dBv&lqgA!; zV)7dqxl%-=olmo_diUeb#|a(6@`Y*Jg!0eq+7TJHx`uU!ir;;oyvJQXuAPWKEL(JA zqW#6zWtxgS630Zi`6R9`dl=H)l$N$^=HgcqWsWyKzuWM)g`;8O^lREv%>VqH+a*c9d^1p*8f_hH$g2kYE(`zsiYZCJs8i>GWYRjvNf&tM+M4fwEM6N^aOT@d)xsMu9`HPU zP$>CG{F&F6MzhM(hmtl#ddMiO@0Q8&`S~N6GeWSp+44~1;w}2hM<#bf{tElHIdoz{ zUi7Bg@*l~DaV;qdQC@t}@zQTQx#*nMpRZ??X}(!~u}$Pc@53o^dK_HL$C{(I zOTFpl{#WSBD$)rzOy-=)Vk`KtP0(BF#TBMDYd%rs7Of9fhDX)zbS*q^ zUrC_YN-(K4V#YV69a=Jn6($Bjyq>a|ktt@osc)q^8Pt#gUU+}&B<(+J=+Gf|> zln->yI8i@4`GKfTfnv3d(W4Nz{r`5)k6dsw!m6Uy(7QTfzq!xvhXrj{&RLpy?l)$3 zI2LhcgUq=ZWs@qH_imZ=Ca=z2mvMVtyZ#4DK8FAKHgew|uH4BuZFY^ogN^zP!bWHA z&TuchVWYWg@BEJoEuS}EcVBj|CN`g=2cR-)jSVgKR>@|`^zcP8k@8)pBKtsI#=+ItMjCwORWLf#Y_wb zT*RLEs9xu_wD3{PDSUKdkEzo>ZXvty>3xMyTr-RM^CWtevu8~9k=j0y_Xxwx$;}7$ zrnfBU+!@aM(Kdcc@sA(w6&HExH*JcK6LFiNA-P$6aeepA6TDjU4=i%%j&;BN?~4k^3
iIA*OI> zhHbnLx3-As`jg9F1}E_F8hi3AOct=#_iWjCp_;+^9Lupy4VD`hToT@TSWCE3Ea*-4 zyV&;=JXwp5nlwvgB}RVqpYUDmjP8POZaWl?GJJgfI_^%OHIV3SfWLw)1K9oNv0UU!^8Y zyM93Iq~6Z!ac3*!7HXWhF$lx0&CN_xYLrb?Ikwx{uB-3f2A4 zyTQ%hdB%!`yY^^4|H*YBblG}IiLzrE$`1rRbE`jPJWI))l>21k)|?Mg6*qTnir7*9 zX_IB7!F)gS4`-OnJH0?&cNs#~(fSV9(uTG=I|MfZG)! z28=C}{$CA05PCYCS^Nc0d&))eqO2?lr@S4Psw5PrJ85qH<+6T`wQ1fQ@uR9XXIf+V zS;B5NXx;2Nof*$?z+(9xl_PO+1;L9Znfl)`ebs!*^k^E>ZTq!h&&u?)%_VJ4a4gB~ z&$dwUch%66zVeFEYJ=tCW%h@cxU}U&{*kV_Ep}BYcuq<3y0Z7jy<%7-k|ol79~rG* zsmo=1@Ioe^>b^w}J~d_Qv>0C~x~bVPOH9c0QD_K%^v+FtLUVt5zB*{KUn?*CsZ_p1 z&as8&h2i{4(-mACIP6~ptyB$Iu}||g?~EeuOG|eduRdX;sDAh^b9J-e->-~mZD)G+ zoWK6!vx(A4<%3*P7-E~MZkJl?iudf4&G1y>61r}=+Wkse%dd`Zrk*!j*RvVU;pi|~ z(6jiw{^ws(zVg|JJ}%hC6cs6+eMNKgY(ve@_awxmSZ>Xl;wjXmWMz=WVa#%MMM&-K zu(`ok0=F>q+C5&P5FE1M(;vOHy^A;8Q~&fPZPuYH4+I;gEZwH|zAoDGwa2Bcs*8ihH?9ZRZF!pTwQm?E4z4qzt$RexwT&H#|>w_2c{V_Q@c}?1NcHZ z{2n+g;BnlXrRhxH8nyL%>Tya`yTztKvE2^yW%HCLIb@%P>XGj{}SE9S+EV^DJym?E8rG}u`j2(|RN35C6 zl=J+lgXOd(N!nYRCeJ_oW&WY)rBBU2zc!t5<9*N;>xEh}XQEB**AzsERC21x$DR=^ z@cTC_(lu{#$sr%c>5L^lOFGU!=M(A6o*lP*&ACVIch@@Sp3PifT^Fo#s_BRGL)jx; zv3jd2OH0!^_2twR>y-I>L*ugcSRM3PR?(Xv-Wt7e5#Q5m5h*L4z6+XP{YbF%^c|fg z8N1J3OpA89psxHWYoB*YZsnS_{~imk4o@srC+7xcIDogR{TQO`M5<=wSKs&MR1^Xg6GzqvMkz< zwlOj2geV_eK6}~2_WQOE)UQ_DS;Tq0YaMgiM17vSJC&b3_$i+`U*7iYtFLnxy5($7 z)MfNx$PjIu;Bd84(QR&V&$*?BU*1NvsGO|$+3@3-Jj*|;_DYK?cDR^e@v|YCHd2j zvhuF+96o${`-&W&wW{G)%DSxA-n`5zX_BSoD_=M5pV;h(bGFlFpRFxm_}3&V7utO~ zBzV>SfBTK*yzkCRmAhasm6sP66H;3!IVmdf{_8t8@77zt?)i(z)bG)pOJ#QS zmWEy3#9+K5vhC&^hm^W|5?=BBsSL;47FGwXIkPk(@Q%`flM6&I{n^#>?_+Y3z}KdX z#u@qy8XjvbxO?sI{`voJf9bE9xP68us{FUzckd4H{lSo1dns4QF00nXeQnrN(R3Cq z@voa=1g-y^fBeP&@s~BXbR6q1*7Lj!newh7HKKrrVO`b-@si$K|6gk?y)Snt|7%I8 zNOxx3`u|o_l5cNo)U@6q@iJ|%WW31yIeRKUKB>3+`{>8~{{QVEPwigl>)9Je@7dG# zMNs_NM8iujt8CUDn|*!0&7Ir#|EIj)?4QPJb3fx-x`ykQ#kAX2#vfaBT**vs^Fwt((gBd&wv63b-6rkh}KG z2ezfU1v^fE`@U)K-_AK3&dhWU=&!K2{@zGVjpe7|{=?qs$M!^AU$<$u@u_Q~Ggx9W zi*>>$*a!af&`@>MOOn4W|B`Xq5syU;ZT0iqPESr{S2)A>JL^{b!!7owzuBFa`*&Hz zb#}Y5*F0gtgC0gH_F6YiRmHB}wyz}j?fdB6h1|j~??0K56l?yM)$FgP$=>fbT|UVu zHa0$-c~GJCpzEeDZdd=uysDq}w%#!Cw^K=Wi>6kuyr~8IY2VV8Ot+P@}4=w&)#v4BKg+19b^V{^(3x9F9n141e(meHSNfD@578f^A~e&o1`v%;dqoUZc1JD#<u7 zvI}#~teke+3dL%vU#U5yxp-E1bCMIYRmuNs;cv3C3Rx?*hB>(XxRZ7JaN~79XKs(m;Q{pU(BE1A2a9*{@k(dRmuPE^ZRf8|8n|#`{5F%XOpxi zDObzaZT)`rUdj6DetN66zm%$T_$AB7_kGq6u2)R=6-$?w?__zv=X17*@f1_TjTxe% zk4wMI<9M<3LdM54Pt1FNtSy_hrtHGG&BdSi-<$qC-Tg9r`g@a~{NKMV+q`%0_qq1Y z%l~w7e|T9dmN4!4eEXX1clT>Qn_=|t@3Z`Q7p|_i`g{JJ@!ywkKEHf^xqQ~XhdTFu zzX_KUWv;;!cFOAWYZm?k;idBovUu>I}1 z1&3_g_AU6Rcrd*oeeyT`Ra`8ubdz~%$0a9sK7O|1%{%9< zKh15fTUn{Eca`0gbhP>LNi**EKP1HjPH)&B#<@-O&ewFyCtH`XHC#M%(o)v0gid(z)O4XGOuae_*)?K@Pr}OCfohPRUx5u)@&$8~EDI!tB zr2Y8$2iL|HFR6oS0l^nkWiEf&xc=Ccg{{kUcFX^KllWw_|KqFn-8J7VpN2n>-S~>> z^zTL1ItMpJtriuIdvHDR@chZ#fu_lu<*naX^GQ$G$o2YSXIZi6bLVxleYdlk2}%A` zQA%>-nUW?a|824Bgg6b3)~TocyjhPpENPkQI`Q#MVVyo@@rYAy6_)AeRvpDsF~+_!1F(_}qm`)8+!nzm ze=Yqz0)NdPtuypI-gNbi=kaU?_vI1U@-tYN`rq94;e7l1d*H#+xou^w3*+{EIP>BA zLrX({jUXxM<+@CsW%Wg$pZq*&yiC8|%Br&N&zlcFcsd1yrCqzX?ao_x`s_PCj|VfN zIcAtnSaigG!IRj=hTjjar_J>%JR@GN<+pcR`^{b7OXj|s_E^ShVy^A!J@)^8@+!r= zUwQcIamA{PKaOnbX*+Y~h_>1ZaDV%G|Hl-A({rkeU9Pj|E-8O+xO@KZU*9KAd|CW7 z`2Tj^JvnBK244fu2<^W(vGvD+9a^7~cRc>iE_!vJtj@;D>%0B06#dkmtNMS63xCiR zaYGCLT|O0?{*-*#dG#3k3zqkF2NWi}kgq?oAbiE!$%|SyKYS2yGEw}iczEdJxq9NA zv)X4k%~`G+wd}&fHB(#J)}Ju_b>Wcn^cazIoELf&!|U!IS=U*~8nHBY&BJTSE4Kd) zx0-PAa$4_|{*#ygloqmYJbU6^(^H7`E&l_$;Fp_kDsvkWwTFxozWZvg|7M~!Q3@&94`)>>R}Tx z|MHT7&-n>UfM;ul`wG>&lIKoHCdTjmrMAa>fAzsg=gxZ@mHd-eDYVvoeWm|U^WW6q$MW(#}Z{@Wi^uv56UgMeG+6GD{+B=y)hwD7AeOdN%{bQC%UtE7T=l;y@nib8; zno#`4%5+uY&$@d86J|a&)@BUTWLT0?*!ucg{=;2=-TNKnFUS4jS$R`)<>r9ilS{On z7OOR8S|}>~KQ_-j=mAq|Nyg&n>wLXgrz7U1yS-Q?DDQ2OzC`kLCgVNz1uHkLd}*k|X7*Xhe0Gat z5%=l4uE(Bluq@U7GcnzpkzaSpI)z^L zJipgP;a%01xGhUQt8Bl=xjt%n@icR8l}!y*H+JxLx<c=}mvDVkuUCx%mu?i|9Itj}yxxcJJMGK0K$K0j07T`_w_ zK-#LMt-|M@8(iHzrOiG_%wQv%izCzVhBFd*!DrVlvALpRkB{sLR4fvDoHjYu zuyDKgqW3`YOkA>KyytG$E1cYpi>9r&-7KHnyF~J^a1= zZtT97UEJy>H*IsdOg*;i%&I=3x~0L`x+m=T>$9FdAL`7*G-gTr-c>o7B(z88;p5dt zi!N#!>``m0=iI+6`-A(%ExrE^zdOpj<>!m?YrKEI{C&isAF}TKpO9@2Z#0WCbDlFg z#HHn2u;VkszJS*GN4|L+o51(Y-j98gnLzx_h{OA2-y7_^|53GTnd6O1!Kag||JJQd zf3Ks zc|YwYN2Kqb=G&tvjB^&10zbJ^0^iL>w+xL6dev?JPoa?>`wV3a`_`>|={ddcx=7(+ZtX?>~ zq$E1@tJH@tMoD{>@^9*`z4LqNgtK?9T;I0WW6G?*(~q=-g(U=Bo9ixBCZ5O=d!%>Q z;|EH|n#7AHZ+)ZfBl{+kVT1pPf3Y3!ueC*9Q@-*>#rJNBw_AL<{O;L$e>(o{P>p!?8@|>(3^6?oEx0YKxC%S-k&w z=(gU@Rk`_f+KpNT$LBuVtmS(vG;FKz@$Ib60^v|~7bBERIYz-g^!{#obmu>az1o>n;H$Ne?SSa>ek z#G6lZiuyGnID?HNS4Cdq=uxM@VqasKLgi`^t)42~lxsKJXKD9MTb_5}!*3nSg6~IX zzsp%Np_^H3qOYZV#=mV9lWQE}F9zHaD>=RG6cPc&b)9J}P75}ho)pnO`%X8r3=Wh&U7pX&XbT~Tzr z&*_KT$3~07cPS5dOCMQpz258X?S8$C0?~xn#94WV9qN-_dKF){d3IFqPRX{U{o8c) z+jAr93Rk6{S=Uiw9L<*R?L0A6efx*bw`qy}d(S7!ED-0PwP2w$XRWMd#958A%iM%M z)$j7@pP#PYzC8WBKi_8YB`$8VuPj9KXISlbk=Yj6TDX_HeYk z4&SpM^0&LnPdK5tgZ0_2$XWhplo;-b*mWcvQVBPbvVHa4HL0yU-}PL$5R3DSE8q4y zSwv5`BBWdRf_ZU?;XBcd%**X{<3(0z1g5LF3Lam%R6(~neE$LQ?%vPH{Y zQGU6>rqEL#j;wz%dD7X+-R|bGzrp-$xCl9+W5i7 zbw$HeOWV+^@odlQuUf8RpCn^@TjwNyLcIK5wX?=w-r0o7cKx{Y{qLIAeWB0q@>HFw zXWT9-$yC8mtNppEl)btvGRwQ@DbMbCr_Q8>O5yOW5x7T$I4ZkG#NyL67oX! z@XVDl-95X7Uuez*)o<4?7;!e+{8-T@V|94O&b{eT4A%OoTl>Q7o2O>(7VTJg@A4jN zxyZ@@wy!4f57Ks@{}#PO_r1rBfT*4YoRzsTaZAq~a_BjGDu%!4vDnAv6}!cE6-nkc zT>dptP&Ht7&yAVlBky|roEFQ4BfB^YCS5qR=bXplSrQARs_g^U zmM>>+xN0tb;|?!Rro6Ehm7Y@b}B&r`dsva@k}=EvHr=11-*Ea;LG z=(~Muhqld)gSkV=j}@#Pm2lr^Wysng-ONxr6qXX%{! zd-S@Do_nHS{JFoY=H5K(cJx@ER$x#_`=g&r%y)NQ5^?&*ZM`k#+{CcMn=DPYo_*T! z+qV8OgXxbgAO2nTRN`>bKjx8V%GH;d{PN9bYm476k0u)V$;;bWTG?4ySJl~sxa$?U zh1Sh_u~1sov2RwAt!#hL3$|iClXH@CQrB%4m>dt1>CuSt^}AF(*Kdy4k+y=Dl8e8X z@uwBvC^5>vaxurR;fJpD=f{jOm*4!U+ZOw&)zwR+T)OC!kp8NaFdf6=wOb1cFLWF% z_;dJTxqJG}gQqt?_n$9sqn2mzM`W7JMokU3%D4=Z_KIDceLjm6ReK6~>N%sr?7!aq z5t1t1n>+bd-{c=FWU`JeI@Ea8@x1cu#`NWD%nxz5PMI|=BjTN*dcJOg>4R%-Iy<&} z^;R;8IJPnAIkQD{@^efGNHWvyBFSZ&I)C#j19l+)6~6T(=u!MZ{71_mmB=p z(CPBrXHls9^2HlM4yy<%>~*=FoIKI*#>JwCQ98@N@LgW>t4{R7g1QC!=d$OvnI&o) zzOyNM{XKQZ-yMzj=c`|Oa_!nnQ^(vTGOZs@%wb>6C4KQ$+=Hymty9CS+4HY6Tw265 zZ&mX7M9JtiFE(tupfTqZ&()4)VRu~YB}`^~F{wI`p=j3qaKl=~zYfQ^Ca7M?Ih&BU zqxt*>!?bfzciA5ZwD1>PU$=|Ve9zRTrJ*i8Y+L*{zh1Gq_j7|@^z`(*+Ya@uarrZe zq2@@grFhmv+audI&$cfWe0*z*vj2fyQC1@QoGR00-k%fy{gjDOrRmOH7B|J_P|IZ+ zGs`vD3f%IivT8YpO>#S-cUbq`L5@ZfzuDVg+r3%HQT=(%f!9pEUdGI|bzh1F<0RCS zXC2X=l&IZ$G^p-eZuY&&)3c>sd9C$I=9rnE#y>)k~QxZ zx18LGRIRv(sYL2rl=(Udl7xRE~vU4$Ts!k@XNdW>G#pA7ZMYiowS)$R(hs~8Q%%MeQx&4 z<2eWAmKT3yH?I2n~(qUv9O}`B15Rm^@sAD>$l`A`ebvt=)~?dB}%6!+A|6mC9xK6s}Dc4$cmd?FMrGZ z3@yF{rvejO+z*G({vD!SUdE+>p!w>hb=TiH{4_(;1p7soogQkjpODei~+5@tPFtTmBkQp-)|jo){K zztp>zd~CV@i`a(8-x`bBb)~l))hhU~^@2msl3np;dwkQrP2;T2T>G{`HSAoOV9%#Z z?|C}?ckG{awA^Wt-?gJofeImw_3keg#LBFn<-F^4?=p6ywPCDs0->Bq8HOsmFYXJ{ zFtIs(SfbHTQs_R5CYPScwaw==PlT;xD_MBx;XDcP=`x9zL(kpxm6&Vwg5{i8+tFLg z)RkVH+%jKiC8M5(4Xdw!yO?@%tl0iFS1WywK5@CLar5ZBr9H0IzPVPe$&*|UCRm3S z+AUNTT6}q5zLK>41qXS{Su;M#9S*v5C0W2(dhI&`wh2+*qS>7py3X+PacBvWmrJhOO`m$T? z1z%vX&4-_Pp-*N0a9#7@jj>xIlJHdu89!2@) z+;E)2S$epfee;Z-y8GEZS1Z+iJi61m_q1DE;fcFDdQz{f_*kiEZ56?BSf+eMSi_ei z8(MfbpLDzM-uTRU%d`cuQ4uW9I{2;sNU!9+FzI7d6sySUn`IAM{w;9w+BS>7sk}u` zPeD+QA;yhUe#7jZIJ?SU-%7b;J?HPKsH-xo`1R}Q?C1J^_m-(W7m;JEIpBA1(Iycd zx8?SA+^%frDq3!PSWLI_xU$bSxzd=U*2z$G1Kad{jrO}^@BhBqP${YYW6I&9j=L|< zaY~v{yCY^w)`g8H3zi4#?m9b%bF1-<57RcNH%@#jFhd|QgN;k<`pvTkT57IlzxNc> zU3Z^*Yit;^@J8uU`#*b~p9tia^DXZDc4LEf>46h+zc}Ytx_)}hHv9NIiKKZMQ6#9r}v*_w4N6V{Op*m z_q)LQwVRKnK(5PzYroIuuX3NW=jG02{~xApSjfM<_RfyCpPO{M%U5lmwlz5F%xj_B zM`mAdvz)OZV~M5vHS-s$nl(;JF|}(=m(JaPdJ6G=qz=-xlF*W z=(e=YT7@+?7bPmQ^9gux%)8j+mfBc#vcUQKq6oKLE7l9~?-drwFnq2S!m{^I{)@Kk z8yl6*PHo7mO#W?RYy0!(*>!K-@6BHukiFdf!@Z?EGVyC1pB(vmKGvm6e({~8!`D2f zsqramoy#%adE<(eRr-tL?%ulVbj_Fhop^eD-Q^pLN>zLd7#psweO$KY%$2}hZ2pXk zR?7rxdh;J!Xqwv}_9aWSFfp-Y?#lbG!q}OUzkOTOy82|6=&j4QWTscx{;+s=ZHHXT znr{nk|BC+mFJR4vUuvTFY$es+M;Tacd(*_;SNWsoiLYhfBeko^0>4%IYSN^4u2zcn zU7#LOEOKsPq?dfQy8nuI+gR9lOunOWbi$>)KM&*{uUsme&b)wS=MQ&19gdZ(!8!H? zeJUIG&-}!?i(xLyohiBB0#&ZN_RV|B=cY*P8+opi`l110QZcUWiaUm${L2;E@;&*?K?oiR49WssUJ)h(q`;fFj zX@8A*m&ELIX@#%zj|r^OUcFU+N%`)rdoy>J@KtU0zAITSbt5y!XwqDhl>KZCwZc_e zt{djwUX-M8%Tw2ARs759Wii1y4jIffXX+d#f06xr?O@(JG;DYd(N>tj{S*}NUgK0Z^GHmDVGIi0h? z)%=F;DGtxj{8KB6mdPjh|J`(MR#QE9t2t}_YqP6~TMks5V$+LmyVEl(KdA1|tz+|T zm!+L}^_AaBOX%7JnOEg1f>Zg*+pIME>X+R-Q<5O?aCr&;y}k0%iw<@<$|h?Z5hxESw-P$iN{W$h7S0f?vuUeqnjr-fJH%jC!lx@D6TK{WX zcX;w5w0*+SEoZf=i#lYd9E|HzNu z$97-b_i~c>j(HQE|62%f%(|N5n2;gU$HFDJCiYIS_>AQnPp{h}lXGp_?UFff9~-_Z zbSRk}{429ULF1`iRnC;+NOQe2UsZSCHZe2Ue>TO{U;R~c8ULxHQO$PK18R5g$=0mW z_O%h;Rd?bfpP|GN(=TVXu+864UbRenhZ-+qLX4Jj(B$w5j%Us)C?1b&=aky#z%kd= z*0)ViqvAh<6MeimfBcKObt*-t8sR!1#Z|L9Ws z-A{2wcU&x8T&+LqUFv?QaPLZm#kJec-^G;t?lBk_E(~~K62FyCoo()Sj*Ef2I|X_- zPOJ7 z_DV@K+g5R1UOHn=_*dN<3o3f+KC1qDk!&j2=Q>|@c5ypzMdULUY>9v zMkC_bvW&}ilhWPPzr9Po*!U>o8)uZr!oC;p|NVV`{ZF>oQ6vBLeBb%r-;EWSyj$U# zmReR<{b93jSNF4je|PYHbNl!2Z}-2tfAQhpzlZP3%G|B4`0?T1Uv_@^e|i5O9Q=21 z?|s$Z|9dzim~E%2?Ejq_>to+=%AfttvOoVl{~tVgDSO_M%vE~43!aLZzu6s|cxt)6 z&UxQs7qmPtS!*6S6ISuaB69oZFWMfC8$VypDh*zoe)?kY(c^FBW!@dC@Bgs>`=lq4 zbDy8gG|gY{xa}*CirbsM7nPQG4{Oa^bNlovJ3qhMHS?yPJiSVXyS0CR+@<65MPhev zk2~Z%Gl}opvYYY?FNnH`29#el%v4y?{{35DnN+6$PrnL#^>3BW!S|<2daby^$55`^ z{i=%p)emDvdG+7b-+OsvMQe;h(&jinmwxx>@snjyi)U;&m(IFpvCp*^Q&`hp>9PI^ z6u;A8QhR;L-=4VRk>>1mHUD27e^PzLF-9f-+GJNl-#C%rR_)>)Gs7obikb9;U&J!B z^Bw0I?k8EPC)_Wwh3}XhVj5y}D(Z!0W%H_2hFy=uBeT2Sxw7XUTaka)du!s2NmphV zt@>TNFYb+#D3`_0mp^avudlc9p10?h_ovH~x988_WA*!VvTULMU57WPvv)=vc)G?d zG+p&WY4M7OPfy-nZofjwe_!ptM?Y`IAE@|q^Yi9#_2tVy+?inGdC#V@`rDtE{rdCv z_}=^T(^^U~$(AFKJ#ShXHce*B}C z+uT9-hSx+1odu?sJ*3{gI@UgcyYkc5)Z6R&-rw81Z{NM$8rQ2sYZnF>hF!Yz_p#jF zI{(c0^si?(Mv7ewITWrb!nyruOU&A}n_jlRQA%I9R^z=%*3E~!l82UrecpKHoXvTW z+G(%fdT=va!l?%_?U%yCb_o zbh}dI%T<9f`|kU8?XBsbZyed){w-)@#=-FO_wL<`bvRz$yD817$|AHjd5)>b=iMiS z4k*U1zw)N}c~OsYUVrnSzJjwwMJ}a05i)nK>h`3tS|?7M9&F*6^p4@HqSOIiW)TIc zBP%kao2@SdZfmHmE94Yoe)Io{5D$C8h3gNF_NF}BBa^i;M6*isj6v9*rnt3N+9aaW zi%vbX6N{{!xY$=?Mb%`jDb0VDakt(oKWpu{P2<3#mLBv*w#>9vS)c*vK(Q*hm{ z|L^~Q{ol6lbH@C{l&l(Fwt3p~51+J{Rv8m@`*f7cx_+rso2vp73?N*cH1)fHPlEY_d(ae`P-zDmvZW1=OOpC%sP@>MDSYT~ol{YtTU z39k;Gzjh%|t#Q_se?9r(>no!tE!Zy65Un46%UeQO&2-bsgIik)OK#fUXEywDZdyS*R|6?07WX=i17-UalJ#g*T2lc4ei$jWA3j*>*SEY0xma&<` zXLXCuZ~g7nCsInHYYvO-di_Xi_8$i8?^e%er_Y?4UDd~W*XaNoxK}RpSBqZVbWwumk=v@y`K+a9 zt`_E9HrjvUK!)MjaNms_UpI2DQZ8O7c4}2q%ig2*MXk9DBV^|EOxwnGeQSPjstDVO zCf=(G9`(8kmja$Ijj9R^Z>rq7^;m;S!c?J41JAm zGpkXwO|#MRerl0i)oC7H3*WU5Z)rtcZqNDly-T8T1HXvv#B~9GjSfigO`Ce(|Jgj@ zx5tjswNbH0jd@=AxDI$X|i z>Dq%d;fSJ^N%IvSnCKq}X?yr1oMTyEdZ@8L-ElU)eM`R_c<9cNa`=d2M^p1%)!+vE zV<#WWcO<*Ye|}=sq*D9Q!y{%^olCewuGVIbtD!6&vPmWT)y04|A+lKOWdr77w`M;+i-UB4|$KP zOb&bAd)z#JUQ1E0%#t^HkJ6?pffbh?sp)PG5auyFs_*Dqu_uU!ZO*zw5nb}1uCQ@x z>FS*-{jeh5WPgj`8nMd^?~zBP#|TaPGD75jYUnaH0r6>d4xOG2-P z3g2~Hy`gar>(ReQrED6PggP9}J9V7v2^U}bdi&{Drq8aCDmJ-3J$&71k1Ugk0VT(C zUi#QCULO!HdFX*`Yf0LS!1$KSZ3|Zjo@_Jba_n!8>Pq8OnpWVy{`9)FN|hH&>;pBn z_U&5p=7jI^lY2fCF`Mswu)MG=)ZxyK7oq0vX{xvM(vMDhoW3&SI#=g6S?9(VCwt{~ z?VDAt{cc^jZ>)o0{Ue#8FQwg^zA@}rSn%(&EBz$>iUMQg&~NlWxyso)f2H>DF;(m33l}MZe-iuS=&y zmXv(du{YJ)eKN8C(C?TW|KpbycWyM9@_pNi>CD~|LJc>Sjy~`@`0kZS?bRohoP7C8 zC$k)zrk?Gxa;i+d+@YfC6@HN0!szzN$Ilgxd})!XRuqf6yJX|kIEItLj}@AD4d$Lz z5-XoD>uAtsjU2J&vx~l_U98%iu{UzfJ)K+kv7)}0z2_rJgcdFC<jc zq;h}r5t%Jh^qg0H&qC(cy+1lvTf5{Wo5jMUUCZvY4JUIH1AyQ-oA#o zt3Pe3_9(qE;4yvSV9IU1Rp(Tx@RD_66J4g9UU#9l_zR!Tw27xxXRQlU>|@(oohMZ& z{Iqd_?Ycbxzdy z8h7ip&YP1r_Ow+p_|-&K{`~vs%KpV=mQ#4_xp_C<|K%z-@CsjQe@4lbU;uT$?sE{mOl(yYD%trU=)5ee7I!x##3lRqx`; z{V89MvWK4Lnfm=oDw6B<#{@%a6 zYTxGPd*`m!GYA#4e*Gr(#b?>pXbX~L9>0T;O)sT0@@S9D#>hx77*M@stxGS|_ zT?Okb>9Z0_-{jts>6_ZI z&w?eqV;9VNE)&~-#&~P5$8(pplKs-mo15SIxhnqgsokQt=w9y=#vdX|rjGAsmYwN4 zwKB^t^mg)E!Da6wT@=6BrQ6O`Gjb`iJbJLK?N}psZr@$|&Sc9At7_)h95rCnU&S31 z!wA;r6v@o>uIbKlYx z>I|nEowDwd(*bN`yYv2gvAclZ7I`Rm^vnH=oy)R1-T%7WW-3I*RV+8M6+#lXKV zJZgI5?!p;zGE3Zl@2~rtc-_%>UfRkqr{%sCkuO$g2gsgX7%8Cbz1H3 z?S^lvt0I}h+8*zozGq*|grpnwoA{m>a#VzOF|B$q*CBfEg0>C6e!u!UbDJ-Nvd)_y z_tJ{@KIVN^6~Gwzrgqg%xu_2jV%780*0rzNe=I3qyLj*M{(9zS+XbZ;pFNLH-@yL4 z+pYSx)SHV3{&%WXzyIy?t<1{jo8P@n?@Ml6T5@+s-fGp>xeJ7!?K;=y7QJD!dZ}yf zQugSKdA@NVfYqnjdZ+DA`IuPtNG*vh=8b>~6Dw3)KcJ6{E*+-+UQ zU~|=ZbH+igDGIHAioblnL@(@r<;U_`q@=)oZq0fF?u?m^w$@2q5e%$5bi^XhwpF|j zSD}wc&8ri-3(xnHwY|HJk6cofY&h<@}}gomo_( z<>2c2(`z=(w4w-<9x@X?G|r}39A*gU%K> zTNxkeyLI4DCa2u@HxG^kH2er~<4Z6)Y{+mR&N^Fh--+s5|FhQpZ+iz2|B`zCes}&qxqHu< zKHKtK@MB2uTD^zMn6IUi;)i54Cbm>oMq$sx`=2wM^u_tFpbr+^laG^hkPa#k@^Su3)s?HN?tx%xo=(fwzHc14%{}L z#UC~6=$t;K=!!!N58dxt)0o}bTW7F@K}qdH*`J4MGuIXyzL*sfy84+~bmtwPo`O)z zjPMJIhqGQbZD5?fSf(ct?W>MIQTf^Q9xbl zefI7%SFq+b`EmhZK?ZOhw0!?bX}&r{I-D zwc)hzEq1$+jET_ zrdj^+a^8Q1|G6wrYCOyGWekU>9W;3n`TLC2^mPa2#F*7?^&~&hUmbb%#*N;4>QiH` zN+fOb-P-+Cy>tKag0wlC4%DnzJ8NHM^(Wav=>Yyoa=SOQ2X{_uITOt}scyymbZ?ni z&YKHzUw`|md04!D16NQ;>*dq^&s4hdi@m9}LSv~*%qQgH6xo6-0U*H@?>v;C)!^ zm}%Mab4%`VJw_up?tAZMsz^R$S;DyXgWVquF1O1OeX=hW`Z~s`|E_IKc@Ux|Ides! zOUcDKyz$e!rH|gyQ}9u9pBQrE@y*Zk%Poa={eJi73oGA=J%^20kBhTRF1~*{c&>1} zW43VZ#hQyeyVvKfTB^Rv_N9qy+7k0i0vgdrxhfNdIPw>N6>72H=`>GGvi1o#=cUQ> zHJdb^UgX;R`r_#|ekbpwEd92CFOAPH@#bt#yTvCDR<~y{1iZ82tuAp*%iYjhdj8#w z=|^R+Di?kJRn75(;Xiv6pY_kVdwv&nb85M)*sCq}Y{T@OQm<^*t6p*9=8T{JKHy5@ zx3*uW9ZozG5UH!%w|JZ7>V+o@TQ|t9OAh(_>HKzfvA-F0&duhJKgir?;o$ndVkxVs zuhjk1E6!c%Q$5fgV5)jvEclZLbF7W)OD&5VdJg--pUK_QNK&hl*d0)5R zvZLn(Px~Feb+zq&`9^J{j1FtwMnAhnn*-lyR=-pI$oi1ewd~nj(+GFzJD-^rmv}5~ z*jmSudB1wgdS%Bcog#@z`Wlls%uIGZKYQ$xX<_rZU4MJ!yVlJ9_fEsGkjc2`--_6M z$@VWcuUGES^kpsEQT(lLa%8C6pQZk9((ddqQW0f}U2V1d;LOZwMzy&N@&6SA|3Y^?Oqv`gsgMO)tV&nHGAche;M-}U!}h}ztd{A zgvc`09c*`P_eX&*s(7eH1g<{zK^-r;C{nmTlPe?&{|4>*9;TzTUa<;$gR$ zez{wI+B=Vn$Itx!J@eHD=V>oWuUZFvo4$E>!SrQM+}PI(3ePxo{NxL(_KCW-nw=pL zZ*q#hMTTvA@;pi5)I<@xmAlu<7OE<)FYvK2WB#_;HIUb1?;Mo{YPT4_gjP9BHrgq9 z#nO$N`K)<#XKx5=;~c+9=9RTG*Gj!@|0wlH?rYhk`IpnCdN{r)bINuu>hMjn<2e5H z!M||!1xvm>zAgT%w#Rh&7wMZ{7VTIq^g=Sr|L-rizrUELsAxs5p1!NZ@>kE9=bw|J zo=9Z;TWjjHb>YXSJ&%uNZ;0LS`gZ1vjlty~m^#XfvbFV;jvnUJ65ROTV!@1Cub8$z zGLYMocG~g7juTx%Gv4kyJLTe6C#8k&-#oW8cx(LWiS1kEv}s#sZrvOqKUwD9)=w(a zCLFuuA?=){DECe1&(sf$a%We)yme;bl1HZ}7du^89NQXnKyyds^T(R3E(&T+P6tv? zp8LqP${~iw@SdvA+S*G2n@+r%DVY9Y%_a8q9^3uS?^EZTF=1SrWF2x`)WJwxcG~T; zjcEqK%a*Nue(_ZK(?>0q#~vJCC${3->z5afDc1+w=__r#AmkXl`N?1L<<`!P2P?by zkI1?{?mcwL?l9v*^U!RMHFFkl)hv(L7JmNxy!~~q=a<>IOwPIARIs_o-(;Wq*&C4; z74$ny40noEuV-KPczPlCmnF}Cg*SbV_+lI8DQ;w}`=zc!@7RUKD`tJly1VSE&0L3G zH$@qxZBssdTQlv2=o^tqQ3vBfrz(Ep_O?&ERvjO{I4q6h|I+Z&tg_CPYo9F3Jy=0yjYjH%a|kF(te}< z^3|<}F8r_jH2w0IldIof%8#%AE?%T}>W!|`l3BVSJ4$MGW0bP+W|T5^*Kv?Pq4Mxb#HC`{ zG+8mVvm*R&TXoGhztRhRvy$=cr4q*D_gXTzC#MJQy}{qsvSY?-i5aac|E9@Q^I8Sf zAA7qnzWT()EhZn2Y6{rI&vA1JVG@#FCECa~cUH!O0po=c8XtzGBr;qI*wugZmSU+p&`+UN6#7@TyYUoe{dh#8_L^@edZ+AC-x&0; zQBgyZ$D75GYk_gUmW+j-p{s^8$nyom4SJN3rK6}RegI)of1^8|1T_Hw(c<`lH8?AWj% ztoA^N;)~rZA+c#+*=J2kv)wCmVQ%f4i?h}U{kT`ZoK46ic4CdT^os0~C~OyZJw9-`-zE&0^jaN&8myclw>4z0F@^k@9r4decjMx9V5#=e2A8VXMXN zyU^qm%ZL33Yv0YU__W_9H88X2$+Lohr_Rww1XIO)eAV<>1vyvLEYtS>bReStxAu-b zuURBB*%QRJXS(>v5#@n0sYjt$>-d>QMSf&2)?~5CE zId-2rKd*91+V1K3!G{CI%CCFhUBrIxR(_V)_cMBbwl9B|tkiVUOSs_LyZJA8B3)f_ znhaHcsJ`EOV~N%y?m)93l?M}Vhgy|p87^ENcyZrN(NjB@b$qPsT)1HJ_o!T+_-Bq2 zudh2+(XS@xKIuhfEAa%Acs`Y6Bc$*D@vKls;9tp0`O zw^Q9$ywaVlf2-aO3Nx))f5Y(NE8QNe)h}dzCB8eJd@bH3)^}rzt6GahVT!@d3w*0q zN$0<`Si2_Bc5PO`5uX)NR(`@!jw_P%RkT|7{;;l)nje zJbPeDTbj-~{^NWGTC8zqZrrk-EqRAF8{-FuM;qQblx*U9A-Q3X z!Zn5b?9w6KQ^GivykO=;fluzqWW#J1*Z zQp+D?Ro{~nt@@j67yCGEwc4t1fmtk>rr-ba%;xKw@Xa-A;%S@wHPQ;f%c`9o@n^Ef z32gr4W@ssFaq4{B{@R&!oG5@g4WyIob#L|{UBEx!>lw@mdP6*96xz(7t1%H{sIG28Q)g*?+jwgqc#Mr);PV# z?AbMgaQi3Sp>fjP!nzkr%+zKoY4iENJ)_j@uJ0Z6gv~lk`nRQKUR0dwK`o}cdzu?2 znjF0t&anT;n;SQT^Nj*BHtkhEQ&jVN%>k7;D<_vOE{OXM=PajPD7XVz^#ki7S!Gt=c;NdX66+pJ()+Qt$6U~)3!`LH{k zw)T%UEm|caJ)i5XNL5<-FQ3(Kt4;}Yl+1qc;Nkv^!v61HsuN6Fd%2A-IR>)ldMYfE z5VySWVp-R!Lf0mh$Feu0@|-_CHr=xO%e;f-$sa1FGR#VJTN>jlNsIYN_zKsXWkC>n)EK)R?>2%Dtm-c z@N2i=Aa+&NS^YBYmYef6YZpYd{CKWa>alvptd5EQzcJm~!EbeZL)R>4u@&nDRvHGj z@0{`YwKxC0+e};*J$!af>7IHDDn}ivzc1wH@oUgHc6R-(o~q#UYhUDNO`n>Wpr2Ve zy{)C1*LL{@q4tkQ=04uE`SllzH9yOiE7?fC`NYY#$@^W*FRy71v((Qu-aN)HbLjHH zD*IbUxBc6)aqELb#%-y`x8y9U;jQnzPBlAs_nJguYXL+TC%J2*01%8wz4&= zC$VyW+5YuhzyFCdD(*o;;sFZ_lrHPu3Q=zNqx=?`Zz&qj^sIWYfCUjeVRYa{_d$B<$=PErn)X zJiy0Qza(MHind9UPccq?wMJmkT30o%^NEja)f^-%rWU%{JP`bRyL(}L;+9@}gRK`n zbm71^x9r>Z9WQL%ZcJdz-f`+uNzebjIAm9t z;=XCe+kQUyC;R^Tv$*9ov)>(yc;dhB<-OI_kEL9!SMSRDocaFu`E`<&`^BE>dtNwc zp!!zP?ChlyPOd|dFIK&(Ww3hTxI(kt_40|y@`%tFK^&l<*gl7XYRO4 zL+Mqf%b{cuB^mXqG-vk<+ZK7hXzuvBB;B;`Y+rAlh>F3sTda4=r_`6OsW~n(x%A<- z%RWJqqkXqF-M83zqqF`h%VMSFrl%j@&zN<6-VN@j%S3c$*R@>QUb4?rH93UgLnaq9 z$JwHQDed=t)qNk@eO_JqOD{jrhwI>ko6jF#zP^5+^WOt3ygDI#HWiPrmVWwtS=_#^ zeA2vsKXjMOefQ{S>+OXvZ}O`g7MR(itMKTy-u#No~qk% zJ27h&uVAJJYNtZ47_1eVcGKAK;KsnpbzaVwufGUsVJ`0J^n4`S-;{PTL|Iz*81J!~ zp2N+HZ|3~cW@DS{8OgA2zV`*^rM@>-+%?cnb7+jo@kgT;b9EeFo6+Rq%yk4KE)n12R3qQMn}31-cLUGT37dYF7`a`^U-&OnLA}Mre}}|k1G7TM;^~5yoLuuv zlX%Q-^_nGXt|+@X>iRSe zDO=ICzZW@Ow(cm5v|;^s`$Puw-0i=$U)cP*ZYwGM?`_wkpbnYC4`04b+x~p*qykkF z(PoR>JH^3P+n>JMc0Kj~RLMJS&T0lV>F<8Mnw0)cSlLNszv!oPXXW^Aik!X{TRD5N z-elF9oGo`}goPV&F~3;E^yft9_Z>X3mHWk~PLcii;!cCUtM{SJ-dWKZ&)7vLl&^0y zS+aK9#)sSm8X1=P-Uc$IagRX+~GTE zFU&5vy)tFF+N|eE%SAswO5Pb~wE4@$9lwA4c`Pp9{({#zXy4ByE0z0VUu<6f*y-`8 zSBm+r@Wf};Z}h&O-PW4OzRr8Avf?IwDURoQN;~%LxtO-EV4mU^weZyH_6eW;oY`F& zZ#&7CUOE_-k+V;io%y}{Eq}FD)3uh&Qr$iIfP;LpSU;>dZ@ed)G%t6g1($NfDaUr2#5c(3-~1c##pX%o zdd5I`QQ7nNF0b*kFDsjINU8Vb`xF`8xyxoatx(=)x$utOGxzK5y9{2xKh(3^;Ps29 zcgNN&mcBDpvLsdP{i)pAYKeTgsI=C+AiKXB`;u3>QDk7uRpT`}6tb^Lc%n9Pj^3UvTol_Tvm6KlkrWl4jZP^2hAnu96Ac{U2+D zSa)CX65Y`MwAx5ad4+w+!i0W_2OcLhwZ3TzDYqW43fj!^{)|WEiz?;Q^2+bG-I-=< z>f*P&Z0(_{#}SG|b6y+XbsdBr4=SFW??H?PW#`hF(vv)qnO*7ki0S2jk7{1@=9nkDzxO-XxV zt?04(u!);xd*qMvWtFTk=3u$lw9k@9K#OIoFCBnzLtON$HeZhcXn=AsQc1waX3%jmW(5x#Lw}R$^DhA&5`EWcj(}IgSv92I9-D; zveK1rn+#g+yjgQi;i2xuBTSFwW8Qz~vi`~Y9>MU~izHQpLHrhApan>=zrgQt^d%Tr*2w$2ZShtCr`Oe;{)hh3fsTWxr z-ksFxTs3L-;R5d;o9-mcJW*t+^TIzrW%->=dBFxNcFUFo=bE23-h&ET4EStpmD z@17ja8E}PnufW`YKi=H@JpX=xKuBG#QCC%n=B_`tO^uvCm9I6*S=$_x{Q1~M=YYs~ zb=8uKGa20D>>i!7p2Yo_JwWlrl+^{Q&vVloYuoN=yu0;a$+}>+Yp>_xeU`AZihpNRdoYDUg6iJ709I!cPX-m!JGT(iskCbPk! z`~KTW7i0HqO#XQ%c1qWdKWnFMQ++qB{KWHx*DL=%6RT`yQR8^Z`2HoQAk(6Td8{!f ztfVAwN=S1@t))`QH1!DhbnP&+M1Y{o=?Y%xruS$5*W}{#4*KIv;a@}6xW7qaw_3-(#nCHh9+hS!^uL75gTZPJF zzj+>*xa5_{L^pO@WB&M$w@oY7WhmT8)Y~Xj+$TIeay7&9b)wT*-UPd9&*MEV8y7Eq z{_Sef<$|%_UY`qIubh`~Gy3d-BhmR=w8O)q6pKatWNuHD5MTaeuA-!@uo8EYtKzdB z(G+p36S@+zo99)rZ8HmaF;nc2S!4GOn=_BrKB}nhD}Ob;^kUifgRgVabsrskc>S6( z+uWSfvCAF^Rx}<|{;hteUy?;EdZnqO&iCdNciY=Do!yQk-}cP8*!BBq@Y{@IB2Lqn zhvq&yeyYu-@k-vJa+woTBl23)+%s<2G1gyO@as%k!mD)w=1INtI>e4{a#(M>>d6b+ zrls9~wBk2RxAJ6Us$u`jy6APLtW)6bd5g8K3Fu4@34XEceEO0j^Ukg_Dix0}P+cX_6Q)v=CiQHE`m)3IK{^{sLf0N(+{5Oq+4)>YT%^pa zu+X72g*#zKo=3#1kcj6(ktSE!Dq1?Ef}hG=W!l_u(LM9U^hc?j&vj)E8tpcmSob~W ztyJiB=8x;6*9GQE&FR0kLaHmVeZ6<{n@u;@D3&E9?9M!q-tVc~*_3wZm4=C$p}uG7 zk5Iq5P!HamLtOkqj3sP&4H|5^5B>I*1qVs1y|wLjtzID7uweZGwMgwoPnXM+g@b$~ zBkGh56(_8JylyjJ@4qjisXS-4`_KFL{N`Cc;5{-^&`HEvT_ z`&Q@5oI_7mdsrDA{{DSy|K6^cnoB9x#;!58tF~@<(Y@?8*Z+sFrZfHfICle2&f%XI z=FWew*Tl)6eEXf}rGTTWzUeNw8p>4Oq1_@Jx>V)oqc5?RDr=WndtO+S>;C?TS?1k^ zw!((I0mo(^Gu1!qG3#Sn-R@dh-pM=DH>Rsd%W9QOynbJ5ao}REdYui;dm4jV3t3rS z-7)a%Wv^wwzHOD|{plT7jKZ=LZY$XczO5({cG35HG1K$5VTY~qu7YhRY&j)zs@oi` zctZXkOlsBRHQ0M?D$9|up2tpeElN~hU)HKg{q@qK?^{vqrm0NH8HTglM3wZHWX!Z~ zd|@wO@B45D(_;yZXVbG3nPmSyboib2rtRhBD;gF1t(K-tcxJfW*Kb2WUhEc!qbs;m z=DKzoaVDL$JK5kkWp^UG-t}cOj)pr*h-NHj;p`OY4wt(0$l9vTWY0g%Ggi5&A1(hh z-=CAaXxXv9!G2qK_5?GkmxPKMSgI5>R!hEKVsYiei)8^zN>*;X^L3j*u|&A{-!p1l z#xaW?vWFV2cF^8??k0n$&f5=4$;;a~U3UhwD8ytLtbCa8S7M@GWP{$$2J30_H5YMx z@$>mT{ia}O-t{~;515DUT3sz(gL-p6FPlNF4UToD)?lvj0r5$nX^Y)4fEq(oG;`0M(p&K{b)YZ9OU-l&a z=kCe*^?&~Tp1fUTmvwS~$1PpPtnAk-h1krS<^^URpI7O2-QoX|gIx<)uKCGClqW|_ zzcV)}#Bq-4oL7rVeT;7GKDr{?F6jA$g>TZ{ycPHUlPBqPV)xpkGcNMVNyaBAI9)R- zdB1yGdF--%$_W>ao#gxXlF6vw#`@7VgN$2Bw-(t1MKsOycze=DM5E*Ekv-}2T*a7$ zWlmiEeI}^zNwaTVWoP5vTM-7&T*Lf(e8clXr=)c}S4k`D>fTt%bH?s}SKyyjg+G)( z%Dni;QYI&PwB7CISHGf}tCjC>IVw`-d1%Y_H2-C5m6smZkndob={e2$QN{FThACb9 znbyspvm%k>UP!K8YmH6OL-ZwMVg0N~g*@&%_m_#A1~?g?uZ+8SO?1x! z-4iSuQ}3k3E?>}@{Qbg@^v9EL?tH4;v?<~D|F$2U2HnMKM>nik-p{Dn?0Y0`{nxi$ z*9C6~N;dXJYsYQWUzPoAV$X8-qVDtC^UPS!9NsR#5@%;^Y3uD@XIJ@4*($E_wa>dS zj?e|mIGInc3r}NGInXDdQ0T7nS?lGim7EU@{vUCb_|cZX{U%r7thQ~ET)I8g*Bfts zTVk`tdsnQ*REf>pFJc9p928{IR&A|UnVP4?(5`*eG=js~W{cNFI|+@2u7b6b&lVfW zsvcsvfACa)zfDledKX}*F1fF{o@2NzMrPA4<{cH z&A5}a+T_5ud!H0;g|yUH7ws`!qgnEEwcgT9y}DVKT}u!CHVmDjy@Shvt50c>?)0BL z9$Bpg7RLVX_B>hMWc@4S=8M;RV?P@G-l5#l-CVhWN%81~z~KG!y50otmu?N6us>nS zjLp@hc~XBGJ-#nrAvlZ2m%ZI8VrFGT&&l&1k4``9y7S}bnxM1&0TccR%I*HP?0ArL z#pPoPI;{2rzO!nb>Wna5Zeo}8f-}BN6NsDyDD5GEZ%O?MS`{(xlIdk8r z-Je&}|9|29GQsoLzCTa*_d7ptzg4%%tR*K8=54aC%MqXdwEMG_wy4Cumwk8ICYh&y zsQ>p+@UGMj)o9S_BLrlQOs(*^70`1r{ z4BGzd+;0kvUb>=4sq`f$zsK2CZ5+9pzU5LSHgR0prK!bBrZN1xchcOhr$uQS+r5WB z&+0BMF#jX=qiO!8X!BdWm4fbvV|A?-U2bX$68NVV{+8E!iDj1*J3~`jS>P4sc~Up> z4>c%k7TBtSb9vBmS}J5O3Jh@2g5zzEnP+DgM~GWG|n&=i%_ChW931>scmh zYyOg}PQ1<`J~2b(%+hz=ofCGhSSBxYn6H{eJa3xFV{zBgYCGBGu6Oqqde_Ka=-*fz zwC4A+%XedXGEBsM+BG)MpQ&W|c-a9%rnUDuewWU=W4-?Q!ji>BmkV8bR@R2pOuA+G z`uNfx@0OS{SN-j{rT5MZOG1pz6;jMUwj|F|9pSc{%mLdR40=u2hJ|ApY?8G z|DW57qt^&KZd&qvVRKrWz{fUs*`7H^xmb&}ihi!m*d+1uO`^m#mJ6%I|5V&J{c)c! ze8HD)F3H?v>F`R6#my@BnkMx4AJX^SalN$WK*8f2>xq4*y#A-K_2%R({%&<4OI++` z!o%eBEMB=A>pne5x)L3&U6?U@`?jc!OBx^9XA3o(XH`0e%X&mzjeKvTFO$Xc^utdk z=XK`Qi3ifukIbvvzA4E1PUQ#VsTPe+Q3rbWd`~xtc*J#){m{pRfS^B@!#4yj`EYMR z>lXFy*Kd{?b{wT;Apw3}q#gmI% z(u@_YSF8`t&YJoA!-rdZo{R=n2RE&~#IY~XeZ|aXqg%7LtKYY+|Mf&iXI1f*oy}G? zYeEw(L*DH^lJU&-^@GZ6ohzT#I9}e8W5&FUM{Y&LO|}228=YS_ZBf*e{Ln47Vr9S$ zJ{~qR@4Opr5z#Ft)IRQKZ$Dh{&}ye?)%Qt9v~BoG)?EsH#FA*NIzyMw2nXd-+7`e;c1`)IPB|eXFRYkwZ;FdB)j)uN3oS6f2(JvT&#p>aTE! zXkkue4cq-@?eT|p#++3@p6F#lbpFpx`MWn;y?EGVDtTtEboVkBpBdjIG8M~f zg(FsET)q;K^v1)%ZI|WUb(ekBQWoFIKDkS0!Uv9bL5J5(p51bJvbehc`MCY9Kenx( z_y6aUw=X+?B%Z%nUYBS5OZ5KS6EXH~%O@?0H#FdS$I;^!u=YpQnqpU%L{8Q@&`>TGrnTNm9RQp(M=_Mm|;O5%7>d9f#wKc3F zESF8+HnrAUOG6>{0JlP!YB2Am;OL$eRY6x$Ub&YD>hD?QE*5iji{96=Uq^0jsruda zF(oA|aa*&F<+OXH0zSt+{#sCGBYuu2eNDX4g}|eGSPv*YGCkL2!?us>$xVTph^BS- ztasjdP$KE%vg+`ayGL&4Zn#+??df7{WFK&q@m@nvqU~-a38hdceFZ7r&I}Dpjl}vz z&$*V}7E#>wYFp?O^J^bfyu9mnAKklkZfM(+qO6R~-A~?}{QlVYx6?rt2}ve13AW6o zo3A@_DE4!)eF!_aSyY}YSE@JFwwO;Uh+~9T!*UIb^(Xg4busimK z{-UQYdGVt6cSYRcadG7jJziR$lN!O3@NnlH*C|UmPcPbXWu2$A!QL4C%|W-!@0?Xi&0-YCucO_pW9N0>SH zmJ_at^2bk==k2jF?yxhed#q9S*I`%Y{#@4D+3Jb6XO;Eso-*0&{OrSL{>10qdn11C z_SxA2JlkhjroXFtyy;F>l>6N;UzT;=aO?T^GJR`36Yp8k!{P5gzT291bN%sc5$_xq z@`c5uX-|l#?Xyx4|M@JvC6Mjbg3#nAyJp?_Uvs=_dAq{&YdQj(#Bv=j-1q3VJnFd9 z_E1S=;Uc;G%_mb=1?_r1=k-frITa<_n_6Pg6~8kgt$nAL_~;u1wK4b0mOj6upK^ZB zn)R%owT~M8yHa{OCF4Br9QS3S+}@dg!(Y#;QCNPrJ2N+1e2@1g{X*wmX{WPGw2v%W zUU>RYTI64*jY5VOxjyjC*Xim|5OQPKU2oKClOiO%MDx-6-Cd85MQ=Rcc&zr*tKD~> zTzzdUlDMyKwdT9Xchl-4uZl_RZ9Bx;-a&VbpuIsB>roHL$hMeDg zA6JUV>Q9$GXFFqa z=^L9==bL>j(pls_{dISZPhOQneW%aSh*JyRa(VQ7yg4B=yFBpIbEQ}-k6w>LAtgVb z$QZi`k5rOE@;VcaePhuDWLuTk%{zoU9cw9=CNrYQY-FVSN%2`nC9&7&YRZ=GmS1G1^$f}V({bypN z!A+eVXB}ntLH}PvXlfKk2wc0%I$k~3LTZ!9dY}nmbIw`rP zY44>Qe7x7MT3$7mah)i=QE}g9yAN>-b`>6VZ@VZS>U70KYRmM^NnBh8MF;mUpWP{a zRn~jqRge2uTw*8b*JYP{i@VzIV|-ejM{a(?hetiBk7YJYH!0u`Td-PWwQR6{gz;<# z@5$0?(k}1$yWY*%wsGH-SGSkdUfBHqZB+Qy+{@oOuI8A8-Pj(y);z{5-E>|>7DH~D zgLbO-_L8O-Y_BCsm2DO7^i9#2E#sB;JxNW+dMZF?N-eHb4tiP@pMug_bwX*I>lwnNy@A2l{{#zHGua+^~ zvupXY$hRfiiW{5Hee+52FF&dKM=X~0dbD_?t+Tt%i`C&WzE8~4SQe~2*tYnD?ybun zUuW)MF0^=2$;TpOo`t^8~$c@rzBLs|u_g zC8kbmTxVsYA(3X?BLBtiPsePx5}ge{?L5*R^NM!$A6{_i$I*+CiYvr&GFF}6rG9AI z{j9!i^A|Fx9&g|BmnSzm@iSO)uR3q-Ad3ta_{b_R*8O4q59z++DV#ZeC*hAqnpV&kkSat%xl+Eb-yT zja=zJPs+qhTHp8z&$pX2```}Ol^5nN(*G*5@pd5l(#bp6CYnF?bbt19N>7#1n*V!W zzUsTPV_QPw6b5!?Wd_ks#?Pfs!i=(C95R+#6%w#Uq24p6#dd9x!RO4?U%Ipxy7N9( z7nrEsclbl-$->}2hxg>{;8)x`@#wQVEl0RM%NMF_IV%4v?A%AE=WS*aOW6}562iIO zz2j}XD0fNM+9PUnvhDW2{9lf*d3pV>Qt6uaDqsKG3DmkL#a9I0>Fl#M+VHC2$Fcap z{-ca}D^g{ojFyJxRvL&3vF&%1RnRX^j14R-2=fh23F<$(N$N~vVSV(wUnWht%izJ&D>tA%r zmpAPU3}xNpdq*{qkEd5?NzdImho4>&kbB(n!fN`_qpAYk#i8d__Xj1Iwh5#^o9fco z`u5Rog=*Ca?ppgE>S;XGQC9UwV^y%2L$Vflr`aLy%y4n}U`QbZmzLdywyz{-A z`3EDve0hMlL(KM-duwJkhH6h;= z*SyDZ&D?XRSrx>dpXpk6XTpL2wb|P$-?q-qXnLU(x`=>&0dfL92`n2WGn=@}-jd;Z;zG*H~7wU&TyE*x}eo|^d zr^tg{e*(g;FKzns@oN3Ps=t?4&wKS-%s2Gt%~h+^@9(RtZd-e=O7im6u2;)HnEYVr znKI$q2Ui{|y~neo1Yeqq=qObFeOn*w&77YXFkw#n?}-e{t|skuNmVO3veDe4@r8)Q zbS~LS^-Em4l9=9Ii?zRff12DaFQ=okRyT<(;_>uq>{PV*dZQxPJ^dB)bRwnrEU%COUaC?(TEwoV5I^sYFLS=Y$Ih4Y7|CwdBfL zZBIYUb!j_1?|W}whAy-A491`Cuk;TrF4@a-BqYbe=jyx)ZE5vs^-Eve;~6JZoo7{Je|c=s_^B%Gu9WbQP3lO8YRPZ2wPEJ#?$7Ml z{H#w`>==K*|2Cr|j`O{DG%L*Bv#599w73P+w>yUGFlDb&c8CjJH-Yo3<%y?r3xyV| z-@B$zb$XKR-)ZiGF%2@G9|a_~iAF7BJ16(5?d&H3mYl=ZA7Zwju@gJ}b<&Ugdx9bb zlcvg*iuPXnciBf|>!!noE9L6{{d|6N*IKbqv+hqZEc1Hm;urdBoaRZdzUKYi`$$}m z=FRj!hs4UAW@K)unBHNyc?Z*Dy^5N%;S&63r%g?|5fR!H_vhm~W4B$U$EK&ZE*dB3LU$E&=o5twPR$LqnND)TFb z6*0>7uMH<{kVwvtt`xJ;J$ZiaH4E8Gy}UZM+Z*39@a**w_EO2U_u61{W>eaH#w*WE z#lkILgleQ5I~rokvA5}=*+JtEtp-Ox2bLK8irez?>aNcdHT|}H-*{u&vTq*6LD4A(%ERg*QcMZxp*LZtvyADcf!{?B~9F?a7rm{i73kV~=Eczb|#vug*S_eLjr+-PG7^Pv`JkUEy0K=Tkea^1{x5 z7ZvZjFSkTyZ%!09Kirooo3lZ;{O828zS&wIb}T;Xc*QpL%-+52i<&wrr6ZQ#KK|~7 zoq*u~i;enO?cxiVBYeYTw=jEq2dp+fHBptZ*i}b3b7fd@ioh|${g-3kT$*&pKi^ck z>-FM&xsL>PNtgAdKQO(*tG+LE{toBV>EGMpuDvXaJ}YQgV#QKgd0gVaw1)zRmvais ze*Bkapc2dft-3tQXWiw}bHAPj&pva&+HW!E3E_{GQnu;rD_{GXG3ox2eD#a|An7IGZj zB2)Isz;8YKe2?FE?uq>gx2Ssg;qRu#XVS7YJ0q=A3s%2XS!l9-%Fm3CuFF3>cm1f? z?>+s*OdXLtja_0l?ay9#D9b9`(3Pn3+HHx!$$b_tw?1Q6y4JkhiRYZCIT7l_X( z&8*xc-Tg;RDa}-*O@rgdrL8k8U%Y6ZHFe4oKQZI&OBEXLTmQNmQgd*wkaG^rY;W>~;G?JnwUCl95$$Ocyn`IeRiL>im_3tZJ8= z(yy{@i;sS%vMtr#X3>%_1&sfF18dF*KC0vIfBdU)&OG@*-J5silncMkk$MpE6Wljr;zaP*(p{Mfmx38zo(?#6g?w*|P|KTIw0?y#9;tR1Q zE+<2Icj&LW!JpNm zQ+_#Wb-$QYF@5(k{Rye2i=Ve|lM;DavT@#1nc0HBH+6sau4I1Cd$e`dGq-roCw*6Y zSmUoQRDW|KqMLPx)@{LAZXa@f`tzN>v~1RPCb@;?u0D;|ZpIiDY;?WHvrEa~gxbc# zlU~H#5NPK6x#0f1FJ*@n4{^R~P1UVDe|^T~%ziIJ;Z}}@GfR`Bs}hc#U*48-aY6Eh z`}N5m?#n!8UOZ=loyUW)6^G+Zl7r8@Uw`CgiK4J?ZOr{eVdmjYdqMd5Ms)6_uLMNkd3o7jaD>y*^7R(ZIqXaWw6^U zW3jk1mhl~1&gODY*U1Nk7RPIMIZs}{=H>(yMX$TQo4y{MRC3=ya?19vKNVt3&E{R% z>+M{&KQX3~@0gRLg|HdBkif$W6%&&~H~kUSQn_k2wd?)z$j$_rxZ>~&8o!f-efNF2 zI(hn&`{gP3tEOomSXX*zS_YHv)(?Cx&pE4CXD*JMDpvCF(uH!JSvof}uiVirb4}z( z`}CHvYV(0b?1$XnU5IbePTjkzs-)|pLihE952mh?=({j!QB0a@piA1FAH60rE`crI z0_vG>Kg=q#%iXr`aNX;}3eid{?)e1OJeXE(W}K0*^T^B{Zzsr(QC^B?a^c+OqGP{;p7(P>6n&k-)W6|-y>u{OlHZ@Da3Dx}X6*M4|Lb8u*&_LgVmZ@L|73NxmbC9gkzE@NK9oSkd)w;WsB zJVofJd~v`5sjC+ZxD*eq|1|6G!Qb=T7Wi~IJaSfgmi1)kYgg|_@0q@AJ$$;kg<;i{ zI>jiC*L5`A^qI9d+C7a{gR$gFf; z`UBC9nCZ!dRg)hz)>J3IlYcW;a_V9uFZE+5iY#3Oc$|EFmxKH~9&5Y4<+210# zT5dAa;}?5XZ{E9^DzCUrqB{M|L#2r_Gt%~LmO8ZSNpkxg$-);49x=V+&6>l0^O?yB zsns5u`l5fUZmg(h`}?xfxe*}8?@@BXk z+AVRe>Ei5b&lNrW6au!MG@P}EdD;9ozVoXWuG-OOEL+A@#yLBEWp327NZqSju6n)N z@F+g{gFPSTqVszXU6)-fJRzj9<3qHX`|9WMkAJ%N)~W*x?MaYxHKk;K`O#p?a_j(oBNck7qXa_Eq{G8Vd0Kxp4MINpPs(*Vaa;= zW-+s!>qi?-)iw6}F3ntKH*bZUs8shtqb{YSODP|t`t}{K;OL*f@t^fB6WL;?-QDX} zdnb4>^h?QW+h%iQmz})jG9(EIUa#df=P{{lH z`)%LxzO^rTA0=#Y>-Q>Www3?5VIi}Jo9V%s3#(NZ-aKf_bNP5nQlQAT^k~jbk*gl+ zj-H{PKN?J4@TSUgxzhxL31t~V?0@@r|C$-bH04HD{NlBHI<1a%CvAJ{H(~LYcdC3f zV)6T{_d2@vK3?Mfl6T(9c?*x-b=zPZ5N7QsawE2(C&OR*=hJ1zcfOkJyD5C7%_#b% z{6DeUp4FOpp=sTAuO1uU2&yjFQy9+Ue{+#h_En`aoo~yt=klHTS@Z4B^XclxZ}q?Z z<#cgZr`^^i(>Lx=l(Rg3UDL!QyW^gh&c?IVWm*rd=HHQKsnUBO#{R-hHpwFI=#Imh zwfQ?1`+nPF{ikh9sp>x0CwwQ^W}W7}n=x6|wRP>L4~6qX=M>&x{(f`TL-s&dA^&1W zo=oYSE~Q#Tsf#4|9AVmO%rpj{#dY8DI>o1<3jt#UEgE&cD!&+KNe5!f$OB17 znQM2a+zz{4psfG=i_sH5XOP_E3)gdgWPB)r$LTU)^#P)T+9wylBqJi~gJs z8@l$o(qs!_u~gO}fv{_aJm zS5)p}@Dnm=D=}sDR4WgZZ~e2|N4zqu`@7qP-WA24{Yau{zrUoiHU+lgW0QhtL95(*@$P=zx`+h{u1 zn+KB?L>cyX{hwua@*ZQsW&4H(!8zL=W}RT|cynO}W&QsF8#lS2-+w=Wt7 z&H3V=_-fsivbz>+*EWfJtmto^u4~3HSKmM{WHK+$9~q^*N#Zu{XH?^AxeM8iop+y* zt7M8*4qE5Ds^Jjxt0`}_JdbdCER6od+?o3E*Y4|!UllEk_>mm4CG*xJrd7(z!{2|@ zc*%S~Zk{SzTK|i~ZKOUXC!1t4M`o7Dl zWyU9)Bi-er-M%`ac*P8f`IIt56HOb_4KG-%(ZA+BWm~h}O|h+$UE1Z2 z{QJRPu4Z;_;oI~z<;NqPzo++^aQ%D{!M$eh`%kmy>;L4I{T^fxUHjlj;XXU_zWFM< zf*<=e&q;8&VOv&q=im(X2h+5l%UztoQa0o9ncu2w+m0(P=Rc9!k~Ay!Y!=`4mC8Yf zfBfh^wmijg;`P;M_up7^irvuITXtJ%^t?{Z=lN~Td1t3xUi4qB5#x2~(z^`nTb`yGYAP)0vifw? zzT`*O_sub}H@b8-JWDygNXmz|%`V|rYV5V2O3vp!Ze8Ju4PEfMCo8tPM9P?9*TK-a z@uF9EZPeLnvt3}~K3B2el9!5;L}q^JVVeFyB#p~hu|{~+i8-6Zb7g-mS##v2=i#ge zYucQ%W=4HIe(kPui_1Kw1I-p|7f9%<`fgfpuJJ8se^%}1bv{fgD=it1=li!Gmb>)C zU`N25_bKNVPy0J>Zo(e!zj{Utx^9n;x!)1KGL4@hC;6R-@Ty;iKg=$y>bvOFIJx$( zNV3iSHzhOmS}glIi%M=qblP@sCHPN!dizAt^R2x{E*g4<&Uuq`cTHZtmHn%jjQsDx z0b6x@j&0w$-b#AwTN8%>$kJ40gLH72I+l%ji-#yJG=Y8VV!*kYLR<63!yzF)2 zyg%!2-&JOv6l#&OHd2T$I>bb2sm|Nph@E39{c2hIRS`=w zrM-(D+QeEvlq-%iYX9eMcjJqRK!98A-IsCmWKSz`l+FAq9h2h}mHu$X+_!4(Y|^%p zIXqJ?zI0Z!x_-sui=++LOADWl+k)k`S8JQzx7@xltA3X1&SVe2FOk>378J~|k;q@u z&QteW`__H;=r6s&a`98%uDx2{y7AZB+^f}90!DM=-v2f`rF&-I-J6e_bnJQ$2dbsD z3-r+1?{X9{1s!t#to>4@gH96q7-;r{z-5BhjU zH>>~H8NaQd>zx)?{lzED`d% z@9^H_@$4;^JLjZz0bBZt&uFb(w~2AeT%$dU*=o}>W-FhZpkGwE!E?Dt_Yt|R0(~35 z%RY}io++#=>TvSjrfgAV4UrZL0WtO?Pt#qSXT`oQ3bRz3D;bos;>0t{E6-b9=9)ww zeamv{MR0**SJjhW{onMD1;u9f#t3%bD80~@uD>Rsym^}32dQGWey!D^>t^Je2)b`_ zzMgZv$*6Y!`W0&LmOIM&d47K(xLW_Iy-{6B zr4Qtee7jdA?O*n7U%%C#f1;n4g)X0~z%~Dwz3#K$IVy8>FDOZN2yK~{@jk*gLhi6s z^s;LwH>O?s+xTCs{DSV?dmXECeATj$E`rQh;y0ft~r`)fa?pnO0cEUH`=@smm7P{Un)j>7vsz1|b)9_TM~p zyd&G!=oSCoCx4C0K5?yGf9+S<;qD1@BbIzFiss*HG4a>a%e!_RZe>+8eguA&szMz zb@r*vnsQNJ8AJ_Y-+WcRn|a;y-PQE$_C_uh0f!fBoaa7w>e#5;d$svjq5R=l^6Jr+ z>6eTwVhs#ZubaJ@{rYmbX}sF@TUH3_wW#(&JWIwJrXY$Uy!(;ZP zv|fcK15KHXcD;FbdYbjtCtZ-`zSyI?o@L^u?FA>_tkP|tH&gfTtph8cxqY80t7klU z!oKO!_Q#w&*ZlPVbKP=#^#5+1oHH{LLf7^L?%268+4$uz`MYo0N}B(t*Roi~_21O2 zl~{7zeDix|?GR&*t!&$h&-wU%Po8o%Z`SWMy4$o1z1z>4oxhmgx+%1Kqru(1Q}0}g z{!+Gi&)WAd&J}Ex4!LUf>HGG&vJTFyy#MQyPd%<{HkbGPbn;HMPQJPDrwAz{{@KU& z+-1&)XI153?pUaG+q;f=-7fPLWtn#qbM``Ju6!u>R-$*wQ?5NGIK zrF9LP6~8TW_F7o`SJc5$CET^nw<$U4yuH{esV`fT)*KOkpcKk0D03#jVcx1^Rx?ys za_3HuWIQC{AmMBDC$;11-%WZ^-y}J#_H5o07CU2NiA1Kv8)vTC1um}H=ZtFd;{pzS zc=9&#SNc?Y6?gmk@U5@zIa%JA_A$|v#ZLzWEnHjtnpPNJeCF~%Gx)3IFKxZ) zO#1($yfh9su1Z>bfT6F<+UTjjrUXByO~gxu&3`)G=C+pj%~S5`_rDX(^m4X!W`9gi zmhQ{6+m+38udLd)=-QpW47*7eboH-K%l!8twtF{I?W)b!+D`t}UR9npdH=#$88T@< zzArTXw153Ui}@zmm($j&g)a;cX1SqvbL)=954pFW+qP>*#FKy4TaKmQvYi>~{PJ4E zs*idn4W-t_NUXi`>X7ARPsOi`jDKER+naPGYkfr7?oysj#VVV7FKBAsX3A~YS3T$0 zw>yuHMb6fHYhk+C%Wu!i#AV^_953enPu;TN!Lomwx-%jtr7x0w*7j+7UggB4W#T{b zUhFQ|Tzr1fUB=iqm&DfPxOkf7bu3&QIM4JIQ}AuA)Wv@`OgYtat@Q+p(N@n+UPmz% zYvlv>ovrngo~%E--7?1OSb5ZYy?@eTO*2;HWqy&{o;mwp@97%$-KD#g4xXE4n@Z%sy+Ocl} zFXm7FVe(A=^UGONE^~eApV{o`c7yr5PGIVy97gx{w+7p{G2B}?d-mNsU!|JTl6p24 z&(sggwA;I8(!-#I|7~pV_}-g0M|Sn(qN(Y9=YJ&T-&fivyoc|n!0j(e&(0O?xGGb+ zYH^uQuuR=-yLkyGci#$(O*vIFS7jELL;QoIg=-CZK5p^ax8>QRzaqA0JA*TPSGHqR5` zYCUj!tw#2Z#WEIl{SM2$c$&1!64@%Gx+X~*A3Y$Fab|VL-^*G%m$^s0E!ys7QqTPF zm&{~|3WM9y5p5?Q1j<{kO8(+~jMFxu}&*=!#@HOu2-~6GEVawC6>!!p%{kk-& z{(Q`gE8c1MC4#LKww`v_Dw!*N^ZXjqgBj~Z6SwPb7mqf49ag#e?ToW7J6!9}Udy?l zxZ@-Hzs%pk)hlk*)YV*HzFzD4+z$p{D&7d5d~`_k&hN_(H!m_cZ1{dI`pez&x37Ab zlR0)g*SvD{refxVEZcMEPD>;n*Io5G@i>Dl*Z$%OOkdYaYkWz#?6A3WRsM~wr7I1O z7)CsvQ$Bx!{J#r<_D`<9e(%@h8DPy3zIVxrLkZ`5Zn0Vw*!;@Zdo^dBNQkt;S>_3c zMOGa67}uYb9&plsMQMA@|H+rwUrh*k!aOq|=AfKN>DLcl_6gg6@y=h<`t)&>`&7Hi z-`~F8p0ZU@;;{C%$_4VuoV}-wXU$ZOUw%A6u5;IpG@doecQ0u=|8G7g60B*R@gR3e z*S1{&=0-AtizLe*ZMbJGTcXxFSN@XhyalhrcOKh%J88z+{CXSf>c3q6GnB4far?Ps zwy~6oUFT}g#8SWht%A>QqD3gSSj~W^L=&F|IitI_q=-px1Y}Hk3D~P+WIx~tWR+ySj(L0?kjw-O2H}7 z+Pe0#46C&5qwV*;ZSp+)?3>=Fup=GoHeda?oUe1jatZnVGj55?&rJXMg?YxOkgba( z`&~6JY+7(F^{Rs4@n(^*hlNYDyo+r8UPgs*++@pL6tZxEcT#+QrN@!atv7!2|C@aF zpM;dYs^mL?yQMlweCO9(>bKZ0P}J*qlS5x~&1M_+rEURVjbj|HE8bF=`^5RneG!qL zdFsV`qIx~&uv+A4?_gtLc03nq7` zjWc%#scqf5I%!sO@CvovXBES$pR4Yhrm$1b@ntt#$m=cDN@1^9<8g?md533e6CBU}TkMYaD#{SZxIV zmi5|?57z|7O8gIg@F~kpuR?b+$A|OH_by*lx3X?`7v{;#-+C&m=mT?cV>jCr-)kaT znzQ|iibn?Coo z%+4zpuh(}pmb-nHt<8;ym}k**T6=n+^h(_iqA$)(Xby2-xz0W+FlSd4=iIgN7n!Tl zSF0CmiS}~bb7$mLny{l~*5Xc{L&nbL-g5JczBd(ch+UsMQTDm|lErHj?7!7UIXQTp z-T64IY4_P1H$GGsT={Y$V?kt{$eiFso(F{P9G9?Ci@D~rr2Vhp^{tQDwq!1{PqQm~ z^zqQ42H%KtoMxWR@B42~Nw~4BaKFN`>=O@@EV)&>i?lz5?VfyhOUmQMx2wO1ZJHV1 z%=&vz_Lt7RXAXy5S@`_zd&c7@{%u?F>H1@@+c!C+*z51K$TQ0v2~10}vp1_y>CD~` zV16e!W079|#+{-ULt~GB``*3k7sI#36M6d#lNz`$)U|X~oLKPI??A$bFr_^UtGFNS zeeLxq!R+`ler2oZ$#F;e5~hQKy6`o%|zh{$Ja077G^D9HmyGK zT)?cp>-SAF>c4GU-TFPs-S=%mwyAXqlY&-#nlw*U?F@@w^A)Y$1~c8Wu-V)2tKyg} zTb?=JBds@XN1tY0k!&q5dhkxjn*(j+OgiP9F^;5HTheOgzeUFTUUDuup zZ@wIUZLOSPtmy5vPZ#@b5mB7qE7Q6w(|_ed#$R8Kw8lShV!m&9-R#ze$M??}PRU(z zEl+W0Z`H#N?hQYq?2Q+7cwEuhQdBlY=;C{}-ObZ}c=W_K@P)6`)|tA=M%{I3L3M0x zRgTNH?)t+w*De&OY}c5<+#Srf&3yaerCB>AZ$8*H zY3s{HGwKvJwIA7SQo6k&N8+yAX+yo*FI!fcJb#px@OD#ln(xPsV;|Q~x^Ta5>B9+n zdk;=j^3Ygi_Es`wwpVPtVr{V4^K+hG&!~T`yQ*_kNB50)TMc{S8S&RM|B7ANv%|$O zzw?{w_K%h+zoQR`eLlH*Mefe-xC{F;Hq5k}zSr|eg~^ZGLZmsjAm$nD9-#b;#K4ZFsAc=M27zzZO3=mwj3M^xTto z(^~hG_4s|t%5R-&yzXiF%3Y05OP*<6KhNE`LguhbQOF7*md~aZpB36PHt%7ZY}mZL-w>glb4$p_uLZMomtU% z|MqQZwSVjSPrFDuhHh<5)Zt$Gma}yS`;-H_vbq1iZhYq$^5jA9_TzEa=XW^n-?+Lg zQfGE;q~cu@*Zr^G6mGk{aaA&__df3J%l0-cGne$~wU${eQJxchU#+q0W83Riix=OQ zu&?%7rm(H4$(r-{$*|?`%qzV4r8j6?;JwBi`^sPX>Ws=a_ao)Jd)nVu>X`jqFZ*(? zzmV;nOO+pVeTBXT?pUk;K=1yHecnE`=jSI*$o09+db4-tn>Sv9I~t~))!n-EwP)eQ zWvg#J;k@W@%vSMRMYZ(3#-;zlw01mp73}`yDdBS0>ByaZxvzibF8;hdPdrU3wend~ zox(EttCQB9PAX#d-;~vQ@oUewLjQ9*E8fYvp3t5qZ+p&ss`QH$hQd2Sgnh66%uhDa z?&4~Fu}~!AaQT1BO*ZpqUcDTzmvctA{q>g zu55qhd*E_J*Ch5p@oBO5Ud4(eH!W#0-@i zzg3ULi+IVsNJaOjA}x#aGfw_$VE?M9WVurr2cq0$N` znLMY=zGv{^2FE_Lm5*KO)LqLulfrJj%?mLyd2sxx-HUyk+qP_-{+zqT&3(cGC9Nw{ z3)ksgO#JtH$MLoCySIgJ`ss4JL9hI0^lYv#;U7*;V_r9PZGHD*>6mkqTo0A2A8q_2 z_ImSK-)yIw?s+lR#zL~4kM-QSX06$9W7+9x=}-Ek*Ghgr^j1dlc)!6Ev&XMiDI0xx z_o{^9)w)xEUUr1D9<%?sCAEF+?Nd%`XH1cB=AGg4PxEZuu5h=)XUBpQe?NCz)fTpN zrO3QztVzpfL>k?EkpI3vfOX&ewB)~*8>L<>Tlq_KmF|m`c3E0p-d}@)ru_~#W#`*A zaW=1q%9)<{!dWjo`e&*9e6*VF-+G713xCP`?D=IJtACyQd7Rdcab#ztj(9koU5N<|bZYu+4L)_3Q3vz-2|K5ve1p6cQI`%)5(8}f9NB2+G< zdB*Q|T`N}PV=Hv_z!Ia4^N$}~s%W?9<*QR^*Un_EI$WIY`1#oSmGSC7jb@w49A`L_ zxWK#p`<4qbuIutY$6ssR)iFt!A?#*Z0{7iTi;ZWqo!{s%^S1WmpL^p_Y^%uehFG8#Q1$OeE4p4uC#ohO=@_f z!$oInvz3P14z2lBw)DwY0c*9eNk5by1Sa1Te7rzRh|%iqnf0Rouc`D;et11Ha;mwv zp~nBkzu)9A{S)Cm-u7`uh)d3Ar-wCJ?jpZ-m-nwx5_yqgDsIhqdG|@Vije17{;6NT7>UZKbj8+u&--%y z|G&ED`SJUz&F@KWstSt`6BqclXu&h)Z;48QZV6m#A`N5TPBMN|$=u+mKSR*Z*flG? zv@9@vwYPNj@zMutxfKN1GFE?Fk@xDDad(G<(u7?Z&0>d+XFZNDpUW2?`oQdokBhEg zsE5PfDDPeE>sNMaYP~wI7%yaLN?!_-;6C)D^yhiT(6|r?;H5<3B(KDNS_x1LpHn+152<>ZMK6_f0ig#An zxs(060>_x6u3im2ST)<_-P+1k`py#LqS&R@U1{=f zyn&6=bA%O$%BiF+fS~3^C)SrkKgLb)f@+89AS43zIxQmP&0S6e7)Ak z<8hIH1t0vI%>UGI&-}G)A{)7qSQs78Y~P^4R`dUrdlL7_s|VLG_-^Ce=d$KvdBchn zXWgh{y^OQhEPCR~s28~8p^DXnwi}22Ud(5(USHf%;d;1w&Yh6gDYF#6F4@gsR{J2i z{|~G9XXzC#OK0{uR;+i^D_ile`btKG3izVI(9bq!MMatS#yWZxcXoYZ4zsCctDT_f zH;-{;=j*Q#dn_{hqFW9O|1IdU`T6Z<_w)4n#((zJb>Ch+`C?M}?N{z6mCDag-roGY+TwuVQ+HGS1WodY?Ey@ka=A)szQXQ6DRUx9&987e1$M zu|Toa*|z;fezR%oRld4kzs|w(s6& zDR-eW_{;Ozi(=EB@V$Ay=8Tv*ubKPgjc3vx#k^9M+oSGXT9kNv|0#_>Qf>PFL*Xf*D+@Po)f3KO*M|MDmkPVAgC}Sc5AWUe06*I zx3Y3}9-?78(?i}&>M}d;Z~u3TcD0am$48}|rjjA5Radl+&Tv}%!K6#iP9!Tpdee!M z%jY!3nLkNoebu4h9FbVCYw<>ApI18Jmsj417YSFjzTB!5pmyjL+e_yi#V@Nf()|UP zm%pwu?3-ZJ&v<#tioJYG>^zTrd-^5n>Vnw%YwM!ASIm60Md0QV!}_Rj35(o{o7+}D z-d(S1UZ}wa$gtnoOw>fq}|M4Vn63`uzQtO-n~-3@ki{|kTCW8 zyp{!vcGaXk5OEJ@lm7CuTi(z0%+0hHlY~FCM`$gKcj_qpA)##%GUfEahyNUljI<}s z7is!?d|73xC104X-Mn*i7T)evF8a~?j8mTF=uesTy_dyW*^g-Vzmd7e8=toN^X1u3 z<9=_fHD{S$|GsUxNrUkmX^S5=^Zy?H<`nzyfW0Fx+v{whI=}e!PhPlvKP%?DG)S41 zXYZL=-t+RhM0YLbbKa(KzVoKn?A@GVBT8hyuNFmQCk0N?`>MHoEJ5>@`cwkACB*mzYd5Myy96g@sh@`>J(1} zD+X7urm3Fp0zVhr4mnl(>(D#aIKh1XI2+6Af6pg}_)ecCWjgcp8b|BsJGv=PcX))q zekPRD@MaeK{F8@I>ar=dW+d7_pL*BAWiV~Neb z+jGm`A3J{he#HKN$uDM1@4m`&^<+@o8ke3Z{u`U-?9x@b%kg00H-+z#-!f+Et1FzG z7kXXQF8oHX#)9)2aYqVvHEg#vez9;%swpdHn2XInm#o;2Yu@Ni5)YI1UNO1|gg;*57$OzoLe>$SwELmZD8>6I`?9c0_9I;l8xX=I#NO2VLvJcAEHoidfHO+C5*= z`~TW+ydpo(=ych)Y8OGn@n3F5_hdlWWIur3|R^1hyPc^JjUMCOU`@8W_;n`7lo9_EYM3_qZpLXIi}NM8n=J^Xt4@XpE65b zuX@$G^=mYAuhr*&NPiJpq@8trLr>ZD-<_r(?X+5M%k2lX=8^lF z?{pNFuHCRD-9S52ad;r7yHA$+^G%){oOghF@Ga zFP`6WX7#GAmaNCCCO`h5yjgl`jL$@+xb-}}J)u9}be`{$xwVF4$$r&zFXR684F;hn z_wKEI9Jo?T_2i(F!_7OJ)3b8EJ8Z2lcw+2)w?$%4=BhN$ zm8|!5FWCKX(9qf%{bHlx&u6ic_dW*rm`z(NZ+y>(Nz3JC!V%f3z~k=ummE7Y1um>+ z-=`J+-;j8^QcC=sozmUsLiQyRUvEm~8ZLbN@x~ml*;npu z+M=1WOk=|HvP<;o;`cCUaewbQlGUxsw+(6O1a7AV+QsUdtRT;nt1%y&c#BTKQAl2 zr10@o%u=(rJ7-^)IKXx5fXK#U(_EY9eMt}N*3xC#xyb%NV&fMV=k;M5Uq)!=EjC@f zxX!KNRZdvVoeg#lrrLAzR;`L<(MWJV z%hvCn^}_3aa(GpEV@}Xj-E-`9J0p3;g6ij{92GBOtEr5fb6Mo+&iTciky_6$ot`6V=bp6i|ITka@>vA@<-H z5y_4P%kyGWOJxsj6Loo)*H!;QaP<^BgYADMHt-19&Gm6JdbNJG&JX1S-VJ?LAB3u^ zLMl%e|N3IIS~Gm*zGaSaQD@9kw9WRtWeU8peDQv*<*WDSZdIvSWcP+g!ABta;l;-I z=a&`c$L-^3*?e5Bi$6wRQ`r8l&o28b@%ol$CHj4%~vsh8DWpIH`rZDwqqMAgms zIopHc>)zj(wdd{We>ZMhEmAnZwsbb@r^o{mTbMS9|DeUoi zVN=g8lbn^k+Q!X%#trsk^-}9h7~;jbHyDP#Uh_fcDyL`O^y|7aUImN(c>CnumKuY+ zEC2t+E@^0kjeS79h(Gs}yUH&v<~fN@itvtpTfX+6_0sl;%#y{7U1C0gjT-!rwmY zW4d5Amvu+4ZPa=*ADPq3A06HQ?(}Qz8`HlZ-?wL9lSB-|P7eN^p7YKeId%5za`~32 zVL$lmc1dr2aQ5w{M{Obp)+?Nj%K1?##}raL_iY#RvaY;Uo)b<9?5wX4XmXj~!qBy; z;O5nrizcYK0LC!#ie-`p6B;%9eO#owE_`qQkXQD0uB9SWBEX_6gQ$#?zw8yV*w zF-4i{n_^ryeQ5Rnw6}cki^&VyzN$@5=zS@-_GXc(_5AOL40CUBa{9$AFKu;LGV>a5 zin-t1m^8aDhdAn9q;q_jSXLhX&P&|R{?q2`0(t3MqeOzIBnstTe8KeEEQ}$pfAcQW zgnw5SMc*;XPPIPpp08u3@5Fr8mjX{G$Zt7k67uxZ@+jq=ynPCv-@oQwef-t*>GwbA zOz)kqD74ztCcu@oDY$KdI4EUdKq~#eOtda%F1q+~h9q&ASwTM`tCM zuB&5VDEoKlaQcMzw#PVEd>3n9@XOPq;Z>wGgXvHGNp~waq&HjcYhSlG^SYuyRze2H z_pMTjSIjP&ZrNIHBqdn#Gh)qaO~(7jD;Hk5ZgN6+WlZ@tv3D*GN1}Q2?uxCCx0av3 z!D_-Yo%!cBMg;mje;#*ENqgE1&-;$+#JbLNEaFovO5t0yvq1epxAMZ>HLE<%ah%wt zWAMe)GW*ho*Oyx7o_@-?w^hE*Y`!>e;7`#7%`cL)818kOuY9|dagkfZRN+=rkLCmC z-n$>*$agwBdC{4eAJv8xCj4Km3hE>pS=`$+S6V2D9$w&X7;wq+la}oVg}FIj51%*l z(fIr6Q)I9cgH0?a%ZjUOZ_hfn?oX_7yP;>E@D_*V@z1x{W%^D&`2E!BnAe^BX4gZn z-BrEdd?Ytg|LXrkdrGz)v)*)8nsN5pa6t>-xhw9=l^zo4QQalAX@iS+M!O8Ss3B@)inOh4l$3y#1p<8>4*Cx%DfyunM~P#`;Uk39)<~T7{tU~ zvpc;1RLZd@eBu_`bIc`s;^)^HYLo8&vUNJk_piiJx?)n~DN(omu^a)#?JIc9U)mSh z`24g~wMwWtrS;X`{I6d)+cDYXV4lX0d1kCEejeEYO*c4pavs<;`^AFrbkWOf0gN@f zX1-WGsrcdTv$4#cn%AAH@5O{|-M&W5W7hgvNsY2QZ?Qx@6JIiY*TOSdPKTo`g@9CR`2&Kx>;Ho+{bMl+_QSY{uoCMuhe&rYj$kV-WL8NtG00G z&xB{Gi#-m7^c77s&+2U{X!Q}7H?Rn1(Od3X$@fKn&EZFCdK12c)!$7KJo+Gf!d9co zcMdcC!bN{6ZLVSd$-XNp-jh?XGQ|Au9u49N?%S~8LZ z3hIB)#R=r9;NWwOj*WAK@G zRC;5_W{ZZeX3Y$z84ju46Ht*@(h<(%A=?mfM&GF-o6%{1ouR_JPv`#r3p6o$artD- zgWdVXeDd#DKDf@G`#5~UR3*XdB?Vn9n}T-iz2FrV8?fTUZEnV6thEdq=ATq?H}sP? zUXoD!W_xuf%Yhdc?*^(ZPRhL)ye8;HsA}wNH@@lx7yB-<+H)NUZ#r%?o%Pkx!qaaK z?{Ycf1qz1%)la+3SZ7RHVYw z?KbvqF8))rX~6;owLjmAD_34UrA;D{Om|}R!Y8fXclXY;;wXJfRm<~d0y?xV z3cpv7;1-DdmAn7kne)=2M{H{YSk|*7lwHx?TJT!`R9-^I_Kd@AqUEIrryf{*bB=Gx z@@s3kMZ>e@WlG{d@6wG3VQ^SCN2H-A!abjvp=6~ULr=i{i#z9fU%PYqg1^<5w@<=4 zPU_3(iTvHLsy4;&_LLOn*tDlSDjBnuFK?0PSeB)DFqZA{K2~$>KQ{S~8CDAJSBh}A zz4P$itXDGi8G9vJ?B1~F=`&h}>gXL5a+g)TQ}w>oVQXb_?=eBmxUe_OJErf`R`3Y8 zDD>CQe$E?9z1)Xy*h)3SO#Q#Vk*R;`SXZyco}gM-%(3~5UYOIa1C6n%dE1`JzPNl+ zCpdar#FTxqVjkNcC*>{qef8)ce*fKam+pT5vFOQf*IohpyFRaHtl!c0d0Ff(hlKwp zn-AohZ$GPFlvMD-deZDXMGNtO?icUY5e{0~x%;sAhNLX2|hS z^A*#M-|fPMw(TqByLyT@cmJI8`O5U-GBHby zxU7rw)a_U{pI!F#*PCe!{yp0p^&9P2*BJh8Ikx7|{zb7YFH_z9iB57#tSX#Eip#X6n5VH8eCuIovEO5M zJvRGpc&bO_OB?aC;gW$pFBI;d4zT{PDB#R8!yoR?-Iu5yt)07alDMPep7!+$CluEn zd$XtX?dc22D)-X0#P{F5!~Jeb_}5m6br;fSoIIvJ_h$Ruo0FZ?JZpb%E=gQb{p(?B zx2fNjv~<4A{)8m?h?G@}Q)ei3Zj1hQF6?IXmaN^zTYLS(^UmwcUM;?V@11_z+D#J@ z-z+`HkW*2-nPGd)(!)Xza!;&qJJzsDROtVQhv`dHmR8r0f zulcC0!=mmM7N2A@mds=YGc)HE+We=&{~ccPnW4kPo`Xp))QaI!v)lx~PTgMtrq|A% z=AReMeWriLIfWNTLQR}+?1+CG%3&rI4uEEDP>-i!a=|YwoFdmtFpfsv>6>G^Rbj>ySA) zw(-l3$Pk^_cA<%B)o;B84%N*Gm|DSO(HwC;oIzM`_1kMs2VR{x)fMj2_%Vc$^VkUo zhDCc{G;qjYVze>hb+P6Tk8HUfS~d4>#RRRZ&0AW( ze7VdTQF!i@H(TDeNjCmATyoo0va8-bPf7KUyE`|$bo%8Y_g~+N#OFRe^N_=MHvhCs zLVrpO{~G;1VJW}&Y_DC}M6(6w4T9zVU0ELy`TM0lQ_$&!jq4S>ELiN7AEgg=>| z^m1$H-5{0+Vi)wM^Xz)XcK5`;oeyTuG~ll@=5J%oJ8ZF=)vUj?TI@FK{h~G7ADT~p z{ZmGSWz#N|l67HnlVcXRMkhRoNyt5On`!BHhfl9#H%kU-Z+6^u-<4gcHuRNOwWDI! z@|9mUNMD+Epf%QYpUZ29L;B&iiH|2c+|194VJdZVeR%q$QQ1--W#_KyTc?|*EW8qL zUb%RIxWg{F+S6Jl_6zw!9<&}~{`xjvbb?n=qlZtxu0Go<=hwWsR2nq1c2$7Z?(a7j ztSPqLTw3?^`>en5US;ogZP1pk5u3Z2J?Sr(r8d)wKaWc`<~=wN`fTeZY1?4)%Q>N2 zGzydse0y}~YM7YAahFZfXN=f;7!#K$ojU4oKYhDOo$q0vomJJJzTUmf8oVW2&1|-3 z@x2m;7t?+v`eZZ8x#TS0J+@JKq z_)JV^*Y{JWng34lWBpJRdn)m$e!AW2n`^uiH$-g|;IaF|^SzTZ=*~*z-BatI$hzsQ zk$kzzb&>wn*NeQbUaOt)zG|bfkMHYZ6QQhwE8b}~6qhfOm1uW<)pnIfs9{Q^$dVa# z1}ch&L=AU5GYW1O`DyLFoA*KNUYW*tbFq5PgxAZMbJ%{p=37yH+VF+frtrM9z|#wt z=bMY)c@edlYyWv?j?Xbx?^`~uv-SA$JG1j&Oxcy9rB$H@WwBGAPY)GtFY@82VtCkD zC(Oh8H-dA9`~NJ1&7r$iU;4C6P9plj6<)Qwh1ZSF+e;i`uG`tdz9Ik4zopBk@6kG8 zylD5Y?!0XYN0au1K2?qGTJ`F9rAhdOa`}d1cNGPs43qAazFqm`2#-wYta4uCkbfHw zSaaUz{nS7G=B~_QrO<^v)vCpkYkzVHe2!TA;C0V#b_2cd`;7F$QfKaZB^bDUNAe;+ z-BlbJGvl*Mtr@h$1r_!tJqR}q^PcTn!n^M8D#i%?UAxyN@L7eiZcSt3Ayf3(VwKe|3Bfs)%jpwXp{HkoXtxVb25MLLzHm~^grvoDL&%DI< zf7+xlr;{hB)_UiyPXc!5{^~q>^x^c$sL!{VYJNz*;wjYpv8A{^GF;d8!o%rvU4?>@ zI6oMlx$@|;*&~q~Y!9{7*p~d|xRgF)Wv}4w&%LHeEN%~DUMbeFMn0*rTYSf8nl6u* z`4O+@yQka9aGjd9^8ZiEm1V10-%ZMI%Bj7%GUu!8+4djLADnPI+$!6^Aa>wFvsvSX zz!$ldf(}V4+1%Wk8+QI~XiAWhU0rj&+3Z>Ky@I&KJO2L)GF`K7b>=-|{=N=b8H?RY zWeq2@U$43PYI$~l((TXN1^Lfg*$0tn_f@`Z>E;R?p>VIct2iF)H2HFlUG0kFsLJU7755 z>!0r2{mmuOjXfZDWyUl?{Z)THdkQjNTy>hk=xmb0tQz(SmzXoJm!6bnu{-SJ!d>CI z;y#z+4uSA#+n)t&xS}7vN_%I#*88%R4=z2Z?Y^Ivx4pHs@bv1rmaA3#!$Xcy|zu5K{9y_ z!=<~Y8E)R0lKX9t`!G+g1ZE$QoaK$1if10+xVyk1#@=FXBCzBf1 zT~2Pvu6{UU*1MK3=hiUIo>rS6(|LFYU#A;=k#2ahQS)=!>P+jzHIf}p zjRvQ(FNQu(w#dJ?{*#}?>Z2M{DovL>Teo+q-s5$1_N1SD(YeXNY%afa$!+7SFaPh= zv@1(i>4^0>`r!20RkyBenv^frRkD(aqoiBm-Y>>uhaWIJUOAItO8Z{HRT)x=kpfFN z9R5VboHk*ZxLlB_V7}X|tb40ix3$bUYii-pap;EAIf)rNmUGkpUdlo)ZS=hpFzIfHcwTBPiobl?g zWbG>+#iIOGTl-ml@faU|A?>@{=DfI}N3#v%l6OoSzaH78cvNyi>Wtn4^3Dm7kCvMI zZhet*A$`WqpN^Hgzo)br@r8(Z{5xIAa^z#mZO*MHo@X6;owV|H_G^t9J9fWabFy^f zZSHNc*JI3g&rJ~V$oVWVN4DbO{WC0^cTT%kUelC#d|#~Wzg_m*_ZQT^lmA`(oBMU< zxAqjvNj!U_U)HeiT+94KEr3rhioN2+G4(Koqi=KOuVQ(jut8qw7mv}+mZp7w@9431 z@>+>SuZYOGwBd%+!6fg$T&!$Ag84Up{c%KlqRoTplfMRb-+6KQq=;(V1GR_7XG*qy zR6P5*PxpD(qJaC6(;qHaFz+x&i>|Qqg2fUOrfDgk*vrx38pU|xuRzMu;=k*vvQ8VA zFYS+%QHYkbYEeC^ZLYcd!H#WbEo*o0Wc{vZ!ZuaGl`-_b?BW$~AAUMH)1y6p;2&4Va$=|48#t6Uo+G;eF)ejTWKAuZo=>fOiZVip8=*C%%d1lk9+c<62YX>(pr zZv8E$;+W%%2XaNb)v6AD>QDH`zs|4a+-rt(^LJX;zcz0_czL#C{g2di!{x1Qau#x4 zFPIANo9;?nziHP6{o4~>DA^Ubw_JRe%fs0);SE#NzK1W`XXjcH8AAmd5Cl0%5&r>yFYdYc^rAGlKPZ3vsK z^QMV2r|5jXu7iXe&!hpWPn~;dd?sb>OiPA}C}XA#X<4j_v-mhZIa$4Cy~1mGg6T!TrOcCermN3(Semas zJ;u|G?^fwXgOB?w=PI5J-Ly;Z)@hU3epf3+%?+az zIo?`6bj~<^*6(7LYXrmhmrg9ptxwi2U{7$ZJj0xDrR1r)Kf@=}MBWMeHgcS?O=58i zpS^Zo%ZArxGLv8ARxvZJJKy8W>*ya zmAJl8Y5jyKW#^~6`o;QfB!E3R{pKLTKd%`CuTj#{Io6O_G_7#+waw~?oPTKrdl7p);^`Q&Qzl3 z1ZUNvz8gZ!SIky_2}=Abw@0b*1^*i=jS~+6ffNz)4 z%+OW$yAFFlc&il5`7J`E_w3_?pKO*r+2XbC^An@przUR;V)baWW&fb&FQU0oW0~vj z9XF+W4(J$2PAs0C!cuyFMWyV@$t-hy-GWV>yjtJS{3B8G?PeHrxU%<$`{y!D{>Y@P zZhvmvYZ5ZaFFLZ*dXmLPA@@lZTZP_xJUZiLGwsM7uRD{E?40_8-E+;FBl@Zz#kCEm z9=YZ9CrT(<`(vky-kKx%svi$|)o69fuQ_skQpWj9(w;hNk8Gdxqg?xAh|u(~N9QL+ zM0CEt=b4qZ^dG-xj?bgrit16HHN8`Gk5&6^QmdFgc}?JHqp03K%ac)WkIylg{MhGt zZfw~btD}Ck5$osdWl#6}+sJG2C#-NP@4Np`Kx;HIg{##&y!Y08`ttVm-i2DGoAyK= z)RSZEZN6Q(<;3k26Q!m;lcgu;N(#&B^-mWt%QfWJQ1w3nZJoWgOu^IvYO z@2RATTb7;Ch&!P-xyd}@L%WsRl@+Ia3cN0r?v)4-Jus)tBtD$$KhOTPY3Aka4JDHW ztDRJOHmj=L*wJy3PhI(q-r0(|@fvTY^4#AmUAyo5+1=%j%isTN|Ml*GR7QP0a|5>&%94bNoCGr#%7`rNsepxv-G}rnaX`TA*+x~zQ z$tSOU{v32a_@?fa`nwM)E^I$1tXY42(y4x(>+B~TjeZ&ZbW2_4Ia8)*Wq6Ij&gE)} z9xmO#ZV0VEdF0;it4EqnzG$2I_sYW8(?rBWzxA7zvh6ll{Px}&A&X7ydZC2{)N;`|-Vz+CKM3uH}SYmFdeK=m$O8Xt2>K zF7ODed3Mq6a~H23I5An{dhUj|V%w#^*DbkysJwThdxpT&i=|7CZ)d&#BDlgoGO%#| zg8yfBz2B{M{rJ%fe>%=qlwMI?THa*M=C&$&z5Tlxg6}S;R4mJrt>W;!SAX%13TvUY zPWR_&ViRXw-?ek$eT{uQA&%na1=FwYOlrDPpHr8)!Xxj-v%|}epA24`zq5Pkdj0N~ zshjk|AN=RPGC5DkwLOOUH;4IR#cz{NN~QGd_6$}%FUo3idSlJP2`^Gh=Z2)7`|>p7 zhl%IfvSV8OGxQD@$-Q|mFC%*-;+*e~g&MPErU+#goxCEno!`grkT>V%uafsG_Os_o zZeaAB^|ff`!F38DMeYwLMfUw_*Il#GiIpeuzIK*EL1)n07{-4_;wP0-x#zjOSGlRb ztnSUFwcEOmYaTXyoe&kue@G(oU60GMMltSG&h2xumnYe-o}YP2xa`&oeh0+~)-Ln( z9cL)tc&;4X*_^fI;u_1w?QiBh$lJYc!TRKO+xdKxFFs5xT4GgW5axd5P4t5k`wVur zYke1$wobbD-uK?bQ`Kos{0ZOw8{GUJ@=ba|RPwR^ms9S9OQs)9I%c``iA+-by`&DV zGc#w(yf|L|b4x@T_o>-4Y+fAS?z+;=Gji(5Cc8cJwgtUde6rE+&xHCA^;@e-^nSYE zn3{g{c+E7s#mygml6?0xR`)z8X6Bc*`MD!VVj)ZDGmRgujO}*y{8I6<3;riMB=YEo z?$wpKERmzO;roW`{#SPH2)U8%wX^qRtKGb=chYHbvwdD%^w;PdjRXnC5L4l4ULa&p)~P{*~v9waE=~2R@!${#xpdz!lNRgUL)C$*xk) z4e=MdnAQc<3ZD%SJkN1vp=p!Ei&G7U67K6<+bXm8_@u8LQBf(`p$9Yh__jJS^*j8( z%a9m+)+GAr$^O;Zdo3&H%c`HBcx&#<-sRkKy^ya*bj50BuM{micJ+bQwVzB=PbGfgS$6uwqd`{~i*7BBU**8{`KAD_By;~;lyy>|-&N)1CJkAJqbjQ^B_{q<61ZDnyi{r0Kdb8ReBpoi z-#fVMEoXPVa@fAk_UGb%Kfm7XRC0)5SSu#>>qmE5Q0D*5JPX|QYAu!(e~8@w<5z-> z*>l%rxi;I<)~$-Zyd&qd&di>#FH`uQW>4ZyN&aOmIlI~I{2IGSbMB}VZF`c&n(zGK z?Oe@X%fjbwGp+YBoqV?3^Tm&_?>$>L9k8AhTW!J3;&AOSr;69A)E&TB9kruPN%}kY%L-f(+*lVebBV3W{5g!}_G*vYRhTCGzSo<1RYPU|?vs9uYX5a2 zJPQxL^3mnbY*Ah0s>vF1&+_>~y+y%OLJvP^_@QdaZBy#Xb?f27oeiFw7{tx1Zg2n(D$^bNJ_`h->#s&2|5KDV+LfrR*goGc97mbG7$#KHXU) z5FZk_-l3Y+)puUB$dr_|fsgackK}ChsrL;k*tDxpglT&yw~?LEMx_8BtK%w6ITq_Q z>phZ8bu+9|md{#JoPC+;mhLQmjsx?jEPTB5l(_n0Zq7f8g)_V_w@>YG_POvyFvc@m zLgwjC&*w_7>}D98x_W=g)_*f1ZcTsneCIz+hF1xP*CvIzOq%1`c)a-Ifs}ovVVf1Q z1wWsS)Tt8L&o-gJu9UT#V@c={fu{PvvUMwTUeCFZzrC2X+xDjWq~Eh014L$=XjeI> zk(nm6L;BCrle%hKf2AwU4ym0VEiJlfi=Fn9kNhWn4*pI%Y^K+Y7ctX23cH~xpn=)Lq~RoDIDA%q87UK#KmPU z``$cZ*>gtYjAKT-@cFeaY--l&zp^JyinNPOu~INtHurWWo5}U3#k<)Q3=jUl?|w3r z^Z673#!YhSOh1aX`@61Hep7t-LGuT*^AZoWiyBhGE0;o)*QM(CX8 zLDr<2<%vA2l63?AEEc|Vc8SoRTxON|rw-ZAX}Blykzaky0SErL`#0FxbA$O7Dc*dZ zXXd6cjcWz#T?VO)2l8_#m{fM^ofl1Iugv#rn-lai zcW&TKvuk+={nzJuaNTxwc>Qczn!v4HTi-s@in9NcJt=LHnQ>=|tXBM#n3ciz7pQIg z_k?GbpK)hsoUu$@fzr;F1^ef0iAkHmQm^Xy<-Vr#|4*Amw-<+A2|XDyacXhibC#nK ztM9cPSK&6e{&VN#IU7W!|GPw+u`?u3xH!A~Ax~q`xwSI8Z}`0T_?MgS!8p_U@2t7! z|K2+*bXw$OgQdUToEYhjTW1w~9kgdV860g8vJTkHU6;2hiIw&Lj#Qm3j~m$!Uvh0a zsQY2t1bu5u!RhLUIxpt4A9;4$O2UkBYmFt>62BsbldfJDtWFvw8IP)j5SG7LgTfeHRy$Ez#O7u6FfxN1;qi&X+JAE|<(`e`~a$ zly6z7+#0`F}wEuYI}u-_vyU+_|E17c7@b1_bDR{I)~oS9FY^a@Erx(dnX3ZI;-L>yAJkT?NzyQ;N1(Zv-+pvt}9&hxM0L>8qe4zbl&h|O_GK&o0yzy z1y7^+vLlZymvBfX{NxSDTEd#VUt__fM@g@)^bGAKsI+uk0#?zuc?Po2M&D4-vk{kZV(T-B1Vz9)3O7iNW>$-mL0 z61SH1V(3|&MCF)&osOM43=UU&M4xPL6$=rvDCC*#{`}5HwU2%L2R_#IH_Tpfnj`&h zO2e)lr_z7B~LV zo%3h>Q62h$<7cpuz~nD$nWKM`S_;Q{%7xC9>{WCH4H|OdMUWYX)daQM6SKHc{`*S7l`_90v`l5fbC(W2LNoLtX z35L=~3f*=V7iCJ{&-pCOH*JEyb+he+8S-({4Q{c zEj`c}pWx2;c#SO2t0%>i--rvOtBV<^8YV0hYYCM7V-X*DYF7^T+>Gy!CLM}9X1k$u z@@<3HZsqg0)QBEiV}D^&@hQvY85?#zy|Zhp@W-gD^CvNOEo|`G8y-1VxO(fhuA}$P zuGu83pRufIM$O?V?vqSy7hfs@9JC`T|PC>gH9dcC*eX~4tWs?s^Uu?Mesf|EcRv63?%@}= zYp!+C+)9ihCVj^%H$Rzf;k`~k*zwJRNQOoA?F#SySYJ4JB-!zCK6k>~?kSt{XPKGb z{NkP7oi6utN)KzIspOSMF?B``C+%EbGz(jv(yb3zRPot7gzty*rF|d1Y){eEEX@>( zQI+)iI3-2m%sxrUbGt=)pNGB{`LOT1bY^mI2Dc-#DyP{5v#Ev&YA4xD-g$GJQnPzr zIir;C_%=TBOASIf#Mr}x7P)`)LC4=k&=w{7ch z`0PA`%|t(`P~=vprRk0w0mdz5T@63>a{pdh*5y2Z#+TyxAsf41=w>f?J9qcGgE|I< z^Sdm*+Ef_rQt*~xRf;b>7Hy$+kV{{9N@y={t{@ax12bZsESNlhZqKy1`3F!7{^4 zgTB~4V_B9XdduD(7xMcQ=ULseCnSIM;^PTPVUoco;NRaQ(gJK6`QZBW_>*& zu6EhD#p@}*_Qq=~x2l-Co#M35nW$Egvsq>Nhs&a~?e_n+nyJOKDymE5>@0=}&hxBy z-b=nk^VFDq}R^7K|?lSnqr{p!ACAw{0W6YB!j?8bCaC>~P=k?;$oA6O)^+6R+ zhEDy5{GKkpMV1dg-L|^q`f|l{D|^X?`Rj_6cNt{%eL2J=%Gk!5dD7s5K6AYLv*`4n zOy-`SKjZ{zt?}R8v)@8e_4M5Hd~@!9f1?n3V?9UEnQGS?3Loz2JnPebQS$2PgKU1L zjLIhC;CC#ZCW${UoqV*~A>Jr#QSr_U`K5mnRd227SYolJgDrVwBb$*EGrNn3iHwD} z>*1hJrC+N)PJd(^6)t?p>sy}FZikM0Ymx#(*nfssJdI45x`ZtyG;r0GCM)0gDLUWg zRh?8l7?;bNa-UJ^g6m)TA_x8t@jokL7amUgxoNVj(Y(twR`VvmS7KFT3iq?AZCp9+ zfv9Y`i1)5*2mU;mQ#ZrMrr?G`+G&60hJA(&Rz5G^Y?>zLR9!jk(mcJaRnOvQoOS8@ zD#H@sa_dH?*@nZXjMkh#X{51Uj(O(N;>^_zQ#Nf9-W()$W9Q~9p1ikAY^B>97DXLA zZS-$qOQ=)hO{r56b5HxT&DgG~c_w~UueU>-5OWhV%b8>Ret$gj&qRfs(_FVA=0H!? z%m&M>G^S@k?MzY=+L`pqdl{m{dmCURj9>08whpw`$J z_00K6_atqen_cxKO%J?&Z2Pd}+$EVwY#St1JeC9pM6xsV2-^OVx$N|5j)SrrBa8fY zjs;F{T4pnRWKZ7}#Uc2Xnem~*C#FVwW`=xUof`$YJ7zqUj(kum#C&M8&gp;$?SErf zDvsGLe6_sXWcBMkX@4U=`b{agkE>$Zz1SZ$;j5|j~-X^_&EUW*B<&?0$LE5R0=HK#`P22iQL19WspC`|bsEyhQ z{}!c~wtuS2+Nat*Z}S^>onPPd7`=G(8N(Dl#J|~_QvGTVlMthJkVkr;P4YO?t@fu#&iHiF zFUMb+^XF_lU}D#`^bzyc%Kop;>BqiYe^c_lZlO-}$~Ht_Sv)Q;KU`6}*>TO#k@@44kJCNl^u;{?Xib0f`JA<^!iiY(=Fj|d zIiIbrh{z1C&}3T^1-jJyx>tqYqS6vi&SN%mm-3&#ybw71v)e^({jKfX|Y>zZU$$w5x8%N!-Gac@8Nt8g4EG8A!r@!Ne~!+pN0 zT~n46dtPeLIJ8xg+w+ShcWLD!(dm09tDe1mOzO(fN-3)Ym7*NY7rjo4rK!kB#y+2S zd*=^^Q%9dZyjQo${F9Y?$Z>lYmh<+yoO>87T)G>6e(7R(&7Q%y<^FtDkBLd2A1!7* z!pRpfH-1H?<7!LB%bq+D4^k8u>WkWxg2gR+yX;Hb)~wsU;#c~ii3(Tc3J;un`{kXI zld;R`NRt-V>pQ>9`SWS{+@Qmi`}btlI0as^@d{Mhd^z545${eTYXO#mo~K{c)3>~F z?=fvCJ+$*8tC@q8vV?)Oc?su^DwgQ1$qTmd9{jRB#k6JF6Yoj4zqLh_p9;3`Eahih zv01F+-6~cVmPumPHxD?--CU$Tbw>$LwB^B_7g#-RC^c@Jp|qkVYRv>jtum0v; zel{vcs_|P`*4;02RM$_sm#WV?u}#TFhqYu9;}(WBJzcfBC#KK!xqWjhYs38RH4#O8 zby1Su3w7ttXDT@OUg1M#oKuf)W3tBq`)PY_{A!=B878E5bkn4Qqn8>3W^MkuD`DGS zgBiI;w|}gFIA#?^}6f> z61Z{IANXr}luMo8kt^is!I% z(zb@IQ#l*F`_h8GhpXAX^~Ra*I4z#}qd`4ulV#hY7JDnj#O(4PcIImDdGCt#?o*T6 z`ghh(-rZ`4L!Ya3D|l-8WW8T|wrX^l5ELr=L|h-LmAg;w)X9+4Jvhx(=1LwUPHi$viAomoqEo=Fp7oNBkmMWy2D!Vq;!{iSvb!ur1)%(eBL%08o?_5GLA zllC|t>iT74qpIDPwQmDnEYEE@#IVg-obA(}T@ekp_I9&oR#zqlq@NaAvOk$~!q?4BRhG74 z+oxq2tUerLWRIUdJO;vwP#RsOy(wc5wVkEfkn@cGsafxgl+?i*h_CM|LPMIsVJ+ zWMVxqsg-krwy>~6x1xx{bU~9MZstXE!)M+%RxcMzsa~Y7tv;pBRC`%rak%)=rG7k9 zR!Sp(C%^eKuDJd6)Z$+jrcPhBN_>#~U%=$uo%2$lR{hZ} z-?>5@7iOkNsV4l}dD6c9&*w94LLsfyMk^vJ_yn#PA4z<0;a}UqTo%U#a&-j<7uilc z6EXb<-$s3YF3~69EG#a2YLqr!knF0v#qjOTZzZef&j*96F4(UXKBM_gP|QGagUJ-v zn62hnWj+hy{?zL2=R6{DZMV5i6r?@6-juKv|k*d&^hcgyho*SA$4 zx9h3ipR_efIr>PDlkM*oRf)#7N}tttST}J*uwPr6B&hk~ zaO3_r&W&M)Y1R+?)AbD);(yLrzrMynsz=EqW~J)X+&2G-KiY*~aX*p%(Jb_GVZp&e zdOtHy?!I&U=!3+Ktn<&9{Z{8R`+hy{+6ndx@m_~kXmI|2xTfF8x_nlhs&OSHkPFeBF2ma690<}BN9+aQ^Aj8*8zqsD}BY$F`hSf!7-y_+&O*gW(_sx#JzkTg5UjIFAx5LyU z7R@b{6qJna?7L7A>*iWtwn_U>^mLu|5BaqNQ_Q}co^)$XxOi#Xa_4<-p71e8oP4{b z{_4@>XX|&Bw0~WFXj|06(>1|js!{f>8u8}a_S=44z0BpF!-^lLn>Wt&O|arWTx^pl zE*L+al6{?Cbwbbh0wnd3RGeXypa1i4C=Ptpe{Y4%#j$2G2KUTe+ekpQelb^VGd2iq>_Ph(ccRPI0saEgQ0?0X zhF5?5rtsA3*iX4y`qE#G#d*rVyq>ntJDcRbxOpy3I36>#^ZlyB%w7>fGtZp2yQ~=P z9{-3%|seb>d+LIM&^4?oPRR_tcAXbiAcJEqPbf5>l+XynhpzyFnf?qpDXe)wJF&HhktF~d+%<;#lDrB zMK)ib8*RLid*;o5k#A=Q=DD>;zL^mgC7GZ0c=M^i?9?RpuASK$D^jDTF#SEdTjl4o zJ6W+w&9?coO8*Hy|9|uI{P=k?%1Igqp^fXG7jsVJa$IG`a&1wPj7v9j)8SVyICfsS zb6$nj>EZFXNjCG<&96#r?b%Ssd^c=DFn>g*eC3+hQpYV@B)4cZB~MiL-SA^Jp^;Vi`|rxZGtZt|6w_121!gJavBXHTV7Y6BeYBM`RHn@N?pZy8v(xJTH$0kFoNn=gt96dw%qNaJoca0Y?posE zy6h2uk7^}H{S{{Zkd!PB@0R`7nb)6l%i427ru%62si@+JfBVAcrJh|m!$B^6^UMQw z9Es~K-NFNt44i&3^Io1lrA9)#(`w1f_CL!Q&pv-FdV=$dP0iD(0n1fvFW6Q-c|Pfb zZLAnCYvZEU6MCB#*|5bHC2aYkBL5~oye2aAso~1@q>asMyJYnhe^?mYwCYMzHkCP+ zoe`9fl>Km8`tdKS-6aq5x$fDXdA=lrZ{DR(LDk2z+JfIcW_i6sd^PinS5to4{kr(% zG|!s5vy+ehIF}#v=#$5!=C41bmmOTO+axjI@WvmXoL;aqmMqOv{uO*Cc+*yw6YbK9 z{rN?<6YqVS5fV9Tt^Klfd-Y3ILyeD|@`<=|+gf5bLqY`Ktrr{t0Z-3J_%*Jo`y`f*`{-3^{ua!Yn8^KWOmzO{ZU>yL#i|6UY(;4bwiqh7n< z<(Z2I!ydRZ)$I`dVasTLi|fz6hWod<{xmk^Z(Q`!*4UVT8`E{;&js2Aw#K*Dys8cU zy?E_`)D_>qZD*?2cyN2oD`s2c?|j>trtiCNeTyq5?b*G(YY(If-+3K#bv0Y&$K;Of zt2T7(R0|GCo%rdWk@BU)W{J~_9$3uQX7XG&yZT?2cAwhSDtX@fXI$7Bq9?q5w(pg0 zMUS3DR+WqU4|lnf>+OVFm%_x)+kczoT?- z29@>hY<^cSs^59g_u_N`z5jP+tZ`g&Y3aVXOJ}*;UcKPWU%UB!?v2(-$3ksxykB{U z#du`l~*iHQbcO$ou=jhUH?9R(|1;nf|l%)U7?smaXLZe=u;%s+l*{W2XJO z+$5*7Z%N|A>WhcAD*12j-jvlbC8xsjOITIG{>3wt_AKcBT-wYcGhy3O%eVY;B_g{| zz2>x#+hZ9gBCk-eVcB;%n>QMVzQkqKY-cD*an}`@JVP^0W9}6Naj)gCzwOu?7P5Fs z<(1fHMsq{NU$bq$TQxCor-%iM-k$>dxQHnquii1wIxRc-v9G4cO{eUmTUdXrwM^S8 zt10nDN_K{ed%vC9CF89xf3zPIOKh3rwdEq)N8V2}Q&pF~E1jAY`}UcH&HvMOH5K*B z787@@6zvE&W%ojh+pF;G$5g}FFKvGt+z@)@ru5GJp0@6`?+?QjO=hSq7wSK?QzhxN!Y9Ywkqp4O=b*%ipXky%6X(KXLcus@8p0Z#3MteK_JP zcfN})Urw_`M1PA{uZ{fsmqD|qC2XvYJ*qR2`;7GiJ5Av{PA-K>m+rDeODnhNhjT47 zFL2*h>K1tU%M`ZgpXfZ!qGlaOtg=4 zia$@_*Q<*;RMurztt^v2a%JDg6sDL@6Sq66RJd{NlWSPwTz75v13B3rty}mUx^De) zkcka@Q5U!D-^Ii=KJ(mI*xi~cV-^=Tt~CAI-}mV2i{6>K>PL@C1$@_G-)4RE0C%QY zpz_WlzMqS$KdzeK7QE+WQm@r!jw*Y;uF&S>OUY&m;y>6G_bf6$6=}7arP8iS;y}n| zo2y(*88s8nZJNz`XF`eK%1A|1nKcLQ%m0j#w^+91?8TZd8VqSM^FAfakP%TA3VD}c ze?vi{%sIZ=BJ#}t=~u6Y_b<8Q=x*8T5h(cb$6ba9*3x^ok~Zx)xLW7v!b2Gi=0A+$ z*XbE|=yfNFcVDo*Vc)Y&&`ruy{by=fXvo&x6ZyaOD~TRZ^@~<0y(26W?eRLn{)Tn2 z(%Xy8eDj+?yI|(6bUx8^-;L}3dkvpQ1uoJ~;wvi^lEwGt^M8|XIeK({XT8A1>8_iZ z&IdVc|1Hb8?ZKQ*ZwI5+yJ2f(moOCQ#)oxYeZ9m|{`cO`@_D1}#8=AVUeY>~}-}-;r zd*#PHTfJvpXHR{OT(`S+{c66_qJ;XTGBIxcx0)vGExXG(_0IcMEqe0Jb`#Y%J*jjL zI^3+Aov^)MrC9m6gvg z>b}}2ai#fi!F9z$6T3-e)5i0Q_2152$=g0B&~C3zcl@;? zjT%FJ_aB}oZ?6;Vx_RbnqyC#x?uUKFSF<)w*v>ma*JJCc_aBXR&unONxwcMv1K;GN zduk8TO|HyXCwBE{uZL#ebca|E&3x+x*8VlVw%d9WzUtiRZ;;mFOi^_?c+*Hl^S46K zw_iaME%jEWN<7ZGsWv-a3SBEL``{6uu`feH%V8b6PmIpOiI$A} z3U;h+S=JWp%lG?G!iSrxzu9gu&DLXk%CGc2b$vz3Y<-n&TE$0CvhUM~2;|T`+0++a z-OgTgtY+bQz8#k&Qr^pyYnJQlutLE+c9BLb1dFk5hoxXVw=j2?Y1Jk)LSDWS8d}L1%ygTiojo3G{(=sgG*LGg@ z{+z))r@5lWP~RzgFPF;?vC4!W z{G8L?v$q? zUGh|$v%zLlj}`GRek!tTCfAYhK#ot1E=Shx<>+5@Va=a3J(cNSJ{;ZT*2BiH(e~^4 zcGV|M*O#iVvHb9KOP_(?xtI4he_HLXskcPL`i(}~#k&)O++~+exDwaE+V61hb;A}3 z#dwL=2X^#KUurDWQO{R%a7{G-hxs>b=l#7>(Q)(;|8FkmWS6iF3S9RkMecHi=lAUV zth&>$^x3(Yam(UsRbBVoO}<K9kuG3nPw=~o$aQf~=)ti$OIZC|U>l(x4tiN(^ zG)uA7>u!B(&#b*eJggzVPv`cFDX-*y1jQ~cKXIP(+TZmTXXzi?%C%7Buvo^ zEplJabuG56nOEGG7=#BMx^3n<@A<*mQI<2-n@#exXJ(Z(-^Ly|YhF=f$SoG_dN4-V)a!@_n28 z#S7K;92SN%6i&ZaS17)4{P^^z|7v6HZuwu;iW6PH$GK|h*^SGt*Cgi2%(_~`S1Xt& z@+-huK8LwBegXgX#yX7)?$HkNoFDe;Hk7V^pU=3)`fmdF19zr3YnSWn-X|z9GizgJ zrSj7~qN-bMPJR(9Fl2SQq9k9jl)v_%y1lW)#&oZP)8FjAGx@LVuOj~|(bIyPuPabz8|Y~S}_^Xi%kKmOWEb)zXNe-q!b`WSBNcaGoD`SV8= z)0C@)wa?Ef7ESo0@kpe0!^#(d=@;8KF3QR3uGxES--i{SoZ~ljdYykIWX@Bt#7%Hv=1g4=4PKy_}0PVP$4d$rT{#A;degg88V@I~P4dev{-?R$^bJWLOm_r73~ zs?7JJ+ReA#m0nLftdqPNNgLVs9+k54T~fTLZ<~yRZ9c#9 zQP$1OA5}kZ%RF-MUDM%vlU6m#?&3^n)@@}}2#RJ|uli4er&n*LzW3FKN)G$`QWBO- zsFV3{uzjD0>8A&`6(#Myu&#~?Q4@Q@J~_!P$FfD!W2>#*v~S;UR;{ZrSoQ zI65c1;=k1M9}%Z+n-=*k>n`P%*{mDF3-tq3KN|}@-uy^^Q|yvE%B}Byx6XLuuuqEPT%>q7Oz%0vwvb< zQ9U=nW5I`HejAqZ2Y1+GrCk@_SQ%OJW}U^(gO_4|v*`Sv`&mKz_360q%72Y-N&_de z@Bj2N)pgkfwZN|5(#);J&rC0iEtUUO6d66o?fXTW%gb+zA7AwUXULrZ~9f#Axkw=|@x4mmis)hfZ@%_1-$;UC#btO(csWNw!tpn{-GmVfJ*7*le{w5B$_^`Zf{|H z&|zYkdADhgPj~NL^#{)JZQVx$i>eR%vTGlEWvC;utn}hl+nx~iu5Ayd`FZ^4nD%v{ z{u$NzpZ~~oW`x*F$^0^kVcnguR{8y1htsS0YZ=$=3cY3;z-xF`U;5$iq8O#Zo)=vA zBXfn0O@DmtXHlMT)wjhVTbBPjm!v9C8{ToUdvW@+gj??4x2=7omcLV~V%JKh*vW_8 zzi(f2%ACitM&yl7rF2qvnNaLqflX7L4*p{d=GM8!5muJD!u{Z}jd6SC?)-M@=j;`$ zrbR6dP-85gXTcY=w6Dg}K&$*hq2jyLX~zGRS^54jrCf4+pDI%LrGisK`t8-FR~E*5 z6&fda6-~~{zkmFXL&8p;hSVXZp=}`mIwtj8`A+iFxV4 z8-FxQKx{(U{=`2zhhCfzH{~ww)Gp%5H`J_hW~i}U-@QlVOI67RdHs`IlCyN|tt>hi zw0?z0^L|aZs~msHXW!MUmdrX;lV>q_aMWz!{a`pjYuCSO$B9)(t=P6j9E%W;`}rwF zi)mK!RHZW>v6K9q9&6u{`^l85#VxM=p>Kr&=eETH>&~fo+-#q?>BuRaYrHr9t^R+? zyZQ5$+9%#q0!5`Ny{8;|)MRP#kUN2gEt@nC<{qKfV({Ar|vvp(~kH2w8_wfClzA$vRnzXuAm>hsA`{dE5P-hE$$b}oG@}X{X#)gME zwVqcd>L(lvTCv^doWiO-2b<^Cvm_ecU*?*;(R$ySo2wb;O|(*Bbl=x;Q{QXt&ioU9 zg0psruWnpd7aL>q}EP7|l^S-9>>IQW$i(~=M9QW-zChzD!dsgm1^2}!Uez~{xr90;D zIU`c!GjB?6sMu7c%^7?m`%b=@bs+FY`&X@-oqaiX!qrj*W#-wNW`ER5I`H@Erzhnh z?mIUuGMZ=|R$j>U<^5inM-$G^dSbNx^TGH3{+|DnE#}}JBl}MF-tOHRYUSTgtvc!0 z|I0iF^{{mB|8n>K-)&Ut;gi3&`~QQ7hws0Yx3RFW`W3tB|M?jVA2vj)pL|~zDSnxM z!*MIfIqCkg!eSF7&MID;Iak#5*2cwMJROC?22;hRpM0?J>;2=;>sNmEzkhSr+JuwR zt)~Aqpa1{x?=SQFKlV0v>VLfd{Qtb=|NhAZcPE?p3VUvd`D^~-^uI4hKTlWptWpnM z!7MNHH1vl>rlREEI{UR@<`QM*lD4wy?OZ3-PxAjv+LMrCoOj`5Gt6t_T5J_ zb~XE%6HdQ-AOCko&HraduO=D=t<@^BUw?de=OWQG)_?<(w>Gs#8N8BYn6I(QX`(~L zPiGM(g>Di4q*+br;!=DSZ^C>t+TT}gIh%KhVdqkf{%qFhsn)uWY+YL%O)V5N(rz|A z(VeONOz-CDm5C~QC;cz`w!FEz{5$`< zQ}T>X_+g2KJ)4~5v~L<#RHjUcpKzE#XiBJr(*Fb_cPYKAsguwDPxhI2p!BTI``2-A zAA~h#Ocn5Fm)ST!N#l9XBHI<-%q{L&Zo(hz&a16(*e8}dc}`sV({`3Q@=w0rGssjn zJ=oJuEs-LSIcu=?Y#KJ!%d&Nw7qxo^Z*GnjknExYD>bywEcbEH!q2s zz93;oXu0&!m51(F#vU^Xo%qPJP+eQAMEp?S0wvzOcRCMmEV&hs-ZwFU}mW$62%x5@!c<&*Y|-~ayZ|L^?#-|MH} z`TzazfBndMf$IBzr?30p%>4EF{n!83$J8I2z4Fkql%2m`zHzYsTVL@0-$CZ`zx@1i zHZ>pefBm2TG5<(a)UQP?tn&PSQtmL;@Ge)=oVX#j%T!_In^j@ozqoUlbuOvNVw`ZN z?1#@pCy(mrNC(dpnFP_5ms(!kRQ8SGcxMzVV?5o^XV3g={2%KdFU`>1lE@yJBU;c? zkaY6HhW$HdMeTQI$y_P=rYP9-@J7CKtSgs@HXoVqncom(`)ygmm5KMxiWl6T81y8X zt>e{0by58-)A#yoonwr)U%4jk$HxcXmhL?nzbyQvQ`!9Vup{@ktcAv%lgW#6x;cSvlp!j`p9v1X>jJJ>QA0Cbw#p6Oe-^=pFQ}(EOPpnLvd?a z7tWc&%W~dr+TC~YY>nFwsy^Qm>+mOlqipi|m?=(zg+C9kIp&exyX(_2wcl>dOxZm_f-mZG}t?Jjb zo_5FM-@biQ%RYL0YSyKOna|42ugch_6h3hYyn1u9e~0nh?UF_X-LGb_FTUDrvelu5 z^}+e@tXl8#f(1cdij4<<{@UeZ$ybnmFW=_Rx^KHT&$(tgY330F&a8X9$s8}mUT8dJ z*n2lS$i(DZWauP=)ZVzCZzgYbf3#+i;njpYC!ZLtPVW>gNDx2j@Zz7IVsCa;V_+^j;Z&jQZL zN;=Alo$425ifwwwvwWMx*~kBGaNKiL+R6G{Gg$A*V{i9>@4;*4ez}|)r}jQ~+d-$R zns+T)Y?o z)lUk_++u8Dm%vnJw<^10j?8Pv+nvkP{qN0lgO?G=@N)mH- zm_x7w=l!uquM#l!%;n%jAbI{r%(qE|(O#|3XZ5#pVNxGmK8vdm5a|wK{oq z-udGv&EFqutCDAA+i@-{sN7h@ByivC3;rHP zl?!t+aad!2&!V9DfehoZce`A^F=-uN+r}{^=VHjocBfeVt1>Tw*73&PO*`w$c`7Wm zg!kYYsV(OlTW%bD?rgiqMzLk?gU5@#VxJjr=bKZxjw7lu^78Xycm9o9w-?2%4ty7R z)cu^!>R{*1C-xuz)^|H8xX;RJqD;^6cY?eX#>ILbyC;bEZuAn`upo28ti|14O_BX4 zVqb02*ekdoPUwWvgCFg43mQI3ZNI(cSi)kbv)T)tA}^hu+xPos%nF4Eg|Fk(w*L%R z!MbKMQ}bNKducfqCONM>j?eL^n4I_}aRZajyFUe=zCGy^>-}=5Z%fnSXPb_3YMjxY zc6{gi2xk!=w?k}ie6Ac+sg$*v+0Zp9>(lr8z_p8`!(R*h(fhJz)i;r?k*ojzPj;@C z4Osq;*F67A)mQ!Nx$Cc;I2!d@>cf*0XJ_(M+RQn-vHH~?rufU6a-UrOE^7bqcjJ<$ zU5{>*A9XwTuDsZ6&iWH41D1Dhe5BoK+Op5DL4G-Rm%rDix;@Q%G*2+3vARuMpLl8I z-%`%Dl8c8`yVvqLDPO+nJoAcJ?Pc@U`Bt6FE-t)v)h^e#V{xAG<-f(cQkTxnNwyX| z)Aluz>r(C4yr?59d;(tw*_SQ}-qG`Zf5rs;Gg7*lcU0c?>Q4Hu{~}Vxho61wE9+Oc z9H*~++#%HP)yYimkN)?6)2Hj?IrDOTxcHSbzft92oNtM2(f<8_Lr6mS&8pcpJIgJWsT}(7*l@9uK;hGZ%MDry zPTQ(Dr!oAU7rSezL-K@{g->~BOnaxgYJ%SVEedBRExMq1pswKj-tX!6rT?5;w~mG7 zsrdBj6~gWB3WO$H(R$Mv+su{e7PqYWfcUC?slADej;)5w;yDwA7VI=xy{!7=XER1_ zO&O2L&%I3_c!{fTzc@4L+MI0(K?#oqMo|Q_4c>+CpK5^=4g@#alXv-XA+xTZ`6@~rI_oI|{Q%`-2S=2}`8oSCCJ$uPevq1@_(Xu$f}(DasQgef7UPe zWuEvw*_5&GUx@7n-Y@s}vbXcw{(Ar7U-R$(%l`ip{W5>^gWIng9XE>9w(4*0PFj^| zW3xz=JF;#0f;+q)GAs`+=?^c_-}!m^3R$P@(AYoF{oj z&#z|3dIU0b{VQh4=vwO9aq;*QH^W=;Y9FpoRFPEB7Om@>d_LHrdX+>O??0zdxfi=H zK8W2T6?Fj zqE!qoUw`%L)v8y!JnW~c{#f3$>qXh8^VwHfx4+k8%3s;` zpN&>I`XyqQpH1Cki8z%2xm%@NFH6J96y~1tnz1gyJ7|MO&Fbp(qw`!%4`pk8xH*gI z;qtP8v-2CGO0p7;?sgM@7PF-J#JPME$4~JL3uRV&zAY^=4Lm$u!se1*?#%$ToSho3 z{hEepfqY$|VO_avk=h5Mvrs-F1qmnsL9ez`2XA>`3f zqV4|wM9FUj#)+#8=Pv$yp=8Cs^}oFeFGp&*1?@sayj6i7QcOk_tPiSc5wSGWn|0DD-?E_Z2D+@ zVsyfbZQeU)zFw(!E$89)^`*(@)~(~zU!-*JweU~VMJ0bv>F<28wo&q318+mwhxZ&C z;sWMzZnz;II4$z||HhqZ%cgYm%kiD={?z=t{?4w-^!H({|L^bK{CoDl@5w*w@2iIA zsnjc%ypEZ`{XMo*Ir!s6H=Y;LO|z%QhHam_bOpaou}Qb_#+de)`&(1o4~HL9@4M@A zqfd*oJNJi>i_bc5O-YqUELw64?0)CYPT1R(8dP?mhI78Vmq6L|JEsAnXl zJ1ys>f0b|s=j-1~SNdeEGGA|U_0#mZFZ3-RM(_V}Ynpsgs{MtO{QsL)N7tR$`qv@& z-=oEEV~w^vo|$j=we<47PkY|iEa|OT8u|ax=KqJ?Z(WtoJ8OUC%>N&O+kUjif8{s* ze^*vQ@qWcZjfJcXIZtmju-Pm>@o-*F(OcuH;?6+Nhf`O!ZZE!W@Vh%&LRv!ov={SL zryF9Kfq!Q1II4F@_{P_;3BtCQW+$1>J2PRmR)y@DzrM!|)5;pQ&wBdY%b7F&ukxR+ zl;w}_%(~+@F>d{;%U#+0=VDG2vP_p`HD>JmwPn+a8Jqm(HWh4%Qv3BzW3Ffkqo4Vn zCyFj-q;9>Z+5N32_H`ZDeb!Z$zqw4W zr$O9Z-&rxxsPf;rt>smUsvPawvB&y%rRPL6h+XOzQG57U)QOpEl12&J^T=1eq7nU; zOJyH;ST$wTCo!l<310K*bL4t-rl)bqMfDw#-)p9|zx$TlX>@m?t;S`u=*&5P?iAKa z{#bU&XTE6m<2NkZ>L!L|c-6gYI++ph=jkc|^Ndq5)2rGzZ^?Xpo)UOl%09h2?r7@6 z^pFc7+>CRXRKCFR(`M-1}9rxY5aC%l6lE^mbh3WdCwFAwE9m zlDP2{`32jpXMYpZIxJbF`Fgou)dhyO3p>6Tf03ONdu^I)z{Y(ya}1qTlDQ_V=b3f- z`{`5P^ZtFi{DJBJ!{+9NiLG^s4lD_R49C?3em+jq`2U~F=37}^CXc0BN5VWm$*Ipo zFP>$&$8!FmAiK1SS-Q%(wX*H5OS`@1Yxh1C;PNS~4*PXoesh7yj4dZ8N*HjmRPE5- z=Gfm9n*S?wnlDi4qVsQ-@N#Mf<**{;PP#rmEem?_HCwst(?}w{`V(Ti^7}HWt(E zYk2my_$9fNP0q=Csj04KHZfaoHn$*;)}*=z$2V=>!yUPgli{hdM)rjdMOv)9fep4< zjY2ctpO@vAydbdax>5h^6~&Go^68PsStgV=)ZV;Y;h$n~;gH_;3m2EEH!A%Sb9-V~ zEYw;0$|JI}V`t%Voq&&5XWrCa{quHZ9bb-Bn_|VE!-wC0cb^(|HPfhaww~s?6P{6p z`O_GzM6z2RiSu7Ip7QFvv5A()#wPb~7uL*w^uA;Hy3nFKrKS=dsxoPf*A&aQihbN# z&(!e0a_vrs9%XSFWh& z-87y5?a%Lb7ALS|7e6u-NXYUVtX}zOjAAT%a)^ROriE`NgZ~Hr2XBy1?n!F^X z`Pbtwu~zaKTF+N$%80zHH$K;|f4F&P@O}?FuGcjSB_I8L;HthSu}SvNLZjQKTE5y{ z34Z@=|I6!X_bvXbaa>7ESSTR#^!U!|f|^x~qL$s)yPR@_-@Ep|eYx%5mOQJ2=Ih*I z4xX>v8Ee0xHbVWV@)Wt9k~QMHR^R(+G2L25wjttrisw6(C4U!J<}pn3u72A1McrcZ z-S|4STOpe>y%?VKE?=@GLwEPA>v{(3_x4-spW>b1yG?x0jK>o!ds%GQO!j@*aMN!` ziR{T6YeI5z3Z*%RLgy@!ZY7;-0+JEd$KmTG^w}sIpl{vdx zXLJf`#_QF{&RITp{*dD zDHd;PQ-pWD{kTAoNuGzz+ zI$H7avDXiHtY?eAC_mI2db8oeguJ{?*Zl_;FfHEo)$r+)i1^yC>(un}^-Svve_x*& z-oE!^R`KnOGfp+CmeUQBR(t4+`YwB+n=E!|n&z>|fimK%H%`i4=1lG2H?LFdjpw*% zCY0bbb%TZajQj(u>~s2FySbT{2tJ#jwj}u8OO9*N&+hl`_j2@BRg3BMe(sxc+bDNR zqOT3xW5vb$vbvw8S@E2=&-2Rs*Y5x2+_~RtUaqjZp1t_k%{-I)*^AGn-!Xe0_W~jH8S7$fPI`N7>$)glN18 zP+qWW#R0GVe;W2x&XfImYwC?0(|0*JA6w_%ZHPB_`RT(JzE0`at@P5ztFxKcE`GPh z@W`&u?Qh)|xmE0cQu>0=d#&W0GVMc#GX>WfOYHvaF4?$6A}cP9xA)1f;tgx<-~4eZ z&Xc^o>*wFZ@6%-`n{V+wzU6y&U#4+RrsTb|{fwJ_X_(8(#Z6rJUijHeqjg5dLRY3Y z75`iQvNcEIkl+06OATXR{*C_Q^gyV*$t=qLdE(X+^6&nfiko3LG0y98Uz^43-^E8? zT)Fmo?dpcN?-L(}9N&6#4fh(eh@4Bm&Yt@~HpO-CD|>)~U2RMK4 zr$1`K_Fu}*eB5vS`c{VgVR>oRFq1~1_?A?w$z{cQPB*8mdiHli$IUy8(!WDDEQmHt z|B`6!SI74|`u*PPH}-TXRsVi=cl(;U$kt~c{u!@$U9jFlAbg{slz*+y+Q+-LzTC0L zi0{VUq}{Xm@8|sR`+Pv!J@)&WY`Kfoi%QfD1YO#1{g}J)^A7ujKk7V-mOc;p6ZA2@ zygch;{Qe!AKS%#r9r*N2eDmnrEN8|0#A-=X;xVbE0(jq#oQIDEH^<*OP}{9{0J_@-N%N zYK61UrL3x2x82p|6HER)?6;n1)#V=G_9>KEJ+8=&UD&1R^4kmM(n*&eoydD|Gw#97 zvj;XuH>PiQu6@%Y*H(4!Zg8r_TZuUbGb7`ERUBCzyI`x_8lhv>k*hdb4tzc`)#$uH`>dNceb>$4-r9tS*oqVn19 z&5I>520}gyr#zi;YMqb6obL0}CG&Waj=cPFXYX1!p*1BF&S^v%ZrQZDZNoKN)1(`V zqUCoo@SdCWl=Dj!yLj>P^v?~lWg5)a!(Si?H_na#@N?c?v>qd^XN?vu$DM@|!6eXT(lAwf&mP-lnu&(r0H& z@49yD($;rv3Ukg(DC~b+u9?=;Wv_*st4`wpg7P210W@#l^1 zGx6@Z!F-KJpMJRPs$6#4u5XUtFZsp&`F1(#@+!ff*H3QTS;iI4_wcNdQvSU59b4_y zCl-X}ZCLXp|I?xWBLDV_t@*DNbU^Cg|L(oF<3qmwH!rV0{r}tQ5C6|KZTDu(d7mF_ zE%H=#&Y_9FPn?tydTC>2?@VJ4$ehdV#>YG_%?&iO_nm$q zz~%9h6KbTKJyynJz0L4;+V=GP1B{#)H!+w(+l ze)qW@m9PFS__2t?VgK)$t!LN%y4oxEH$2O4xzz#T8xN9A-&=+Y2cF-{_wi`_5mv7) z?6n=s>uwpoJa)(>I;Hs6iO5{b(z1mSYW|iJB|BC>l-{*(ZD#WQZ@nV*_3z$BuX1WU z=`o>y%F0;I=9vAD0vEa*J!3c3{-yN~BT4Z&YfdlAx)yyRXz`X9_lY*2lOp!n?fN9n zz``qX)%<~>z~{g3QjgYXyqf;?P1wyl?(7F=8Q&_F&V4Ij7dTJHsjs?g78l>~-7kVK zG7G=$TD3;(olu?Z)m?%IGTE;Bt(doK^|rG-hcmwiY+Vw=ezf3@im`E{)VtZa8wHPD z{yLqb{m1RSabG^CME`2@e7f>f!aQ-!<7}*3W-!dl*4t)t_eGTPEuFd3SWB%By_j-t zSN=j}i4UEw+=?%?jNG)>^PN8YGx6iEV-FK;THsxws@( z>|N|CvxOPnh4!1RecAl9CrIsGnX~PDsa0Oo7C+~Xzo(qq*rg6e?fYe|zbf*)^lbgD z-;)>Je|FZwzSD*O5M zI_uYltgQiU^RJo6uvW`f&p35KIBD(T_ZL<^Jo#6={$Bk;KDpZU`>MY^^5lQd^7H0{ z2S5KcH}7NeGK_81X#3f6vgk#J<%xAkmo-g%CCcKGCMkTLd->FX2Zr{kry|w$&ma5A zQ&DH^@@`r8HJ`bQYj{fU-(2qeb<(G+`sXjHT4_ChY{baqrkVEh!!hRU|LYBoP5;f$ z&aNMCQ}xT1cjw|@;nNGlQq(Q>+O_j}dRato6cl;$!StNe@%DVrIggrqe5KDm?P4*0 zCVcoQ|HjQT9J_7LP8RA_Pc>V!S#`#)3-3ev&NCih>krt}m}qgcIy(48m7wPLU5wEN z0omCHMLtEnuvmUC@J{*hOPof{uPfKjTJog$bS?LMF}KbilaBJROlK@q*6Nbt&WgLd zS8-8HWSZHp1?$dSYmUAjuY0*eQzWnDdB-Zj{g#)yD?Y4oTzQe}%9@*pbGi!Os2trS z+p{ZfL*RXr*^?v_*v`0ge@)-6zvE@^Mb@czxACJ^hHPtXuI7?#}}9D<12y8(#SO z&PZ9{U#+s*9J6=To6fJB@tiZCv2*_9($_xU6iTKXIB;)+`wZ{0{2#Mr4Ky`_^bc3N z%3tB1TfunN|Nm?$Uk+`ztQ|gCliWPAb35bL{_l+~(>33E<8y|vgXn%sZNHGqQywi# zwhvjDJpJVKtbCVwk^BjQs!@s4B{Vgn`%P$_#bbWtSdYD?NaMV(Y;+UZKpIH7~YlsIi{-;?_OHU z-hB48$}j6owkEN_?vzhvmY(dZkD6$1y&bY<{-iaQ>~RwI6={!eZseI6vNlNWr%IN_ zT&rWZ_~+SHetPrr!NF04OtV6UUUXZp&6wSN~}kGLD{w0&mWk~`(4_ZIA1 zx9(%Nvu%RlA&Y{)2@x-s1S_U5^gDDo>b7Fu#m%lOIg{Pa*!3=G+VMtV-n?GjG?VR@ zi?hN*wR^Ho+O#VjIQ+k-s7bpH*wDVG`_*C=z&BOaEIKSis91nOEviC;) zzlhI&Rmv|g%Ly!t`(WkV_H=^pZT`gv6AJup8cz1yxoAoX>lWUaY|TjD)H03QC#xr4 z?usz0u;eTh4K><;%gyNd429jgV(M2*@%FZ*Zz=4-Q5S%NFK zZs(zwGcB7mf2trs5t9n{>D=Y~*nBQlwWaCK>kpDS6+eD_x%fCyc|nG}WXFUl z#uqbgT=r#8+m`9u@@Bu?i4&`wcUFfNrgM47bR{0&99qc5tA2ci+QLVD`cc$ zv{lp2&SQaI_?-id!T0-KRWjT^^+k2p$6FOLNiwq-?_0d z$?~4PS9IC8#dq?=e4Z@Y6&)-+Rpw2th`ncfn_1POn~R@z$z|?UIQMVU-@oq*1ODVD z+O;VwMXNsUa?$U3#d`GE&NA+E69S*Ia{o}!+PPiIE&O91PavZ^x0rX7yoxv$(X_ETIz31hJc{B3! zBuetHbBF8@__Mw*ZpPA!Y%$>%C-LSem!1t-!rt6^a5sbhkNq5LIahY|8L}>&tuZI- zpt+3W8!?5I#xKmBZI-)&Yb0yJa+5O3fU+n!D+)&EeGvk>}othHQo32TD)h4`3uZ}VQ&e-wl@s+lA z&)|*Ov6mXRolu?LT{2;g)T_6O6%zYZ(}c4ATv_GN%^J6~>G9VGXD2@MN}GQ8+~S>w z5-e|~n0imEjh!LJ#IgMoy!Py~P12fiCC}xnUz-*Lya{lK6OX??fp^LGmW^{% zt2s4xoZ!AUb=wPljppzPQ!W*R6wX!KAEWzWTb9ARr^25eZ}90}@a^%IH)023l8-E4 zxm>9)rn#y4_>2X&w={OLEa6=AnQQ&q3`5;>W+xQ&=iAnpDV2L3`dV3cPK=M!=i#Oa zQ!ZxsGFZR4oFRPwV(x}Rk8AAIniss)V{KS_*7ittlW@d~^2mveQ?4!3-n8@fZGG>P zo1Ddx&18*v-se8*czXBwiSDng19_eSd#e8?eqV&tJvh%qUowux>J`p&svo2T(@%llL=BeZec67 za~`!i%Dm0z*i9X6{hJkhpFeAw?f6?z(z^cjk5~I&-AyoP`lLTIr~20SnhEm8?6){~ zy;`&J-ODwm$6u`3I{SrW$^@Rkhm9Y$i1==LUSYB=&a{l_qTJ@6nPzRh6?2wu*3`Mf z%Hv#O_O-k4ID_EAl-h4+A4aLF8ogtj5MgpTr^I!Q>D)&)Ig1l>&g(I7r#x5QXRo$^SQE5zTX+RX5)YL*KLb@#NR(=*>LRN z|8H-tcVGPxU;f~H{(9a5a4S&66*Ak`jta)!InJ8Gm#1u7Ig4q>$$PWj zGx`aqJv)2T^W>#KPvxWw9np>l4=kG=lCwEAy|r5-x$eW8kB|Sd>$Cg6v#o5G6WXmy)X**ZR`5=>oGhN0} z&(}NjZ?*Gff2mc=L5B+0%Ce8F&-Ic9(ZT6uHx9XdGa6Yvzqp<>-)AB)lZ$WK`-*$1r{@^eUvL#`J077c@Fv6c|Kq>M z>+jVYuIlkBFWxiDKf-+Dl5WErc?PdP8r9D}Cu#cNf@{x#I?WyHq89KP%<67c+p}7Q zfkoez=W*<`k`hn5-4o6?E2~QPO3d8-{N$V5U0320tt!5S+-W~^@AkFLCuXSKF7D`y z{v>ne$2a}5eQO@hc*>jao-6xe+t$aQ-ZnDZJou2}uI9*_u=Q)DPkhbd{cPXoE^eE^ zv9*AMcixF(U+%n&G@g8H(;ChtZ-ftj7fG2>ae#lzWF9$QkN#g0N1Izz_N{HPoinkl zwv&msVAX-}Onud7OE1n6)v(*J`%?SkgvGIi8VU@{oGlu2oB7TiePEny8T38Bf9Hb- z%SAVQNt*A`Q2OI()gPTXfB$o`TwIqZ{yt{!F*Td%Zh}wOtyy?9Wc7jxmU6#!%F~xs zMhAE>Hg#2`H;0sIT)ukqrYgU0bh4WFb>{}9P>*6uHq_c9afcO+% zUN!B;sP+e|+ddXV8-Cg0bcyxMo-K`%oe5LlboV`WDrGyPyRQA^3F&v$<*BnjF>Lnb zUiaXhQ}LVU36_>6nOxxN+9pq@*~$fc`mt*YmI6{TeOma`$GI)~UvwOG+L ze_lK}{k~q>O6|b4oy)FYSZ^>@%f=}6rSDs|hN+=Tb8buC&knl49hrQQ^H4_&zrXtG zLJ@X%spB@*>F>=wP2y^f9b0>M*UqVv-Z{MRKX?3PQRPap$Xm*~oUL~LFRPbotK8jY zdVB@9#)q`GmN^w7ljl8UxSD!?U+~9+r^Ub5|0(-_w0r-`=l$QRU;Vq>uC?#~pP!Fw zf8Be$!_(}(?yV&g^(LFlP~N+_X+fJH*VnxfOjfFE)Vp4C-x69GEb(H^MXqT|j!8jx zYgVl|XL9^YreP@SoB1pEWpdq6GyjGnw9n%?LoFPg$} zrtpYFcFLsBm*;#|$PX)Ic)D}Z&t2P;YWx~+_*^>lB}0Dg+TL~lr+&P&c&q5z4%V+b z7yZu2t>rrCeLbV~-HpmEf;%o;j6ddkv*+o}w9?BCceku~vuSPEjoUf=-}hH<`v1xQ zyxgk&`)>Tt`|#oB;^`M2o!)PIKm6mrdb_a2?BC_>?HJzF{#@?vzkhwqB|DZ)mH%0% z)O`7SIbHuWma+vmmWTE-O+V9W!C(|GoQ;WSo_4h;L^`oHqXRF z+vmJ}rhP{A-3ft1KG)9a>uPLx(8ciew8;mS*X|R}KF@Z4(C;X}&8RExK?zUqwdgVV3eLB0xe~$e3raS$M&u%}LTv(wHw@32b zgvSogKc70ey8SSt>iN&FqONI~8<>9F{Ju(Nw@%%+lKpOKtLARmDimz2Ute?VwJZ0r zixXEx7f2_rc#*5g$5?0b+T^Y8M!wFeJ#S4tE}H8;nZg(sS^TCpW95dcPv0%G@jY)f zPcca0UTLsRLf22R9TPrW<=pk_@gfj(u&KyrH^)Z$Cu(7M& z&+&t6%G~)2;*AAYiv^sI7Uq%v=y>J0#6c&)N|V3&k4}cjeO=YIGbUxa?A8x;VUPQB z7Fs>)mg!4b8??QzDv*c$IHOwok9S8m=f9r2Lv^pv*B1?iTU~Y zkwMxwY=*$?`I&MHBxfJnerJYHc;!)ngX>Ix|65XRtyEW9v`;bdy@?C^)UB^f`j^B8 zN^lBj`;^dUmuo)NDL%OUc7OT%nvLP7|JS^} zcJ}_8{q?;+-fwykZg$0lWAf|`TS{L3Rcg)GboHOt^>*{5O-HN*SF%q!XE{Sw*eSMy zh1uNXx%&JcftKz;LUA>VcKy8}-@j!36z7HRt!^^YGdmZFw1u*Ubq{7qp>hwsMT zQpI(xadmnktq+!5eJs=HV()RUaZS6)y-5Q9E0;T!pD~DiFQ%S2DQ}-)*7`h$%X&uH zj$5-Wc(?O<6~-TnJ-NHL#dKp}&2@wFT+3ar?Tt41Nh_{<7^wPSnZ{h(UrYKkC;J`X zPV8-3vfemx-d*o6weu2J>}>1_;1yN>UFP@K$4I!UH{#+yxifRO+&xh7^3tUlMUAA$Eh_I zd1cXSs*Hk`TKj}cb-lEPVNI7E?Ay!`Y}v_O0`#ZwfgvKWy*( zfA^2SKc4TwnjfeCbszkkt{t@9BoN zhqhib&v?tv)yj_fmlU1dA~^Tn`a*UY5xeP43;a&yEb6-Id1yuT+U(|2EBL*;`{qph zEkEOoZZMYz)9kO}a~+(`XPo}%T>3=k()&oSg*p;qx-(WJn%pi5y`s79f7GYunbY{J zdo-=yc3gV;wfx_$*Md@CmE4aU>Zn$@Jx8Z_iWqW7qjZLT^IPqboJB>jVTqJ`5S^R=qG+``06D3&3d+$yS#j5Y~1Y~=d<5mUD;pI zl$O0b?mpY>Gx7Otr#dpuu4Cw4<{0xkVKE0&y0OZw`j3xpcJHfls82PM(OQ1`-WD^5 zY38kMMr9E_Hw`$IQr2`!%y|Bbapi%=bz9cFZ`p0tv+wYZt=Vl`*BSI3mw(vy_;p5Q zweYO(zwO`u?-f~J{9~HbE`bMor)BQkvt-R(5$&v&mHYQ_wt8Lcm>HA&(>dr{93Q{( z!gHnfR+m1A=Hc3TnBQuHLGX^dGc0|@jhik!fBy95qvEc@HEzLsisqjAq_kG1El<=Y z&vL0zuY6owQXXU0AGTwrkqetdJdfOg;Ssu!#l3G8H; zF!x8{G(GOxkj}>aFaBshpZI^0;5@c9KkqcPUo+Yk_qomF?e_0^yUas++X7PTmrF@c z)4Lr1WzOV?TM7T$ujTDgy8ZQO!(3ng(gyyYaFBV;k6yBZ6PzaHFHA|%t)5t*>bh;w)KwpodO`aJIracO$}n62!6Y-6$E ztVzA+4qvyvki;I$IAzQ62CkIj({;FmM6&iQOyZYl-RL)YY3Jd2etw_%6y!d9pCs=t zy8Og?|KJJY)$3}TwXRt1nYVg-7R&#qSqm3rRxmBH{3Dy-5ns9}O{;m*Qmcx82R5o) zn6qf7l%i(z^UTX1Z+ER*_AJv)sX9!Oh;zWY@bZ zx9~+&Gk<7lkPm*bb@7k46{~)g1r|u!H`>ma(~)Sc_BC~LWDQSq#G|7#1v?igsO4D2 zK6}ok?djzb8+P>c)fgR_7r)OHO#jUCdfJA@dD7jR*M+Tn-LN{4(|+ND5}D_(mVEA1 zS*pAw>Gx)Tm%rWSW<{)=Tjqr_sl8e*&$`9^-1PYou4NMEL>gpz!x^gz{{7kFG+*`T zf+@F7rcBcFl6k{&Y>BYrNpH@*t%{iq3lCc5?){jOu|5FX8>?^C-)VWY|7QIku5a?29`t^b-|9SRQ-9azPE#@IcV#xa z8Fs~#-|1#}mNE0h#yPLrYLCz1i@c$5U4eIf_uGYPZ31Vk1bl^7PxMYxDywem;hnHt zVA{c*({^rgpR-n2l3npG^GDe$&Bt5+>YO=sewX|Lb#cAoNB0;Kw+Ua4+*-BQ+vvsZ z75>kkI=o%QZJepM<7LK5K`|aBMshvgMK@}H%uNF!LwieUtFrjY;M}hU!UX;*Ygzr$vEv4sPori_7aCZ?yr6?w_ovozWp(Q z8R;`tbjmHBsI)WqTY*aX)x%q6=onwxRSVC<96Q6GNgt4kN6s70?sYnx< zEnciQP4lNq_iMFf?_MX~xFeH#W1rE?kQ?8E)}^W_>BLp>zc?11{&{m@!_Ck}=F4I~ zvn&sC?9Y3b-}Sg_?S#0OFAgRwn#XfVZ<BZnCm*R?n>3-B_4bA2M<=#NId}S+%ZQNi#*@|zWuyY@bQ#` ziTNA%_bmD=6|QUkZQA8aEs1}G&3^PG@ftsR@pZ)!{zo%JqBN5a*KlRb6^M(tDbaaG z&oV&&aj%NavE9)nCeQUQPbrp>+*Y*Zz`A`Ze-8Uk6WOay-}`~C;3 zO(K{7wPZXGUlS*rsU^wyaEiMOU+pZW&{@koq`R|PO7y0mXH2yG7&J%i=u?J(OjD0# zmmS%5#~pS)z;;MtubXA(O3CN!S>4=Ux@s#$%62lim09#;JvnnMN9^{`Awp|H#@%~sF&x}tjG7lDvyV<0vwI_7Kewu~tP5clUa`mS z)2zdxTUFH^e!1~V@%K9f7d_e&@6DOO50gEL`=-g0uZh!o_P%(d$@$$z9oU z`>=G^x~aPq&uBMR&z^O8-K4_vKkfz`WW2xl)AK8B(!8w-{Vy-P|M9Z?=cHUoV*PH=8(DbVauUgNo2`KE=r zf991-8<+o$x*t>#!}sL&w?)Syi{HL@%cx~^RCR@h{yo(+$0Mz$9S7T7!rU2^~5*_lGpeH?Qg{(N6%G(o!hNY=7w>*pUnwcgv#=&#+@Vq0b= zIOqMBS4aOH}NIiZ;2!@}x@Pj3}XGuH$TcQ{2ut z#B6`)F21qp?t-8LYc8jsnms8+z4(y(gR`nPoh1MN`MUO3?3+5VRhM3E4F3FLdEwTp z1qqFtUT9Xbiz&p4e4BR5VM3JllWSFd*~glu-*!15RI{SaNA)icL-L%Sz&DyW%pNuU|`c@-4>PCO6@IAEi^%b9g%Y z&c;M7T+XYgE2O%O|7woeuFe<-MitAL`L=7WaIj>p@pw0(;Es;|RgV7({EqT^AGhVr zlnd60SE^c}mnX68g3CusqyDLRf-^RYsz%%{Gz~QOIVgRicCYVTw$kpZD2qE4v!<*z z)}C;5MwdSg|6Ejy6p>ftJD~o}tE0+E=&jNM_PFX2wgUSD-iva% zFL?Wi+z-CPe0%1sa%PJ&9|iPwPFU9+*?-mW*Sv*ilh3dGW$9I~@UZ8_TZVgl70b45 z>D`*(&{n14`ZTAbqD0SKH>ITB%6GZ)*ZZC-<^R(oHd-E^Yxb4N%KPcurnK5K zUY|eB_z>UW=qxGruFW*J+-_sskJ@#&`xB=usd*musCr*Ev@X`f;6->^s6}gE#+GNWSdf;*CkwY?DUpTTbpR$bU>=)R0kYmd4{_BVB zm!0`|xs+A#s;i|#SgV7qTHNcZznWZQsySr`0QFFP!U+T`ja9i=@ zaKlsY-IL}VYl}Mcp;N?`b$?f-Ta47b=NDzzX86iFvDGr|WAJu4Vqo)5>fh4MMQ|@oQXS zJXNamXTa|Rch6kk_w#+`pZlKrTsb`XCck()w$`*nJAawceCy86w@X5%wOl;+B7Xt* zOA+@Y@AERGudAxXOm%b5dm?l6ZQq9bO{H1Wtk=me+#ebDXZP)Tm7`yN?De%bd+D|B0?e|wEZFTs!yXyN-gPG|s zeQIaxr2pKx@5mgr&-q>!tk0en%$s(#`n>wdqDjfT3;YVSil%PQ)l&U-n3xdEdAt2&quMxX5HRp`h6?Mt6!nI_hf~BF1Oix z%||deEx50ZNmVgtjl=@Qyu+&M>5C&)gva~Gzb^YQbFG(%+|lF9&&R#%zY%eTGaiWFoY{-Kpi(QVChknvy=Tp(XIICS(z?U`0-$$fQV{@dN zxq3^J`stdj1sDACX4qU&-uH*0TR^BU!Q=SN)~=kjjJD6WeUV!s!Exe@ALA0sp2%H4 zC)cQYB%9ySpZfHG@Zl9wt9x5?*aNh-u^Z2sn%*6hE4RqAea?c%^|P}Mtep2S>owb? zlPO2dB!yP#&s-!uaW1F3nDS{=VXpQ1%x-0ki%e|lKfXEndHUgV$|hd|-0!{MQ1shW zK4ZGn<`k4REVAfla*2a-SB!1Zn*|;ZSNZy`aV~nT{$(m><*au*1Wh+2 zzfa}8AHaH-?fL_B*^ z(!_Ff>Ek@NIXTOGl^UI1e%s~e5Nr}>Qo{N;b60KY-UZ8yHXORUd6#Eh^ULQfS9MNB zbzMpB{7}H*``7(RMnR5A)l8VJWTDH&bRz_<=n5yE^K$h(yd<|^SParkha)9 z$0_sI)RosAo`243ewwt%f95=UZ)4Z}ZLhpD?|x!oS^not;(oS8XJig^c1d$B{O|B( zHiy{9@X$X}FOHX(Zp^#zONu{YZ?i~PMi>MC!QR;=>fhG&-&(Nty5*%Hj(v|-aO_Cc z?2*5<{NujQ5;hO#Xg78ja@DMSy*06CYfQmGwftEX$N2^1q{5e%t%{ABp5nOl+Koj% zuD2FmZZpnyxF)2#apR(5{aY1G*ESldFXo@Ov2pJaH-^Y3Ht|6^ZfaM~uW(p3@2u!& zpLcAkvrWEidhUDV_QC@FMMqDil-wSqN%hq#OxDhhrF+$=hfG&$ed zSV4M?C~H~pW2q2jvmdwRQkPs1d^qROmS-9B*8UQUxLTI*ow2mZ=wkA$`kz}jt?`yE zJ@fGSm)QF}?-V2oYL!zZR(a`fxyXL-(Bt+k+`7hb=_i@id$%-Qp1Y#lXuI6;k2NzF zooAkZKeTTCji98>MPJ?<9F*B$uX(?4bK?QSyQZZ--W@cFR$u-&wJvUn+&RIdTJQ6- zFL>E3kV|T~@UZ#~=Wd&WTQ~aTB-HA}zg`#U8?w0QnC60gMtt>a9yW`G9-rdG+xK5J z+hFdVZ$|nxc@Nm?Bds6rTD~}m<&=EjMLjw06We-T8r=&OX4$qT!q>_`^l;*2XNP9gc~g=1Nai+zP3Jbbiw?p%AmvU2v_<%ce(zVG2Gnc%t7E{p4R zfOvOa1dGDHJ)2INUAq}7R`I$@Dpkt)&gB;Z!naP?CaqOIW%AzHv!iC(ysHmZzW%Ot zQ|u8}MpMXkuakB*clTPBXym_L_hfmf7o+US(%Zu8*y2narS&%#ymgy%#VM@YPQhp|ixg-mo~dDEeN_>WlTg$=LATsB^3TMXQ7F!$VvP zw$xVkYg~_$|9dDcGiZvl?kBjg+mzQ2X;W^Lu@sr63 zO4rh7u%40Gv7%zJk!<0Wn;H3&ocC|j)KH!LtNr%6CD$E&*<5!#kv_#&?p||7CguPC zhta=`uPY_zzKgE^z5RkuKCjIQ>GNhUBFqIZys|cDTlB>+N__FOBMO?D*|kNy+H)>n zFA3hU;#dzCpNM;)eEN%XZ93Lp@A+}@e9JNs&Y8Dn-|qSkH}(rB$QrZS>|OM2_4cJf zrX~TaSH6fkzCdgCqfBdA+2`FR3vR0XYO*-;wV)}ovocKAXzzKKdQQ_HkJG=)^UbsU zZu&4hIOg|(SJv0N!Y{aQzms1nCbD;R^XH}-r#WSNo2Dunym?(w&=7cg#-Yzo7gg}> zpI@{+((u+g>C*K@&94HzGd!NZ*lRQ^NOwl!7xPKWzc#y_m8n~y!7#&)wP?e}(4v68 zl`p3YyolorKef^0ufhD~&fC%_bn|d+TJmvgL5)<6Pub#hg->;S)rS)cmH)k3ur=aa z;jPz8TMNH#;OYzz73*AoTx!biU-uY|-zD79u;jleWuW@{z3QX|Cuem}J5l^RWB#tW zU)EdPJ)rY7HE0gQ{prhsE!yu@?-OA*-*H8R_lNTNxxenDt+cHBd3AZ7`d@9o^6sT| z^M7*Pc{AlNyL|4oUAMn=_8S(J#t9XDzgK+9t|{22t}dvxAxK`9ZT7=mjO{n(CB|(0 z-qcf`DQ$UQE91i2yC1K)?fhp|e%LT{-B+de)fF*u6K|c^wv+!(L64)EJ(mq{zj?q0 zvn>BGj+p)&i%VRG-gIgBY@2^KkH-lKF06ggef3Atjh)waF7sH+|9^gL*InLyPBZ_e%$&pd z>Ulo5^lsJ^3!d4LQ%#xPt~gXQugiQ}k>kk)zg}6)6wPE`rde7jl%K<$@3Di+ z+#&S$DUr=`TsCLb`m*@%doO9KUcS20 zRrKjLGtrEyfF%*SzS?u7yH^KhzM2&0WqjDEe)7{RW?@gh|7p|mUeDGw^&uBW?^`{Q z|9p1*69Wy}PSsYKN!eCxtpESi{^#d^@$xp)`tA2seEah8epQCV-}8^_FLCs>vxG5~ zl(LxovRLflD3S7*H>%-sdGL|?HCI>~z8+X(t*f#B!HK;u_?_<-g-Mk;RtG=pHlMSs zYE>}1Pn*?Nm81O?&CiZ!cIFy>Ki*)rc2&$1MJ)Embw86S1~v}3p|kC@Iv|(+ukjy zS|?Qv1-`SaH&9X#d;FUznyk2;-@o*1x9|3i zypg$HXYD=b51!foyQah}NthlqF?QO!i;Kg}H)y{rnJFe*v9Z1}TJCDg_kBSxTh~1; z<2BZ}bk(HZ_~?%<-jo%~Hd3;WJqSiN^{TyEhC z5zC1g4=NU9zQ{^QTUPyM^+lW6raq@ilG4A(fAMKo+Pge1QRai)o@>%q7yEdzYMwV| zy!5y%Gu=NuBYv-8qHp}(rsp1iyZ4!0Zfd{Yeci?DfoR}*#f$lx4#HFPuk1;gr;`!( zj{8ZF7ms($`EtA%o~GO_U(R;>Uzpa~R5|O@ z`V}tD* z>ryYA@04=q@pF&W-@b&ot#SLu=GplsbdA8ro&RRdPspuks_#gzc&oTal__GHUVY)w zXFHoX7n^bxUN@0esj|6J?|Stu6T6DznWftep4h7%)tq0s@_v2fB{=ZHCA3eCZdHDu;o!KrvJ&PAqHD6cb zn`9CHTYtW7{ht5R{~piZSNrA5!^O+*f9H`7jOJr5U7opXqT&YmyfCq~76m_aL&aq3 zZf()w{uTdfzD-)p)ekbM`lbJ_8WfzW@A#Ll%9ZBe@#ovZ*mDyio-#{Io7~>oRav3W zV&mGE?5c9~4BrvI9b4k>@j4&zHouS^$Ie# ztKPxhA==eKi0y{apOEf|j3d%#UA!&bZMe4UZST@(=Go|?bH26usmbaeN{24H>ZGWy zy0iTI2GPqNp)ow0zdk$B9gx8>HDw=9*Y~L##i#JEwKZ7%^vdgvPk8;?B0sAAjFOG` z>@3M9^WiqKn+xp@n;3q( zdHHJOt}|+kD;{pR*5+Ut;CO|o*K+*13lYleGiDt8wJ#Wt~g5;4(m=lVK@?cv(Q ziOsn?5)CB`;E^qYg0HQr?TC@GG)w2n+$@yBHl>49_}#Nk|G+(I{V=|6RD4@8TTAIz0l`4`;%nD zRUNxcCT%#9daxrT_DR?l9m7X#xdDrPxz^5%HO=AmyRdZbU6$wHO3zm{_AERTZEMH9 z&wwFT;Mn|Ig4Z0MZV%Cg%B7Du+ujVw(c>LF7o1OCo(LVQWtg`Z*r&L+k zJbcVnonrmjt;%#jFDoR5PnbC?v~kr)^f1lLF=XSRBvKmr% z>Qetr`yr|27{5irE51$BBXD|r^)G|z8W~&+PwoF(cW?c_@Mu()!(*-OZJ*K?oO)QW zc-8UHs>As=`u3z|-_Cq_^Vg1RJy|;{+Z}}W=iS-Op~1CoV#1l3>+j}D-#gP=J^%Q% zCgv)sb@x;pIzuKJfLhv_=TkPCk z71Tu>+k1G0^ubGhX{$4}SijtPIepH#t;zfAJa)gDn$NSd(Bp!6x6D*g>p!iP)^)mX zVqGuJ6ff-8t~54MV4L$m?R{Xjtgz#XuKimq?p)Shv+%1`$ZzAdCZSoESX|z(Irwkl zN$z(+>3{6}ULCAkT6X1q{d?Z@4Zo$HCj_*f;{CE=PGv}k0!QnV^Z85G`CnPRB;@+? zC39+6l~&G8i>)l#`eXjl3ZugU4oCIp{4Y&^|7>m4zw5WR@Bi`k-~an6|I)Mf_&2L& zy!@l0t#-<#SIgqZqwV~1;g9NH&6s(ZU*2T$rYyfpNxm<9j9={%G~ajdH_zwmW%KCG{7!pOek z@>`yJOK$Q0kcx0Cr8ZEQmdinDC3$ZEc5+zM*f3W1JEt*>@uk>Ef zsOA3o6ACGsA5|B29nyO7zIxWJU{YP^>Bl!cCkJ>U8pEP;kqIzc6 z>y2j)JN=dQpVPeDA@zRb$*m14$(67DS2@29eSPH9ifs%t{I{2cF?cKP_}_G%b6Nl7 zt2ITt7&eGki2Ep>Up7Ufvgcn*z{1s!vWtJc%ze_az`A>1Yy268+hT53tGsp6I#xeD zVs$+x#S#yQQqTX3#&_rdyZle(in z?wf6pIL2Qmua|K4XZ`PI;_)G$|KHj9HTvK8_}_ohO(IlIE5#mW2?=OjtbAIzwLfT! zg5)yiplLD7mhydP?^pk6vX+hGzv1k&o1Xa8T01YjI{mVY^O2s1ibi*jx<&S>s+3i~ zi_h)sPT_mJGW1y@&w2KOCCSMQ(r3=rUcHv3$S&Ks&bQ$UT(>wZQGWe{FECUeEH3qO97FZ zg)1rxV5(Rj_)`q7kIXY=r$eJxEJzwLer((4K*Sm}H z^WXGevD{F7w@LEg-{m5Y*%`i;zGg{`Up_-F>(wzGpXW=wxlY+CwVEu+dB4R)Dq>fK|0dd8~#SG|&bO6trb7&0$D-Q^Os z`|Os|*xK1ujWIKrk|yu&n-d-4vuVq6?sXAWj1qlE`X@;kaN3;BFlcpI%;&b0|Kw_Q z%Qq4s**jn6TIO%>+Hay+)0;TsG1r{gkzyK&$L2{qS+k$*D5s9&JEnt^Q;ytrKde=L z?OdPXGKH{Rj`xJNJ-&BK_tm@STn&{Q&bpXPXujE=E<0_85>N2mh0kWpvkpA0R2m_7 zj(>WfKbPc-TBnmQm*t*)JYlMzs@tdjw~p=>pRElxJ~droB|7u6qYd{ohk|>z!Y;cw zI_)@jn#D|ip~7taLWhq0@B5D%7yp0h%=b5C_Kzy&D=m5@4i_G{JU6(SnljPk-zT|? zn(4btGdGkq{89V9cKZJdk?)kB)Zewl~J{Qp~lKD z^Wee@C$H8(+H^2Cmnz&_88SJR@#l+u?_=<#-E%3oR$OcAv5N_&`$PdFt|j^~>MQ z>aaY{e7s3~$LoD6+al$!yWo^z zt3S+-3Xz<(9kOE!-F0`OsS{thX2~ z`RLUuG_BChpnu7g;?j#^lU1Tt+~0|dxzAQpw4_aM%WUoBx!X9+r^I^ithgrO-KIT# z5qgjM?|kr`s>Jjf4H#w+u#RjR6`d=>$%UOQs zo2|a;W|ehl8IzO#39a*PlP@(cX?w%gqo|{r&38>D{(CCdmYF*9I$CC&u#!tSR%z!w z`RBBR#@Z?Tdr}rR*@>x53Hy5R@x|Wf`f|3lmK7gg{I=gKW3%)Bqu=iS`7a!H%~?1l zxUzK1g%;V8vr9~0zji$yB(t>kb*IHG%UNvkZz9gdn5(Hqn6aOlny3&UP@nG5$z~PJ zd~&8}t%RRTUWdz{WPODtevGCOrwdXhy>3@7Z(Vp%pz(Rzy>g42cO-jzQsc%EN3 zS#)s1|JiTC4>488T)MdAywAxPl^I!Y3fCDdQu=KfT5X+iK=^LOq?nZS)yB2Ar^{>m zef8EBlIybO+Y?};xT?tY0>kpAho4lq+>hVeXVtzS+@&=9>Bk5B1shVuZQpwz-x>V$ zR&mfvtErNVd3%;zaS>VOFLm|Bf`z@#pC7EvWoW+aa;$ilmGxqtv>Az$iV8d*&GWkD zdC<>7X5yOmb$3syG+gb!c>1Zv@Um6RmAiTVU^fc`*PZULM#U{2 z@0XWeW;X9DcK<{9U#z`(Rj!=A7Q2{D`GTQco8Ha~ z0k*#9c{jSg3SS};XniocE+v1V690jtMknLLXI$L2aCVw};HcMJ{WLa*=X76}=4joUd;5@#QVu3ai%E|x(1Dlrc8LP znR6=3+i9-FbRU&(oj+$6uYDrIaG)|}^RIJ?j8`Q#hB~mSJ@5@wJ0Q+uzubEY-&RFw z0}Zt<+qZK*mzX);Z92C?>aOTHolDn(-e|m8adfA#sws0-XN8`zmQ0(>^`1??IVc>w>vTZkup+$F1v9Q(^9tNEQms zZ$D8T(7yco-7B3U$8A-@{I!=loqWHeA;m0IMB4LbPTBFD8Op~Dm(4oRpL|0vlTo5@ z(dV`Y4-QLTOna&K@bNQ7PwaG=BCtLq$E+~2*W@#}| z|4zYtwcmNJX19JE@3McA{GdE2=klc&xm}UI2`&eE^p@}SO0u^pwwz$YV8554tIEdP zZ%V0f>LQB^0aJQaI4IVzPxK`dpz=BdoxSn0td-_p-K?^tcnBF+hQ zZd|$7g!wN^el7T(XR}X7R$DP>*9_4kNi|Upj?a7MJymD!dL6o9>Gb-h<;9aeyYRTQ zIZoQh7PUy&RZFLUOGxvmna>H;(;6rJ6Y|8qwB4PWxY;-MkJ;?AQT`!vrVH*r5%K(V zYtb#Q!=53UGg%5gGcmorvgkkauh*NECkcG9TXgT%&6|O{_nuhzTO{zz4JOC;k{zbJ_Ts+Yy6Tl9nL%@= zrD#+ zD5UK;wW30~*!8;0c9U0D*A5<>!5}5uhF~Zz1sW_6Q{fkR(yB*hyO}D`vME2Qzv(=4&KZc8sC2+ zFy_U=?_c9H{DTEs!nWI;)?+`q$i!Pry}UWYW5(khSA+EQZ_QZKutfE{X503f@Coag zwngk)nBeLeIZ^D+%xj@5=W=ncvprkqr+P=!W65j1rDo3)=e}BXXNTSfhtmgT`tBRe z-m^EvFutfXOKN9M-K^fs%}HWhdm40a)}7Z7*z$Mdizz)%zI%pF*`2PVdwc7`Ym@rl z#2^2ebMbPm**7WKMX3kXOXsXzIs5V5#&o}zvRlu(ED65;*!1Eo-`01lyY83@MXBFq zFsWC6sm#aV&|~n%!s6YW*EV^t#BY1?{`#0(c2#}0*{{y#(ii_;JPc%J68yY&eFNvr zs;jwoENslzd7fTo-*tO^g8hwavD;0n_ifr&x%|hpEwdl3wCzdv3=EqwH^-|`@I@VW zy!K9c*J!p)wvOGVhu8a_&6IMeJ1u&|E;``3@x=B=i)Jmf@wi@;{OnkZ(W+AqW7Tg4 z`EyB>t)AsO^Ww$lj9=avwQut7+Ox-hc1j!9dzX_BBASm+{;mIS&;Lc|4J}TXHqUR^ zQZ=iRgLmu46RA_2>~6T0?N&_{n(Mo9!{R2Jwzdi03!OCtTI%*pOMSa$uQ}KK;Hwf% z4Bfx$a@#v+rgd4z>CH4d<6ID0^Sk$r^rbZU0=o|fT$Q-zR|ckN>@L_R@_4%9HpjW= z<{R~#`MAAisoIPXk%qb_^Q#SvE36hgnCL3rzu=spTl(oqHx~pIopWtCoi>|e%i#r2 z?na2aANaOl+HJRD?HvLl3IMYKWNpB3;V7(X{#<%J?NNh z9<^#ocZz5DhHIY=cq|SOjgAo2=9^GDXYQJ5NrAx%U#-twl;2?RY!}zrg0GhzxK}Er z@3%>`d!_yB)ZIhsEB}{&&-hXOBj9KCgRl3O?n_sDFo*wC>b(*c!|ns890Hd;+IM)T zmQn8I7S@8U#2f5FCY}tNBG~&{Kd1PyE$6s7sYiZ-gJIb;H9sa(rU(A|rxt$sp1f*H zqE@n?<1}BV6CMW*yS_d9@zl0_)`zo_KQAm`;Cy+B&+|?Civ4~DXPSH%-0QbFY4Yb@ z7tl6%R_$l@WXiS=B{R=oT;Lrxebez>=O?~)3%+l$>%C3imB?9Vy6w!Ew|rsg^Y@eU zGBdEcCtIVQdn7>TjHue3+)MgP-nF=1KG5l%5Uzh#XT@=r$6kV8=33=65kiEf(v)84)ZEjj5_DW((ur?Pjt5tLTBfdXu4~TarllEjV#c9TUw-g~ zU;C>w+pn>qllSx;iODza&hRz9vG`1rL6+aA&4#U$n`$H3j{K-Q{^8ox&ujI4zQqKE zKek=0I-_Q{kF&chQ`L77sip5$pNLNFxBj2mx{4tvZ)tFUzzpAnb`_IOrBnTvKiR0h zE=?~@Xh|zCQnHLWA6$~OzdHPr8~2*vs@YR+UFTfTSaEH;_LBtt(k9;pssh2zI*x+J zBQp=JY0;~nm$HK=<$P7&s_mY$3Rm0kgr_7Pv^WKdPT+8 zMq&F?hS%3W$L>|@&)7V}c>=>jt*#eNiKdooCEQO{1%5xR>a((7+4;*#Z%%hzm^Q_l zg`Z35+zfN0_wyuQ7&dWkmrbZu*_JODiei@%k8FpFTXvwIa&SuJU%&ls|vdx z4-@{oE^+0`y}Rc3GLbc#KJtfg2W^^sa!2Uvg%iI@uDR8+ZS}o|1C>5MpQxqt3psC- zSavmg#)^WA&Bx_y*UYnxyO=dWe8cPuZI${rc?9Mic(KG|p~fFRH`Q62>t_8~u_1r! zy(+ysTgoghwqCqsr`aWA;rhnI=*s%nS_=Y$q;I}z^?JH_<&-&3w4Z2Ou8RNSurIT` zQ@G@dc8O1cbzX=V!3F}8g<13;TS1Thg<>nLChyHQuR4FFsebx0rJ!|;3zvsK zkYC1dw`KApjlBn|A2n^Rl(1iY?4p&44`iJa(Z_lvXn9ILe^~>&4gHwKE;nEEiYgW$jk}}ZZ%#L}4Mv-KKr_U z`ux~^?{%pu(~iZp0TspHbPD8o_QmM#+w?)y+ne)!x_9#I&##W?oeHQvpm%NxnY>HL^Ib*~H&4?_acPrheNy z^Y{7>;%|A$MSWjtqONw=&auMigGZCD)k*Q`%r5pzR<50rZnZAAO0DdJlM2_l(@rh^ z+r?y23#?ZjapBC`GppH|bNz-3hK_d@ z1T1M#eyQj2qaogNlVs8C!{;78tY`HK@M25*|D$|?PryU(yPHpa;+*y3b49>EBQE>5 zsdF1V)czRn&f3nibeZ0gw+-D-*(MNGohNLJ1(%+!dAZ5w7{jdMo;GE5f#rJc&6?cuuN^gG9FJD? zJo7vg-Qp7-Vyb<4SMj-n8fw;mQqTUl@vX|Cl6~5Hp_t1zQ~fXfUAz9c-!@yr53Axh zcKcO+<=*(jLiKxTtj`a7>D^~G2Crt*Dqd84^H{{qDSG}vm(#X#W$k?)Y&dsi+0kY5 z^6r>q{+5;G@|rEFY?d|OE4kZMN_-jLDYl1a`)3v^i!wy*naM6Ymg>o>5 z*enQZDe*~^pOaYfswd{dhJ|+%oI~fWzHY?6fB$#cS`MY~+0Ccp%zEx`-Ly7(k4H^c zW4mY=*F@a199nJY`K9Pve+YzudyLl&605`C-nQ0aVsUGk zb@-rl3+w$mY-exU&F$UOv_8k_m}@xqq_0aYbI;dqShReDs)dKfMw6fx-xV5%j0%?P zOTRg>C$OvF=ZRTzub&saR(tSgOZ&6rqQti`uM1x$9{+g8yzF|LnN7ddx@G76bK5xf@>)srhZ&vB+4`c? zFaEJy@@UOPti~zdzQQ>&relg)w7_*;lXDDWPWTmYOzNFqA4^ z{?I!i-9IGvfx2KA+lHm8|F$M)<@zpIQnvmr$A^`DZ+<`5zV}6_`p8B@VQaCn=hxoP zxe<|+H|N>o*7uX=pPjkT?R`q(+%5Y{V_$K|O<(ffd-1GKO-<_e4BQBVUWp-1^TDgS_j8;-8eD*g_!xLkM>Xa4!UxA zxxbS=rT_i^uc8lsj&6SbTR-k!?KdkmO}|!gizUX7>2Afbe%`-7Qr{fhJ(Jzhdwqys$prr5Gf#SE z8^4iSI%%@X?E6bUEKUhgiDbPH)FmabJLzeag!Y=7(`PeD{I8ib>p|&#yNWeuww}MB z5>XI#B2S5*Nm|N*p}gSxyQwvM55>tf+D=@w%3Ai1&#O4av{{ow>s5s>*j-rH#P>7U z^7Nid8KKb{A3d(COmMnA$?K@?x)_#!<}7w`OyJhhJBiQeU!IEr!Co7-@fzx0~NO@`5@M+SK<8X zFTzq}t!yOZ_|12)eLR?Mc(Xibht-`|j-7jE^YAYG^+$VEmN<)AZp#A?QQbvpZ};(j zT4TBG!@iO!XY$Tloo*_56XTzIIdg}1c?jS8RqC%TN}r3A?$f)x$Yl458xcEZ8JtXZ z`geQogl)b-xnYumS=VIUbwB&$l_YH1713%S-Jw-?%p^kNOUIk!t2R*w^4G^6*KTus zFe7^g^WkNTYu4~w?YB~lmGZs#U`avF548)z?-k^JsL!u?v_#>PjMnLAeKFe#cKfx+ zuX9pmxDm1aWcVQt#+0PJ?>@Zy$of zbj@Sp3+>Ad0mnb_JvR{z7g9AVTCpH`d7GDP(5?WvtDi5|v}Lw!5u9k{dtrgt44Fx> zmoxV}&-~pXGV$rN%%}yNW|~Z=Pi9)lmRZ?9+FD|o7qIa6Gdsh&K9#h!TUiv|^-Pxh zwB+)$7Y;?rRkQr=-TD&5*S9->J3jZ~T}kJy&#u3T?_IfjL-#Usge2YPY`mlif|u){$z-x663vHVLPv9#ybz`>Z&3S#Z8rwC8udL%(Zx z`(`B@Z_`SDJo8`@bKCY+nKx5>r9LR;c(3A~mv|zAXUmta=qr`%g-g~iR=XM{JLy== zYuybsZvQTvp1qO(V8kPj+0M+yM^AG-^P&_+)0Z81!lJ@cMb z#aQhwx$^9NmZXq>!*L#M8=0&%{%n>zSNNpf*{Ut)8K!Yc?|R$HW!th`>yO``btGWB zz4VDG&J7w{FS-V+3p{2y5nndP*CSJ5_6<+-dut?aMD5t8(ketY;_oy;W?S{rK?AeatP(i>i+P2zYa9vG~e` znlogY-dSn?mRi{zQaEWh`woS|g-u1rR(D0cz3_UsO!Zrv$!EU2Fvxzj@uZ@G_7iJw z=ZEFXWo*|5cYQhHUVnqXi*x2VuOs^`nNOu88NCh7yRXN-q)6jd1xN2Cu{u+wQDOWA(W|bHLqvLmTX)7ydzb27SL5@np>66ipSpK^JN3h6$?a$`dcAbj zTL0slpIta=77`tz_wtnK^F#v{tEV3)cJH0{>sLUl-aM15p%bh3svH#FDrdBy{KXb` z?Tc^OBwT9Ge-m!=ThUi2cWR60=4H+MlF#y;tZzB$8?{@_>_B;kU|iZ-8zrugl|GqG z1{XAU)p+_Xm}R%{r-GWq!ky=hHYaX;T*;*V+j2L@2Bvc6*p@eS=wzEAW zD&o5RRda^g*PfPs7Zvy(=S_J1?1skcDJNq?7g+v_E;%G(>Hl}jsnc6tcuo<_Vfc5( zh|Bt6>p$+S?rm|0e;uv(o3QGm&BpAP{ykY0f?v*k$Pc~yW%m>5z7OjhOl@rI59ezg zxnd%z8&|(%q2;qLrfL60Yn)%7c>l}m_zb4TiaLk1{Q)!jyt%X=|Bm6Vj(xKF>5^#$ zsalPZZLcmCwqH2fBJ+Xu-;aX{SChGAQ}S-ym@y?VZ%Vt{$G980GrBeguC%lWUF5mZ zcgufOnOHwPmGi4PRZ24NGfnO{QP`{dQccQ)BUD*;dVzAV`?-dc%?mRxPAi=BM|f4z zdlR{?~ffZ3Hx)Z}`O6R#MiTe4?v3R#z^z!9o~MEw@%! zZdr9Y>Ih%Fplrwc4A-inSkH$cb#?y_&VOIOKYn_7(l^0L9lN@}PV$H-KX?5W_i9BS z?=767-F1^%#rE<>KeWzEyCjyFxcvI9sGQA{emQr{`@DT(*NVo~J0vrwv)_|aGrpT} zTRQ0YF~`}9avpFehE~mJObrV9U=euPXv$tL-|_=G%Ye zi|hWWY%k>H>^MLDq|^NyndPgc^$W`%OHXF8h@7Ojfb(b<%M?9vp-ue-mzcfpeK=-v zVs?68>9ghSij@q?GeurTO|roIilnGYUaN?o-0_vMv+OLeawDB@P) zTwwis!-45(3?5m_Rv+cj7k}E-<8N&E>%jx@Th23%F~*-`d%j$9O8kVs8@?`D`(Trw zjmXttook6te`ikkSaO+l4PQ#&#+RS0mgeMSXDR(`R8Ft8pLB3~zR2m~FD|i*L^t(5 z@V=wYl3=IPDv^H{1Tb~d(j-VdGGeQy<$gpVHHvOPg$ z=9EvI>c*U&wPtThu032T+Q_!M!^Hn`afoDclV#5f_RE&cFQ;ueahazg_wka5%qu3- zrxeUMcUR=%0fU5jGdAzh5H((Ilh0+m=E9E)UN6)vD+Qiv3mkYN>g{pKW<#)i+(Qt(y1o!IaBeHr<`Yn6o_d(Es$}7~ehKMQ>9kaaUzs3SM`c z<4l>D^;DU6b)PEDN{{eO|H+x1T{WA{dreZD^U)n4MvLQ0bL_(P&OXTa;&kDMZqbpF z$(|7su6uKZ)Wgmld+>D6ft?nGqQ{x6AKl+~MfhOh*ALcp(^@mP6|P(1{w(9@ba83j z1)WJO%|@pJYCk=ACb#nSWslIr?!2FsH%pG0ZPgFndwlaG)!>VEvmbdpE!!~r7L%}O z?dvM}8D>?z`|iARc>P#qj$`xZQwm?78FYxvOZxIyX#Le??;K(#a`C3`Ut`kCU-CKc zveg=~G)-iEXt?2{`tq&Dv;HI$TsYC7QpT6GVLAVm zMLvvd^sMb8gDO-Y+u$JOjFYWYg=acM)X zKhLeRlgn>$-?pa{=z%LPI@Ng$FKkHt51GD^Wm4JaR+MeWGAnU512aJtS5KF z6uHRBu?u)7yk_+O=BE5+l_cMv(ieI5oO>nL8?oybyf?f2L)Go3ft!8I$FPoH-3mu` z{e5y=$F1?+30=m$s~4|yIn=k^aAr!v1x@kA&u_ido4Yh!W^K%i?Rhmzn8M5w zxNyfu`B(jqop!DtzbKy#ew=dKWVQ84-qJvpyv$fTrx&}o#jFZ;*?D~TrW-e#mh|;) zwK}swU#4n)Zu#Uq{jJl^8ZFjZ?YFjS+dEH*zkjD%>F_^apZ|wF%{}tls>Bo-wwNca zFWygd>t>wE6tp+)==*-vD`vB;4;@LHyC~)#XMS3RzER`qfNy-NXD*686%peSz3_h1 z%CsjhiY{88np0-LDxGSzXtD0ZI}TQgynp!h`@@a>au`jGCz*v8pE)wsZ{^ayd5k8$ zomMwCg(%Nk;ZeAYwXUYyGj=c zI_l4{S2tbc^YQwwKi}dsQl#!N?$YY~dQH)4_tDQKkpU6ME`|RMcWMb!?3m`dTqIl5 zb~*o>3#~`boDyDUSN*5p!*X|aeb1|ZOa8n6TExm0{&D76(R+Lw);vhzEKXV!srfME z_|2mtub9s*TzAkVW|h103s)QObH^^T=og<()sPU&6fubAGVv_l5whI(ghJ%Tr$Q^j zGG&DfT`zEJUYsS!AMx4FVflqEOfm9_TC87-Ozz&<#kk_`XJ+TH*S`&lyH|5IxAY&6 z7Cc=xeahL1GV+sFdKsVE;i~=j?&9OW{ogzDHare=uE+^_R%WqCX!-NU373M6C-`Hde)f9uEDR43Z-E_L_(er)n3v(qnK!^C#AbT*cR8dz)T zukuw`G<$FBqo#`V=P#wbcgnIWZIlQxx*etyw9<8t7}Fcw9ebk!oo?^){G#TaQQ#}$ zbH+7ke$B@J%yZ^^wLRS3ezc+Z&6at}b|;#|B);Bw-+Ozez^TJZ6}O)sK6?B4y^NEd zqVE@M3JMA|G+h3`q{48k%Hy;gSNUi6TzHu{%}Pu3-Iz_&m)oDYu{?U-vZa2e+LG(O zNN#dUpLs6ubKsS~TQ%BTy%yirwUC~!HtlfYliR=MgdN{%n5PN^EIw?*qNB zGcWb@yACY# zEnKl8?Z=no#kI$S7X>Zddh5!nP6ol#pHstjsl>k*Ec0G}cg{rtO}*(?9!K-#>+iaq zZKS;a+!uAJdA9;9++S-JRj*1^wF&;VW7pdC!Yh-evt`|q-mA)Pk}#S3h~)hx8BKaJ zQ5Ev`8hYIgOky*9O(sp1RCu2uzt=n6G`Ut^D{F71sixDihHqgn*Gb)x&{)@e;MjVL zm!0+D&u<85ZI1YP>E=b}()*{qJGD8|i=90(bJFW)-Hgzg{?lvk+~hNXcQ`)qCeQLM zmYDkZLO#QmZlQxrXZ;+4vN)* zeAS_g#wEF&pR_`X6$I%=T)py$imJ$`|@N#fU2K(%xNRuhUF$GCGvL|} zEAKurPrb#N`NvyId-d5H3X1ov5?$pGJgI2b!;2HSA1qv+Fj;0@&y<@d=girZ7@uVM z!z9*=_x!sF77R&|^AqIy3T|j{x^9VG<~w_OZ&1#*W$|mo<0toTjBC8Seea(Cx~lo! z>Bn#F2#&Wg@8b%7*t=S}S+oD)_uJpHCcj;EaLI>$J`0z12VY!HUc^^e6f(mkS~>56 zmqz5n*J2DWwk%t_^Vyv}I)aZ_-!V^m5E1Vw#O`XeHl^ruz|oUB;(HI7uV0+2>n$w1 z%=uEUXwi$fol~D2F%uNC+N!uz#kyHadYP`$Y_FA9E$Wu16kRenP-@8GBv`#VU+ZAt zp@~P!s&xY&%o2VwW6ewnkF_E0A2p`_*yOj@FFIn5>%I*3i`POYPySZ5Zfl-^So2-6 zISX{}zG}b5B0PD4NSj@z^BXn3#z{>)5!FGCCw1qFn=$-~dSP~GT~h8*FVl1BLRZgA zTjp}lFwlJ1e{-SYi{%R*3C8{ASrs&?&VGq&>LE`%wpPnCjtr{q3sarNgx_)=tjbv! z@_p^rs=XP4Yco%6Z&)vV;I(JwZVst}1Lq{JhaJ+j=>5E>!FIyNy6jIYZ#+1B;G+sp z>gAbj?q>DV_xoy3`(FC_@r8+(8vdNvT(fm*_55j7X6H`5?wnO-@rYs4^Zan`;H?iY zIV``t?oxZ#mg#Va)OJob& zRQY+D`QZ!Zjte7=Jq;@tyk`CsI3af9ji<4Tcps}>oSu-OQ$1~7Z=(4ox7|xm@0uR{ z*yqcN2WKJ|MSZvM@Cg1i{gJf5t0v>=8<{pvu+H}~@|sv5v0~fl{r`VlJoveB-zyK3 zv#H%jy=^|A7 z!d+{tm&=Q5-v6fJI??~i37NJ{r^-&BUUu}fU$?T(g{vEvx8CSs5#06nz!#>YlHVh8 zZ~brExAjxr{Rh6fK5u88TmRZ;>EoC8uD$aTIj2u(cAeQIesa%(2Y!ZSHx2oHPV7&y^7Rdk`Kb&P#GN%`)w>Zw@4yAKIi~7^L92R?JPS+qOSr(Z@NivgZZnA5BecSr=@fueQuT zKBnl-{%3ph-%Qz;qr7*8lhK!VNz8qdHDb9tcdtm{%JnXX$F+s!-=Y&YJwq&d{epj-wWyrE zVwU~HzAqhFH`1!lg_3(ie3O4ZSx!pp1&fTuE_1%79C#Q1;@8SW{>wjP8}ah9G`Drw&RH8GeUkay(nnJBXB?W{ zlT{e^c3+{lxtG_shQ@WaY`*LcE6*z**%QtC+&Q*yjnaZ?e43B_{ys3V-+$^z?0umJ z|KBdy(0rnv<@IMtJt4bXmMPnMN>M~n>{SNC3Gku5U zk&JEs7p)NYFzs=!nEx%7JJ0y#B9>~LyE(RN&0qYmO1^Lx%qZJ&$eZ?F0Fy-lap3VOFW>woA<%NilpvsiLGWj z$2Ogt?iXQhvvB$Ci`okpDfubz#vaiB^4QRSQ{{{WVT)^XoxGR6C}TP5BHVpvy@!{W zZ-!t;deqUrhRxx@9P3Q2uk#x|?TfpWeS5;z8JT7!H*U>cvAU+C_65Vuy2G+NejMEv zr(N-2tc3`+hM0+BUCNLc+S~TG~brsZaOUoMsej z>hTM5Y&fWy%hR73<`HGo(D_$L&FWiiN9UEdJ7&AgTj-YYTX3Pl<6bWLHPVvPGNom= zWx9vv*sM|7dFFHFCYC)NXP)ynS+4t#8+4?ViQRMN{IE#Rl=Ye(WuXE*56;xDGh$;s z)}6XL)2I5N+4UT`td_&Pj4g+mZakQuwxMQ|oLu?)tlq^lGp66+zff$?(!=xrkmk$FORiB1@sUW&Fg)8By9+Z6`}JPZ!TwU-3ku{*?LjFC2e2nSYv)QOFp6F}}d# zMo@|J5vhzODgQL({AX)U9Imoit#;5w)@_N<_K8#d(|$@UVa|0lvvFa)<#r^h^~Bcl z{8PE#OFwJ~kY8dLwl~rRTw1hVu?bW`<4E+j3Jid2h)<9lpq`6}z^o6)FXo zoM>LS+1oW*-EQKqmejA|C*)?gD&OwpTktj|>&(fz$UTpD?CGn^(P3S(&Be0({iLYP zKVMAP^V4Of%e=Z^QFV`+TPx)`82(?H$Lg(eYI@pQ?PBSIhq`a;wk(}zJLlDHWwn2^ zj_d9XxKn;~{>DG*OJc+t>JIhI%1iT<(^Q_iMWpr0yN8yBHCvo*_^zJ4*U%aF<%PkQ z=c^tlt@5rpW-?>*mqy!bJFf(+6tDPwZlXcz9xDm6-b0g}a=iNuSE-51tbENraTV+L z+?M(8R|}sw^vanrJymIs+2fj>M`pCf9jR!(|KxGo`>$6#`gDS9_MDoscDeb1oU@A) z#NyB1oe{HSQb{ue2=Zx)1}Oq#A^D9}3l{v;+R zPLZEq6=qk-^?zu)^L6Q_FOM7JwU`{AZ8tTS4o^QlQ|?gr#pl!Ja5TNjj5{RxHF?#! zm)qt9brtrclvSR6wkzfJgcJE@+7@4D^ln+RK7CT^s@aZd6E?{Hnxj&@NATD2RR=n~ z&-)3qW|YiR%YQ!QzzmC-9@~v1D*Ps$7TM)_aq*>y!dL5BQ(hf$c=Kz~?1xUZXZ~g? zwFt<(iP6wEtF|=r)tt##cBp5c>+X$8^VeoX&relfKF7)A`N^Hnezg76EKz>a_Q%Xu z{9Qr2!NtwnE4iFsvRrbBT(@VE0gI|qU4Un-`#dwINk;J-PRn^+RQuM*a{5`s-4FWZ zIZ4f$IR?tNEar+%v1^FcUNCvqtvTBsy??ptuGC)Bf)f&Nq|5yNhFv`Jbg_qch1lzD zW;?gAOI9p&;z?NX#rE;ilQ!q?sZG5!KkeJUnKpT+9;X$n3yS@)6ZgtHlX8RCq>a%%{1SC4C{(59gKP0zX;AuKWoCiE;D^;>w|=AW)Wva({JTmIoevk z?akb80-90_-Mijz%D8Z$YH{TL1Zf?Y-yO3zPv5fRMT~BsSMjRQmNRL)jk=CP2Wma~OTUD9?g-z@TD^2%*C>7Pp*F>jo~ z|HE|UjWm&GJgS^`LS@WX-Zszux_={g#oBC>hb}j$fEsX}fUiN|xRyW}9syk4SyxxWKV%wau=JZ%y5v zPE^RAv*`Si=IisKW1VA8HOhJ`zfZryE28S!?xZ|$9eS#sud7IDULy12&BQN4yVvi#CBZa5dBxQdJJ~|< z8`F-6tUj}jiC?z3+iT*F z&5&o=;cSoa8%I`}M5%9oCb@1)X!L_!w%HftPM9C;nzvxanac2adw)ouI9K3OH1Bwx z;3l!`0~Z@|rzHnH&U*6q#oQFu@X$Zuxzl2L}Uy_~m8utFNkWo-o_+ zA@k_I1xfL5zO0+|Vb+|UrfqSGyVESndN^5_tQthr{w-d!C%Z1GyECon1oO*MlcqI+ z@WuEX=mT_rE_b=`vX_L zS}Gi~J}6T&`fxk1@#9&xM*a=aw&`k_r{_F;=CqMh%~x`1@B~Y?fRxnmuZ&&_rr8QF zUudX(X4#t=_i!e|hMJbc-Ln)_Hzxk(zmgsOp7Hi?ht%6lIV|>P3*!njS{(kmtHpKB zF19i<>gh~N%64sTG%lFDVS&+)XJ3?;-nM_rkTHMzgI#BT%y2 z*Y{9LlkN3GKX^+l)+FpI*9xqD<+w`BnpLy)I7i5&z1De_?;;iF?Yt$k=#=-4o_QOD zcinum<5Y-AyI*-_r)$MOAi%oi z*Y1h)-51;lb-gXB`nDtaY+HrxXW47J4EP(h4y|U4D6jtZS+4ny@T^U98SMl`Z#J_; z`Y{DHAnr^gi<=v;Ap|x&?MNy8PN8?fb zKXzG-{MlQz=X!)}chG;hqEz?o)9w=) z`#f`9^6w)7TB0-UXK2+0+tluF`68;kUg~4+CeQq-f9x}-{!DvX%^RF<&RV^*>YJXWxh9$ zev#3ZM0b_ON4E;j$*oy}0 zP38LR9r`79-@he+Ob)A-IqQc+CV7AV6Y`d^N@C6X`5AG-yzQ|&Bz^urXV|o0`&@@3 zySJ{mDe`f$lJm|51#+>XQjKcsI3@&mzfSygFX5nrrQ6Mvp4hKrKYhIxnW#o5iSLdx`yI-u-TDfi&@2Y!jFMXdkEM8^$ zEzb1iO|d8Qp1WLMyW`RNvvWMkYp-y{%N(<+y1Zq3Van+pnXP}j^=xB=-L^Al{J5+Y zopkENX`%e}VpDGQOlGt=^Gj9c;D;Tvm;ydOzxrLYd6tB?7a^=;rx4-Y^?mu_p>U}T2?^|6jZC;a85juw{ zh zvp;BmbF69QZKIQ=@Bg>|OUQX~41C_T><4Bu`SMz=mW{1qALO6eS)QGK)Z?xH)ntoT zX)l)s#V^}@kkjDk>W}6xd*t~(KRp?~?Aqg;N$0vtj%b=se6*l)pVaah+%m<-{7UsY zpRfL?GkZn*&&Ww<+r942KYPVeM*E~p@!WvqXY6Y)Tt*== z9p(}^k;?tqzenv6+uXSe*Ep*;g}h|(IlXma=-atztFrVjSqet)e7t(En!bnj)m`>S zR&Lr5F3;t4cQn(yxn`H?O((zLF{EpP|8Dn| zyUEU+$(5&Z|G@?A!9quUHcg+J`bi~RY0uWwb!%3na^2A2o^E{b$-5cCOmF8-&+9l? z>3Xz`X+>4#vPJpzKi=*BE52`~-mxFn=cli`8}K+FR(>7d-e)^r! z{HMPsdrGQ7^)1hNkMHx%ef7$5-;S6`#ZiA2EC-!PzTnFIOE)D8_MWn#!SJiXX;O}$w(|+bU|v>`}zMC>|1WYWSq!qHLdo*m%9b`l)tSD@a(FxDE!L8 z)hu+j`Jm>X*%xw_WzJ05%;Y@n{?dz+A{i&#n#jYm{P)l1Ke?wSp8x1o=TO&u;?SB8 z1(xU4mUH!1zWnAEWG?O?*tpGCq?+%^ahC3Vr`lcy%$+Fw_J_QK_Q|dMe(YO}9Jil% zI;FX7&eHUZ-_At}JD)MO1m!TFy|?^i(W+yW=PG}2eO&f<$2H!L?<+9_GS6Lc5ukoOqVQ=9=dI zIdi$xv9fvIQpUOGMW0Uzo>i1KDPG5Cg2Y2PA2#-0-!)yLOGTD6>}oy4!MBXjWR>3X z0>8tLWEbCOl{yo&$S9-J#$W%lsF~AW=S-iu3wFNx&}*JMIrvT2-Hhdy*VteFnGz%% zyDYUoIN0}7xt094gNxtuf7}1RJ7<;qp1MwsXA!mK9A|$2oU>T}jA25S+3Z6;>6}Vg zvsUT*pDr@|_2;wewnKY%pDdU(zc%j4an%h!Up|lc@Ok}$6(=6`Tf8#M-BVutRZsQx zqlr_me0<5WKrZXc-J18GbE2lqPi6{YV5>RORqb3VpDR&RQgLu)*Y+Z}8GH#bs}wid z?vnl`>}`<~BvUGTbiHFOlXGBrLrLyl_S7}}H1AKk#(AkHBtG3??G~0lyYerp?=rr6bbE;0>N_%8XTod0q!c(_-L)rI z<93ec6z_9PKF8dDXz$D~%xTHW$}bSssP-)3|IV(U#<8-cMTBS9`5T`;So{3q^Zk=5 zpJ8uV9{kJ6MBs76EswvGKT7m2k}z!RINMQ>A9>2J@8WmOgKiBP(+rp%%;}6VJoUU* zE+#PU(?idHZ#@^5R2Ba5@w?~1*O8+ye6E+H{rTZqp9>w*AM{gL`)Bj7J*aBxb#UF2 z4SJbDDNoA%O?bYhcvy1p^7Q}h;c%f=W%io10}gM4B7~10U#Z}>7~%eJfROVsRtCmC;j*M6Dz`~IFued5#aGgeBke0MK*Y^c zTW!BkFQ`t3aU0mPT5@yYNy8QJs4XNAJ->38#{I;xJyUSd=F6+40 zGG2*|Eu1Mw8P$z>TwWe5-hcah*YC^gXJ+iV)cnZ#b;B{cpgiIA+Ve^~BG=zhtY>Ym zi!FbAsB`C0K7PR?t9A!(JooIhBh#zZ>D~``FTZS-+2Qf=jraNZb{l6$sr##H*yese zp?IIQ{Ops+MJMZ58Y!@TPWZwgp>s^(LD;0CC7Z7M>K&@^{>;Ulesq3h^@m-X)qJcR zdfTD$4%*?ZQj7DI+rY|D=B$hS5ysF-?i z!>--yU++C4@-CR`&DC35B2G6SpHp(6N74CMbc|7X*tU%o=D$|#jGlYu@6(f9{mLw+gz&1?aLgD?CYoNezsgUb*)&HcH^eL z*5iHWyC%y8y-ruD_;`8Zq2;z($10EJo|+_~VshMx|D>b%lko3SK_(URSIK|$NO^0~ z!KYkvB$~7HOvj7njr)FuWPX-k<*K+Yu8_1db`C!kh{svPky7%s(FsKs_n|GJI@+cKU;q4X2d+s%-n{% zQ7`Ak^{w&Pr}kjgr=p3MCOr^eP<^xJ*PDtX{gscBeolYCs;1xj-Ky#zH*ZeQc(W~8 z@TtU;)mLg6a%x|#vG#eYxw9ep_W`~06$Z9u&lzTQH7|6ldZul*@H*3i%&ZF`8yY4s zC34!d1>W%wXzk7Ze0}}DwiqVE{3Di=9x=>RdG>w9i%Au4_dihfFlKPEK z6IW|@M69X*EZTZL@m{mE%KqssvnGmpJ}G;3>FC**{+binhjouG+2b}NbC&z52jFrXF~>`%O|G)4m>#%G>HEYh0I=sjD~i%x7Nv)L)2`^T>O{ zfGOTrY%|(SZSCC7`khQNbTht`~WpXphaIwyZ$Q+dNd6ThH<5Ove( zlLFS|x`jM>WPC$beD{aOkAn8~Zud(XrN1(n?_t_~rDe~O#TWKT?O4zDr|aIqXKR!1 zHkz>>5Q=vc)Ht~Nh|JSZLiZkC;i`(R@Y%p9eD%4I({7UnuDhq6MkWYYl`v2BsOOr( zA*VBI%fo{K>z$vsip&hG6RA4Cr0Ma(m*x3yyua5L{GImFaPqvIs>E5!$8xF?mo9?zk>1*T?cFiquy(=ZM*dr%)MVVLJclUqA(wcH{N8*OK zuvoR@Gvo}_WHnZO2=H&6ZntNlYvz?;&ej)C^cw43=H_z!mU+k`G1HgbsCT{R?M-hq z)j3ojeR#ieTGxN+%m%yC&SbL*O-1iMrYc&Tey)E1LG~%PwW)iaPuczI=Jx;Mt-D-) zryA<0wnW>R_#DxD+^4fxc=yDPDQ-em!uk_V2nCet?lbUMW@2B0Kf#Ox309 zWw(ni6Fxglw>ed_F^KhvNx;(sd28VF?qiCl6y{qsb*VLfhdiPAcRl4}FhEn71YrO$4p7qs49MKK9 zuu$)zja)!<{*Ie>3mi0`I0wqy58TbA%V5px7uphR!9Azo413+R>|?sh#r0i6CCR7X zIccQJ&YHgZ`lcwhjagkCy$7n^Uj2W#pjNg;+whxiwNaFFOiKHOlV7JeY2-QgY!K

#}F5W5M;HTUP~+ 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%0DSP!NdJ^W~=Z6$r8@|v;`GT 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 (b1Q3oEyORG7p$7-Z*AJk|EXKx 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 }bLQQvN>vq}XJ6}V+GV)7=h=#qA5S7aZ=9_^ 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 E04R$S7ytkO literal 0 HcmV?d00001 diff --git a/sbcl/.quicklisp/dists/quicklisp/archives/split-sequence-v2.0.0.tgz b/sbcl/.quicklisp/dists/quicklisp/archives/split-sequence-v2.0.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..fd15c573b1e3e7d274714f81941845b00abe60f6 GIT binary patch literal 10329 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 Hfq?-4?iT%e literal 0 HcmV?d00001 diff --git a/sbcl/.quicklisp/dists/quicklisp/archives/trivial-gray-streams-20181018-git.tgz b/sbcl/.quicklisp/dists/quicklisp/archives/trivial-gray-streams-20181018-git.tgz new file mode 100644 index 0000000000000000000000000000000000000000..9806b7d5c16ec999726e1431f84ac9d95044c669 GIT binary patch literal 8024 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 R?`8Fj*L&)>GMr#w0016!o1y>! literal 0 HcmV?d00001 diff --git a/sbcl/.quicklisp/dists/quicklisp/archives/usocket-0.8.3.tgz b/sbcl/.quicklisp/dists/quicklisp/archives/usocket-0.8.3.tgz new file mode 100644 index 0000000000000000000000000000000000000000..c76a656e31bc4a81e81edf2b25253b770af1f31e GIT binary patch literal 85851 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 literal 0 HcmV?d00001 diff --git a/sbcl/.quicklisp/dists/quicklisp/archives/yason-v0.7.8.tgz b/sbcl/.quicklisp/dists/quicklisp/archives/yason-v0.7.8.tgz new file mode 100644 index 0000000000000000000000000000000000000000..c34daf3aba5d700940561bc8771499965da07002 GIT binary patch literal 27918 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

#r#{dbz*LHd>+4n&%OF(PNsMOd`*W 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

Z%+&F$oXH86}(jHjF;rum3O6u1!cE| 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 F0|41G`QZQn literal 0 HcmV?d00001 diff --git a/sbcl/.quicklisp/dists/quicklisp/distinfo.txt b/sbcl/.quicklisp/dists/quicklisp/distinfo.txt new file mode 100644 index 0000000..86798cc --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/distinfo.txt @@ -0,0 +1,7 @@ +name: quicklisp +version: 2019-12-27 +system-index-url: http://beta.quicklisp.org/dist/quicklisp/2019-12-27/systems.txt +release-index-url: http://beta.quicklisp.org/dist/quicklisp/2019-12-27/releases.txt +archive-base-url: http://beta.quicklisp.org/ +canonical-distinfo-url: http://beta.quicklisp.org/dist/quicklisp/2019-12-27/distinfo.txt +distinfo-subscription-url: http://beta.quicklisp.org/dist/quicklisp.txt diff --git a/sbcl/.quicklisp/dists/quicklisp/enabled.txt b/sbcl/.quicklisp/dists/quicklisp/enabled.txt new file mode 100644 index 0000000..e69de29 diff --git a/sbcl/.quicklisp/dists/quicklisp/installed/releases/alexandria.txt b/sbcl/.quicklisp/dists/quicklisp/installed/releases/alexandria.txt new file mode 100644 index 0000000..9c5a37d --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/installed/releases/alexandria.txt @@ -0,0 +1 @@ +dists/quicklisp/software/alexandria-20191227-git/ diff --git a/sbcl/.quicklisp/dists/quicklisp/installed/releases/slime.txt b/sbcl/.quicklisp/dists/quicklisp/installed/releases/slime.txt new file mode 100644 index 0000000..1a3e79a --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/installed/releases/slime.txt @@ -0,0 +1 @@ +dists/quicklisp/software/slime-v2.24/ diff --git a/sbcl/.quicklisp/dists/quicklisp/installed/releases/split-sequence.txt b/sbcl/.quicklisp/dists/quicklisp/installed/releases/split-sequence.txt new file mode 100644 index 0000000..28a0527 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/installed/releases/split-sequence.txt @@ -0,0 +1 @@ +dists/quicklisp/software/split-sequence-v2.0.0/ diff --git a/sbcl/.quicklisp/dists/quicklisp/installed/releases/trivial-gray-streams.txt b/sbcl/.quicklisp/dists/quicklisp/installed/releases/trivial-gray-streams.txt new file mode 100644 index 0000000..2e59812 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/installed/releases/trivial-gray-streams.txt @@ -0,0 +1 @@ +dists/quicklisp/software/trivial-gray-streams-20181018-git/ diff --git a/sbcl/.quicklisp/dists/quicklisp/installed/releases/usocket.txt b/sbcl/.quicklisp/dists/quicklisp/installed/releases/usocket.txt new file mode 100644 index 0000000..c7f96c6 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/installed/releases/usocket.txt @@ -0,0 +1 @@ +dists/quicklisp/software/usocket-0.8.3/ diff --git a/sbcl/.quicklisp/dists/quicklisp/installed/releases/vom.txt b/sbcl/.quicklisp/dists/quicklisp/installed/releases/vom.txt new file mode 100644 index 0000000..00d6362 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/installed/releases/vom.txt @@ -0,0 +1 @@ +dists/quicklisp/software/vom-20160825-git/ diff --git a/sbcl/.quicklisp/dists/quicklisp/installed/releases/yason.txt b/sbcl/.quicklisp/dists/quicklisp/installed/releases/yason.txt new file mode 100644 index 0000000..0071fa5 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/installed/releases/yason.txt @@ -0,0 +1 @@ +dists/quicklisp/software/yason-v0.7.8/ diff --git a/sbcl/.quicklisp/dists/quicklisp/installed/systems/alexandria-tests.txt b/sbcl/.quicklisp/dists/quicklisp/installed/systems/alexandria-tests.txt new file mode 100644 index 0000000..04e4471 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/installed/systems/alexandria-tests.txt @@ -0,0 +1 @@ +dists/quicklisp/software/alexandria-20191227-git/alexandria-tests.asd diff --git a/sbcl/.quicklisp/dists/quicklisp/installed/systems/alexandria.txt b/sbcl/.quicklisp/dists/quicklisp/installed/systems/alexandria.txt new file mode 100644 index 0000000..8f1de51 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/installed/systems/alexandria.txt @@ -0,0 +1 @@ +dists/quicklisp/software/alexandria-20191227-git/alexandria.asd diff --git a/sbcl/.quicklisp/dists/quicklisp/installed/systems/split-sequence.txt b/sbcl/.quicklisp/dists/quicklisp/installed/systems/split-sequence.txt new file mode 100644 index 0000000..a06b52f --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/installed/systems/split-sequence.txt @@ -0,0 +1 @@ +dists/quicklisp/software/split-sequence-v2.0.0/split-sequence.asd diff --git a/sbcl/.quicklisp/dists/quicklisp/installed/systems/swank.txt b/sbcl/.quicklisp/dists/quicklisp/installed/systems/swank.txt new file mode 100644 index 0000000..330bc34 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/installed/systems/swank.txt @@ -0,0 +1 @@ +dists/quicklisp/software/slime-v2.24/swank.asd diff --git a/sbcl/.quicklisp/dists/quicklisp/installed/systems/trivial-gray-streams-test.txt b/sbcl/.quicklisp/dists/quicklisp/installed/systems/trivial-gray-streams-test.txt new file mode 100644 index 0000000..60077c8 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/installed/systems/trivial-gray-streams-test.txt @@ -0,0 +1 @@ +dists/quicklisp/software/trivial-gray-streams-20181018-git/trivial-gray-streams-test.asd diff --git a/sbcl/.quicklisp/dists/quicklisp/installed/systems/trivial-gray-streams.txt b/sbcl/.quicklisp/dists/quicklisp/installed/systems/trivial-gray-streams.txt new file mode 100644 index 0000000..7db7b2f --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/installed/systems/trivial-gray-streams.txt @@ -0,0 +1 @@ +dists/quicklisp/software/trivial-gray-streams-20181018-git/trivial-gray-streams.asd diff --git a/sbcl/.quicklisp/dists/quicklisp/installed/systems/usocket-server.txt b/sbcl/.quicklisp/dists/quicklisp/installed/systems/usocket-server.txt new file mode 100644 index 0000000..0e815d1 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/installed/systems/usocket-server.txt @@ -0,0 +1 @@ +dists/quicklisp/software/usocket-0.8.3/usocket-server.asd diff --git a/sbcl/.quicklisp/dists/quicklisp/installed/systems/usocket-test.txt b/sbcl/.quicklisp/dists/quicklisp/installed/systems/usocket-test.txt new file mode 100644 index 0000000..2610e37 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/installed/systems/usocket-test.txt @@ -0,0 +1 @@ +dists/quicklisp/software/usocket-0.8.3/usocket-test.asd diff --git a/sbcl/.quicklisp/dists/quicklisp/installed/systems/usocket.txt b/sbcl/.quicklisp/dists/quicklisp/installed/systems/usocket.txt new file mode 100644 index 0000000..4f2aa80 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/installed/systems/usocket.txt @@ -0,0 +1 @@ +dists/quicklisp/software/usocket-0.8.3/usocket.asd diff --git a/sbcl/.quicklisp/dists/quicklisp/installed/systems/vom.txt b/sbcl/.quicklisp/dists/quicklisp/installed/systems/vom.txt new file mode 100644 index 0000000..94241fd --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/installed/systems/vom.txt @@ -0,0 +1 @@ +dists/quicklisp/software/vom-20160825-git/vom.asd diff --git a/sbcl/.quicklisp/dists/quicklisp/installed/systems/yason.txt b/sbcl/.quicklisp/dists/quicklisp/installed/systems/yason.txt new file mode 100644 index 0000000..dd3ba86 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/installed/systems/yason.txt @@ -0,0 +1 @@ +dists/quicklisp/software/yason-v0.7.8/yason.asd diff --git a/sbcl/.quicklisp/dists/quicklisp/preference.txt b/sbcl/.quicklisp/dists/quicklisp/preference.txt new file mode 100644 index 0000000..ca57830 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/preference.txt @@ -0,0 +1 @@ +3788524139 \ No newline at end of file diff --git a/sbcl/.quicklisp/dists/quicklisp/releases.cdb b/sbcl/.quicklisp/dists/quicklisp/releases.cdb new file mode 100644 index 0000000000000000000000000000000000000000..1cafa2a146dfb1acc733b73e5b63d893c983930f GIT binary patch literal 515221 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%0ADnw#%Ky^XG!vMVQ4bxCafEXZM|6u{{i5n!E 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 literal 0 HcmV?d00001 diff --git a/sbcl/.quicklisp/dists/quicklisp/releases.txt b/sbcl/.quicklisp/dists/quicklisp/releases.txt new file mode 100644 index 0000000..fa290a3 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/releases.txt @@ -0,0 +1,1831 @@ +# project url size file-md5 content-sha1 prefix [system-file1..system-fileN] +1am http://beta.quicklisp.org/archive/1am/2014-11-06/1am-20141106-git.tgz 3490 c5e83c329157518e3ebfeef63e4ac269 83dfee1159cc630cc2453681a7caaf745f987d41 1am-20141106-git 1am.asd +3b-bmfont http://beta.quicklisp.org/archive/3b-bmfont/2019-12-27/3b-bmfont-20191227-git.tgz 7982 86d51f81bfe1ce12cbbd6387105bc0f6 be1523d1f02ca7fce9fbd4b91c879d8bd3e68d8b 3b-bmfont-20191227-git 3b-bmfont.asd +3b-swf http://beta.quicklisp.org/archive/3b-swf/2012-01-07/3b-swf-20120107-git.tgz 75453 c130b35b44de03caa7cdf043d9d27dee 2dc75635c4d6a641618a63e61a9aa98252bbd2b7 3b-swf-20120107-git 3b-swf-swc.asd 3b-swf.asd +3bgl-shader http://beta.quicklisp.org/archive/3bgl-shader/2018-02-28/3bgl-shader-20180228-git.tgz 96057 fbd3727d73a99fc11116d13330b4e1a9 bbee1ba646c170f11a97829e1d3477990075bc1c 3bgl-shader-20180228-git 3bgl-shader-example.asd 3bgl-shader.asd +3bmd http://beta.quicklisp.org/archive/3bmd/2017-10-19/3bmd-20171019-git.tgz 22819 d691962a511f2edc15f4fc228ecdf546 054c8be1629c24d5658cdb57aa858e08919a955b 3bmd-20171019-git 3bmd-ext-code-blocks.asd 3bmd-ext-definition-lists.asd 3bmd-ext-tables.asd 3bmd-ext-wiki-links.asd 3bmd-youtube-tests.asd 3bmd-youtube.asd 3bmd.asd +3bz http://beta.quicklisp.org/archive/3bz/2019-10-07/3bz-20191007-git.tgz 30098 269233dd30c2203672739352bca94461 738b9a01b481ce80cdd75d5b44e0735e9d6f3517 3bz-20191007-git 3bz.asd +3d-matrices http://beta.quicklisp.org/archive/3d-matrices/2019-10-07/3d-matrices-20191007-git.tgz 41071 f1c646a034348281b8d05aed3c1ee153 ca19e0105d6c8d2614c2d0cbb487492c9aa077f9 3d-matrices-20191007-git 3d-matrices-test.asd 3d-matrices.asd +3d-vectors http://beta.quicklisp.org/archive/3d-vectors/2019-07-10/3d-vectors-20190710-git.tgz 27831 a5cf6cf3b78cba6ec36585bc6acbde61 b4cd1b5bfe087dc6ad95671fc74242905d6b22e5 3d-vectors-20190710-git 3d-vectors-test.asd 3d-vectors.asd +a-cl-logger http://beta.quicklisp.org/archive/a-cl-logger/2018-08-31/a-cl-logger-20180831-git.tgz 18415 27b4f20b1b3d779319df4f2da5e6740e 03171fd4aa730f0d692fa54c922d2ffb16558da3 a-cl-logger-20180831-git a-cl-logger-logstash.asd a-cl-logger.asd +able http://beta.quicklisp.org/archive/able/2017-12-27/able-20171227-git.tgz 30476 bf42d58fb2f32f239e9f98561fb11be1 3d1693e9704ba4fcd19a151baf16e3600447d83b able-20171227-git able.asd +access http://beta.quicklisp.org/archive/access/2015-12-18/access-20151218-git.tgz 14821 a6f1eb4a1823b04c6db4fa2dc16d648f f8cf34ea96902db935db8c183e7c09c2fc2c8c90 access-20151218-git access.asd +acclimation http://beta.quicklisp.org/archive/acclimation/2018-08-31/acclimation-20180831-git.tgz 5069 71fa994f03a01452e0a15d27c61f5d55 3488315089e411ebe6347e4acc6ff062667a91ed acclimation-20180831-git Temperature/acclimation-temperature.asd acclimation.asd +adopt http://beta.quicklisp.org/archive/adopt/2019-12-27/adopt-20191227-hg.tgz 22054 c5ae8be1ffe8c9f37be9e9fb60196859 b54e9303f9b8f6d9bb3a9437aa29a67832bdda73 adopt-20191227-hg adopt.asd +advanced-readtable http://beta.quicklisp.org/archive/advanced-readtable/2013-07-20/advanced-readtable-20130720-git.tgz 10570 bcb3c8a4757047bf7a41117265b74a3f 163baeafd28c4f4cb0c3fb42529df5ee75a711cc advanced-readtable-20130720-git advanced-readtable.asd +adw-charting http://beta.quicklisp.org/archive/adw-charting/2012-09-09/adw-charting-20120909-http.tgz 291857 932a2a8f87a6a26b8aece05240850451 7a7e66124521f356ff6b6b9653f8b190b827b7e1 adw-charting-20120909-http adw-charting-google.asd adw-charting-vecto.asd adw-charting.asd +agnostic-lizard http://beta.quicklisp.org/archive/agnostic-lizard/2019-03-07/agnostic-lizard-20190307-git.tgz 32336 b9fdba47c8bdb8071c824dbc4067f7bb 83be3235a297e14470fe2815edf191c221368990 agnostic-lizard-20190307-git agnostic-lizard-debugger-prototype.asd agnostic-lizard.asd +agutil http://beta.quicklisp.org/archive/agutil/2019-02-02/agutil-20190202-git.tgz 6480 87f78ed77eaddc8877b44af4a6151e2e 36e70c15d9938571501ba9da145a4c2aa95272b5 agutil-20190202-git agutil.asd +ahungry-fleece http://beta.quicklisp.org/archive/ahungry-fleece/2018-08-31/ahungry-fleece-20180831-git.tgz 94922 cf283b8fddaae5430703413bd22a8841 ed6c9c7e8def3ef93b16670c73dadc770beff94f ahungry-fleece-20180831-git ahungry-fleece.asd skel/skeleton.asd +alexa http://beta.quicklisp.org/archive/alexa/2018-08-31/alexa-20180831-git.tgz 11101 322aae1831d32c65e4f7512a749e5794 d27375e85ec943d49b3fcb77b3ab606b2dd63e92 alexa-20180831-git alexa-tests.asd alexa.asd +alexandria http://beta.quicklisp.org/archive/alexandria/2019-12-27/alexandria-20191227-git.tgz 53842 634105318a9c82a2a2729d0305c91667 3df48554c447086fe060dbbca21943dcbe7b82db alexandria-20191227-git alexandria-tests.asd alexandria.asd +algebraic-data-library http://beta.quicklisp.org/archive/algebraic-data-library/2018-08-31/algebraic-data-library-20180831-git.tgz 2657 4e0c9d6480ef5824821e38ef88ce7c0f 35e8cb9da56cd9b6f4bc6bbd9b6e7094f28e367a algebraic-data-library-20180831-git algebraic-data-library.asd +also-alsa http://beta.quicklisp.org/archive/also-alsa/2019-08-13/also-alsa-20190813-git.tgz 12973 0c4ae0cbe5abfcdcaf2cd448e9be85db 77fa84942c50e825d52643b03548d5d2c6e8d042 also-alsa-20190813-git also-alsa.asd +amazon-ecs http://beta.quicklisp.org/archive/amazon-ecs/2011-04-18/amazon-ecs-20110418-git.tgz 18915 6fdd5ad095bd4a492e0d5cd07b7fae98 f8aa169d0a8e927a8357b210570f72d0198d630d amazon-ecs-20110418-git amazon-ecs.asd +anaphora http://beta.quicklisp.org/archive/anaphora/2019-10-07/anaphora-20191007-git.tgz 6114 bfaae44cfb6226f35f0afde335e51ca4 88e839f9edff0b74502c7595df3122a434401268 anaphora-20191007-git anaphora.asd +anaphoric-variants http://beta.quicklisp.org/archive/anaphoric-variants/2012-10-13/anaphoric-variants-1.0.1.tgz 3961 1958c6eed506b8dd7f7ebf4fb85142ed affec75bb8b78489722f937336342d2e003695db anaphoric-variants-1.0.1 anaphoric-variants.asd +antik http://beta.quicklisp.org/archive/antik/2019-10-08/antik-master-df14cb8c-git.tgz 1655490 1bfdd37b226dd77d2a83a8262c7f5c75 027e6a3fca896a523a6cd49cb6ae501605c6d953 antik-master-df14cb8c-git antik-base.asd antik.asd foreign-array.asd physical-dimension.asd science-data.asd +apply-argv http://beta.quicklisp.org/archive/apply-argv/2015-06-08/apply-argv-20150608-git.tgz 2451 d6c331fb609e14d8e99c2c5235767ae5 41176149bfe25382fbeee01eef0ca9aaca6aa6ec apply-argv-20150608-git apply-argv.asd +april http://beta.quicklisp.org/archive/april/2019-12-27/april-20191227-git.tgz 81594 6dbbfc4183b598deef9adb7f86b0dde0 21c472f95c9b4690786b296a8e189f08bccd1a40 april-20191227-git aplesque/aplesque.asd april.asd vex/vex.asd +arc-compat http://beta.quicklisp.org/archive/arc-compat/2018-08-31/arc-compat-20180831-git.tgz 69330 724b920b586c131d72e21b9c7438050c 4709ebe97f06bec4e489306df69bc6bf308aca8f arc-compat-20180831-git arc-compat.asd +architecture.builder-protocol http://beta.quicklisp.org/archive/architecture.builder-protocol/2019-05-21/architecture.builder-protocol-20190521-git.tgz 42621 5513a5432729ab4577400825d93d919c 1282644bcd48c2a9d30f53b2c1d0db53ec171d5b architecture.builder-protocol-20190521-git architecture.builder-protocol.asd architecture.builder-protocol.json.asd architecture.builder-protocol.universal-builder.asd architecture.builder-protocol.xpath.asd +architecture.hooks http://beta.quicklisp.org/archive/architecture.hooks/2018-12-10/architecture.hooks-20181210-git.tgz 15541 698bdb1309cae19fb8f0e1e425ba4cd9 c5d4bd17509ba19d55913a247ef56853d51a4169 architecture.hooks-20181210-git cl-hooks.asd +architecture.service-provider http://beta.quicklisp.org/archive/architecture.service-provider/2019-10-07/architecture.service-provider-20191007-git.tgz 22626 7260877f29b3fe3ad6e94126360f0bd3 9ae3133023dfc49a6e891ce2a3d1eefdc25c0513 architecture.service-provider-20191007-git architecture.service-provider-and-hooks.asd architecture.service-provider.asd +archive http://beta.quicklisp.org/archive/archive/2016-03-18/archive-20160318-git.tgz 19507 5332faf00d7b8416c0468770fa9aaf1f 83bcf90b745c5d8967086741072f3b7496733868 archive-20160318-git archive.asd +arnesi http://beta.quicklisp.org/archive/arnesi/2017-04-03/arnesi-20170403-git.tgz 84553 bbb34e1a646b2cc489766690c741d964 c83ef816a3596038ebc507611c2c17bb822a1024 arnesi-20170403-git arnesi.asd +array-operations http://beta.quicklisp.org/archive/array-operations/2019-07-10/array-operations-20190710-git.tgz 26278 42291d895198108ea4a39c195a92b4fb faa7ed1c5d9d9b2f9f1beef7db4deb8060297dda array-operations-20190710-git array-operations.asd +array-utils http://beta.quicklisp.org/archive/array-utils/2019-07-10/array-utils-20190710-git.tgz 5723 58c39c2ba3d2c8cd8a695fb867b72c33 5bc7a920472f8e254062a993d720b3d1ae4642fe array-utils-20190710-git array-utils-test.asd array-utils.asd +arrival http://beta.quicklisp.org/archive/arrival/2019-05-21/arrival-20190521-git.tgz 204257 9bc7b64b7b838feb61a99fd9241d8b7e bafc2300f7fcb8c4d7574da9825658468bee8480 arrival-20190521-git arrival.asd +arrow-macros http://beta.quicklisp.org/archive/arrow-macros/2016-09-29/arrow-macros-20160929-git.tgz 4832 0545674913ad39b66989b2a6318c69df 0618dfc6a77bdb78065a9f52e19e2af7e49df5e0 arrow-macros-20160929-git arrow-macros-test.asd arrow-macros.asd +arrows http://beta.quicklisp.org/archive/arrows/2018-10-18/arrows-20181018-git.tgz 5067 c60b5d79680de19baad018a0fe87bc48 82ebf99cf60c78e451f73e515b418f7c2f40b18b arrows-20181018-git arrows.asd +asd-generator http://beta.quicklisp.org/archive/asd-generator/2019-01-07/asd-generator-20190107-git.tgz 17944 3d89b79133f9d2e7bff3e7735a299f96 b9e465de3e179e7a7c0b73aa62be878777b014ea asd-generator-20190107-git asd-generator.asd test/asd-generator-test.asd +asdf-dependency-grovel http://beta.quicklisp.org/archive/asdf-dependency-grovel/2017-04-03/asdf-dependency-grovel-20170403-git.tgz 41965 e5f32a1e82dd83fa6446c28c2e43a73d ecfb684ceed8f4a95d124aa4f5398ec35a2dc5e2 asdf-dependency-grovel-20170403-git asdf-dependency-grovel.asd tests/test-serial-system.asd +asdf-encodings http://beta.quicklisp.org/archive/asdf-encodings/2019-10-07/asdf-encodings-20191007-git.tgz 9259 76bd0a61aa4df19e683d16592e0e62cd e3a8f15e4b8e4c4b39d4bcbbb67c6e7c308cf3d1 asdf-encodings-20191007-git asdf-encodings.asd +asdf-finalizers http://beta.quicklisp.org/archive/asdf-finalizers/2017-04-03/asdf-finalizers-20170403-git.tgz 6663 a9e3c960e6b6fdbd69640b520ef8044b 3838733d2c72f1dfc49fd2adb186f490d9f4601a asdf-finalizers-20170403-git asdf-finalizers-test.asd asdf-finalizers.asd list-of.asd +asdf-flv http://beta.quicklisp.org/archive/asdf-flv/2016-04-21/asdf-flv-version-2.1.tgz 2116 2b74b721b7e5335d2230d6b95fc6be56 7f61773346be3e61c241d597d02a3ec533d15989 asdf-flv-version-2.1 net.didierverna.asdf-flv.asd +asdf-linguist http://beta.quicklisp.org/archive/asdf-linguist/2015-09-23/asdf-linguist-20150923-git.tgz 4653 110db875b9d5cbdbc41fff8b50cc6688 b5929afb75c89ab6729d90da79686bc0885d7b55 asdf-linguist-20150923-git asdf-linguist.asd +asdf-manager http://beta.quicklisp.org/archive/asdf-manager/2016-02-08/asdf-manager-20160208-git.tgz 3156 67452d33f1e027b145ca8bfd0fa2806c eda6b453d5d3481e2d4e164c3206ae84012e7edd asdf-manager-20160208-git asdf-manager-test.asd asdf-manager.asd +asdf-package-system http://beta.quicklisp.org/archive/asdf-package-system/2015-06-08/asdf-package-system-20150608-git.tgz 1383 9eee9d811aec4894843ac1d8ae6cbccd 910495edcf74671f08ba09181539bf644e0cbb3f asdf-package-system-20150608-git asdf-package-system.asd +asdf-system-connections http://beta.quicklisp.org/archive/asdf-system-connections/2017-01-24/asdf-system-connections-20170124-git.tgz 4933 23bdbb69c433568e3e15ed705b803992 c49a358d1e61207c282e985905eae1810205fc2b asdf-system-connections-20170124-git asdf-system-connections.asd +asdf-viz http://beta.quicklisp.org/archive/asdf-viz/2019-05-21/asdf-viz-20190521-git.tgz 4138601 d979610cccb9ff58b71d99b01aaaca8b 8ce5cfd76d8031d15055a2e8390d0ac97abffa67 asdf-viz-20190521-git asdf-viz.asd +aserve http://beta.quicklisp.org/archive/aserve/2018-12-10/aserve-20181210-git.tgz 524530 4f5ddf1dcb415a1dc18a280bff91334b 8c71220d450d52b271ae7c3875eba2f37dbd80db aserve-20181210-git zaserve.asd +assert-p http://beta.quicklisp.org/archive/assert-p/2019-12-27/assert-p-20191227-git.tgz 17261 4d729e645c2a4a65aaa2eacd7602c044 f9324004ac2a29a9f217563b3fe992eff57be600 assert-p-20191227-git assert-p.asd +assertion-error http://beta.quicklisp.org/archive/assertion-error/2019-12-27/assertion-error-20191227-git.tgz 14185 797ad3c5cad14fb25eec76ccfb79b66a d9aff6bf141a59631d4371eace22a865bd29b0e6 assertion-error-20191227-git assertion-error.asd +assoc-utils http://beta.quicklisp.org/archive/assoc-utils/2018-10-18/assoc-utils-20181018-git.tgz 3516 cb9f306c3d4fac34bcf58fdd1a45eb6f 3210b7eb3a287e0307777340517b73093bca1752 assoc-utils-20181018-git assoc-utils-test.asd assoc-utils.asd +asteroids http://beta.quicklisp.org/archive/asteroids/2019-10-07/asteroids-20191007-git.tgz 3522066 e6956f404d402140e6573e24d849fc7d 89a44fb3225d6525e4bd26d20992a10ae2a0917a asteroids-20191007-git asteroids.asd +async-process http://beta.quicklisp.org/archive/async-process/2019-11-30/async-process-20191130-git.tgz 204948 a5dc34d24a41128f6342446e6348e791 18ec6b174dc9e249c7295a315233192a3cc37eec async-process-20191130-git src/async-process.asd +atdoc http://beta.quicklisp.org/archive/atdoc/2012-03-05/atdoc-20120305-git.tgz 36850 e9c40fd27b136fd9db0d0f13dc7d51a7 e60e3ca611b8eb9ff908091482932c14a119066a atdoc-20120305-git atdoc.asd example/blocks-world.asd +atomics http://beta.quicklisp.org/archive/atomics/2019-10-07/atomics-20191007-git.tgz 7007 722ec3bce23a990b37a5ccfe28da725a dabf84714ae2eed3598d6efe390c124e1b8c9791 atomics-20191007-git atomics-test.asd atomics.asd +authenticated-encryption http://beta.quicklisp.org/archive/authenticated-encryption/2018-10-18/authenticated-encryption-20181018-git.tgz 3639 02feacbc3a7b22144c368c498d5c4376 e966e0e3779ca5769c995cf4dc16e241c708a37f authenticated-encryption-20181018-git authenticated-encryption-test.asd authenticated-encryption.asd +avatar-api http://beta.quicklisp.org/archive/avatar-api/2015-06-08/avatar-api-20150608-git.tgz 2129 52a2e667536e10f80124ae2436f5d9a6 9fda0ec095f9fbdb8073605703d792a0eb3e8398 avatar-api-20150608-git avatar-api-test.asd avatar-api.asd +aws-foundation http://beta.quicklisp.org/archive/aws-foundation/2018-07-11/aws-foundation-20180711-git.tgz 4880 1cc177097ef8968147370f9970f04174 a973090f169db7cbacba714b68499f442b084902 aws-foundation-20180711-git aws-foundation.asd +aws-sign4 http://beta.quicklisp.org/archive/aws-sign4/2019-07-10/aws-sign4-20190710-git.tgz 35619 6d4df76edbdc135eadf22d09450f9c3c 54a0e8742edbbd2be9740fb6b9f620fe12c64d92 aws-sign4-20190710-git aws-sign4.asd +ayah-captcha http://beta.quicklisp.org/archive/ayah-captcha/2018-02-28/ayah-captcha-20180228-git.tgz 4660 396998f1fc484ded0afe3209ff00a380 59257d29def50e9701cdef4d34f13242cc85db4b ayah-captcha-20180228-git ayah-captcha.asd demo/ayah-captcha-demo.asd +babel http://beta.quicklisp.org/archive/babel/2019-11-30/babel-20191130-git.tgz 271183 80087c99fe351d24e56bb279a62effeb 726d583c6b9f5ff7f5c1fccc10ce2105348b0405 babel-20191130-git babel-streams.asd babel-tests.asd babel.asd +base-blobs http://beta.quicklisp.org/archive/base-blobs/2018-07-11/base-blobs-stable-9d781d0e-git.tgz 2442960 8bc33597482b7c41dc961f7ca69e2aec 36ed71aab08457bf4452c4d70de23c4574383668 base-blobs-stable-9d781d0e-git base-blobs.asd +base64 http://beta.quicklisp.org/archive/base64/2018-10-18/base64-20181018-git.tgz 2014 e7d77c873d9111e6e0a6704422805b24 3d8e62f5d3313d09e1a9ecd8d66f25b24eb58e73 base64-20181018-git base64.asd +basic-binary-ipc http://beta.quicklisp.org/archive/basic-binary-ipc/2015-08-04/basic-binary-ipc-20150804-git.tgz 57492 800adaca3395dad2c379fb6d64a51b1c dbc53ed3a51db6ec3605366dfca6616efe79dbb6 basic-binary-ipc-20150804-git basic-binary-ipc-tests.asd basic-binary-ipc.asd +bdef http://beta.quicklisp.org/archive/bdef/2019-12-27/bdef-20191227-git.tgz 13288 d9ff843530ce32a539ba4c7273bed079 308a463a559f142d4afacd85b439633ad81ac76f bdef-20191227-git bdef.asd +beast http://beta.quicklisp.org/archive/beast/2019-12-27/beast-20191227-git.tgz 14403 2c7f63da4924d0436d38082a7b1787cd 50de9053276359660d73b742d39c29f6c9c2455c beast-20191227-git beast-test.asd beast.asd +beirc http://beta.quicklisp.org/archive/beirc/2015-05-05/beirc-20150505-git.tgz 27301 50b1ea2e799d918ee68ff607f2ed7c98 091f2c11d2b297704101697235a411841ceb23ad beirc-20150505-git beirc.asd +big-string http://beta.quicklisp.org/archive/big-string/2019-03-07/big-string-20190307-hg.tgz 3949 bdffed5d0ef77e065911aba09e1bdf8c 5489c493ce7ca3c482880797a0d80c9c84e91384 big-string-20190307-hg big-string.asd +bike http://beta.quicklisp.org/archive/bike/2019-10-07/bike-20191007-git.tgz 70596 4cb973b533ea10cb735a167f77e2ff7f 9b3226071cf82b50a349d501031b1a8908ac0e18 bike-20191007-git bike-examples.asd bike-internals.asd bike-tests.asd bike.asd +binary-io http://beta.quicklisp.org/archive/binary-io/2019-12-27/binary-io-20191227-git.tgz 8936 ba18c49eb1fb8ff286cac00f7d0009f8 4ab347c91ba4fd1a680a8f033b30d1e14fbf4f1e binary-io-20191227-git binary-io.asd +binary-types http://beta.quicklisp.org/archive/binary-types/2013-06-15/binary-types-20130615-git.tgz 21337 e26f69cddf40a07beb89d9066830c44a 2f1a13a9ef75be93d53cf55d7c4c07260a620c3e binary-types-20130615-git binary-types.asd +binascii http://beta.quicklisp.org/archive/binascii/2015-07-09/binascii-20150709-git.tgz 196802 23f4db8372bd521725dd78dd667c2be1 e02502e8146770e87fa5b6e461b7729ee1117ad2 binascii-20150709-git binascii.asd +binfix http://beta.quicklisp.org/archive/binfix/2019-08-13/binfix-20190813-git.tgz 103896 916f3d55cf63c374ff9afacf03f9e9cc b3848eabd74026fd5a24d290bff94cdacd7d6dd3 binfix-20190813-git binfix.asd +binomial-heap http://beta.quicklisp.org/archive/binomial-heap/2013-04-20/binomial-heap-20130420-git.tgz 6211 ca40cb01b88a3fe902cc4cc25fb2d242 81583c3945e9f392cb8943713ed18724f72296f2 binomial-heap-20130420-git binomial-heap.asd +binpack http://beta.quicklisp.org/archive/binpack/2019-07-10/binpack-20190710-git.tgz 4335 88c5ea5d36266243886fd6d92ed03c94 6716a0de1e6296ddafd615d56bf7799d30faa4c7 binpack-20190710-git binpack.asd +birch http://beta.quicklisp.org/archive/birch/2016-03-18/birch-20160318-git.tgz 20320 1ce06aa2cbcef122fcef36186955cbd4 7deb668bd53ed29ac66d33e598efedccfe5ae6e5 birch-20160318-git birch.asd birch.test.asd +bit-ops http://beta.quicklisp.org/archive/bit-ops/2018-02-28/bit-ops-20180228-git.tgz 7131 487abc6e8afc586eb96300931a43d7be 923abf5d89d48ea17333f812c9c4bc1ab3092d90 bit-ops-20180228-git bit-ops.asd bit-ops.test.asd +bit-smasher http://beta.quicklisp.org/archive/bit-smasher/2018-10-18/bit-smasher-20181018-git.tgz 8790 bbb6df9cffc70ad72fe3a5b06664a0bc 6a4942aee4a5d892bd3b89cd5f2684dea079e951 bit-smasher-20181018-git bit-smasher.asd +bitfield-schema http://beta.quicklisp.org/archive/bitfield-schema/2012-01-07/bitfield-schema-20120107-git.tgz 6659 fac865d5c6379fd8e4a8526b99ec0662 5b4bf17a55e13ed80e657a545b9ea1ca5ceb77ec bitfield-schema-20120107-git bitfield-schema.asd +bitio http://beta.quicklisp.org/archive/bitio/2017-10-23/bitio-20171023-git.tgz 19253 4f906c8f8928bd703b72eb2207fbb623 d70390717f22b95bdbab594c14f468d674809844 bitio-20171023-git bitio.asd +bk-tree http://beta.quicklisp.org/archive/bk-tree/2013-04-20/bk-tree-20130420-git.tgz 21425 5ae53564f2a64abdc1424a054f965485 e0690274745029d8135d91abcdb18598e60e2999 bk-tree-20130420-git bk-tree.asd +bknr-datastore http://beta.quicklisp.org/archive/bknr-datastore/2019-12-27/bknr-datastore-20191227-git.tgz 630259 48d376b77c3e4bf912d25e7606f96bc1 b31c08ff484786b46311c972c2cc02ee9cc71ec1 bknr-datastore-20191227-git src/bknr.data.impex.asd src/bknr.datastore.asd src/bknr.impex.asd src/bknr.indices.asd src/bknr.skip-list.asd src/bknr.utils.asd src/bknr.xml.asd +bknr-web http://beta.quicklisp.org/archive/bknr-web/2014-07-13/bknr-web-20140713-git.tgz 172044 e867c9d79b03ea02d3e8af6d5d4a1fd7 80c17f624bf44065d7992880117d8a2373cf6744 bknr-web-20140713-git modules/bknr.modules.asd modules/spider/leech.asd src/bknr.web.asd src/html-match/html-match.asd +black-tie http://beta.quicklisp.org/archive/black-tie/2019-08-13/black-tie-20190813-git.tgz 13657 c6384b61495e45e737b0a4c8befe02c1 ceb8f687a25fe99e90bb8c7619820a7c2a8fb7e1 black-tie-20190813-git black-tie.asd +blackbird http://beta.quicklisp.org/archive/blackbird/2016-05-31/blackbird-20160531-git.tgz 12865 5cb13dc06a0eae8dcba14714d2b5365d 956c28da3fa238c46a3c52bcfc15afa415af452b blackbird-20160531-git blackbird-test.asd blackbird.asd +bobbin http://beta.quicklisp.org/archive/bobbin/2019-12-27/bobbin-20191227-hg.tgz 6090 1375f0163d0143291610a6591c7045dc 78bd651ef3eda07422453447881f91873bae548a bobbin-20191227-hg bobbin.asd +bodge-blobs-support http://beta.quicklisp.org/archive/bodge-blobs-support/2018-07-11/bodge-blobs-support-stable-8c77e4af-git.tgz 2287 9bdcf48ab4ab9f403838cd059b9affaa f44ce99cff4fbfc8362b59098847185bb884cce3 bodge-blobs-support-stable-8c77e4af-git bodge-blobs-support.asd +bodge-chipmunk http://beta.quicklisp.org/archive/bodge-chipmunk/2019-10-08/bodge-chipmunk-stable-6370e76a-git.tgz 1252241 0e111d03004ccb45037cab97c96e9bf0 6d930f384a15c6aa5d8e194135c367f9a779dc9a bodge-chipmunk-stable-6370e76a-git bodge-chipmunk.asd +bodge-glad http://beta.quicklisp.org/archive/bodge-glad/2018-02-28/bodge-glad-stable-d488bef5-git.tgz 54298 e5672047f95295ce6ab1da8f1f98b4d0 1bd91fbe51194ceb31551b724626d37230831cc3 bodge-glad-stable-d488bef5-git bodge-glad.asd +bodge-glfw http://beta.quicklisp.org/archive/bodge-glfw/2019-10-08/bodge-glfw-stable-7519a922-git.tgz 511390 030b8f5e93f15e435c231daa1f59beed eea577b03d23779d483b5e82ca79612e5a2551ec bodge-glfw-stable-7519a922-git bodge-glfw.asd +bodge-nanovg http://beta.quicklisp.org/archive/bodge-nanovg/2019-10-08/bodge-nanovg-stable-90fd9f9d-git.tgz 2103878 197d1b793047b22c7ea6c25e7628e58d 24ea020872dd2507e284e46b0197f102f83b53a4 bodge-nanovg-stable-90fd9f9d-git bodge-nanovg.asd +bodge-nuklear http://beta.quicklisp.org/archive/bodge-nuklear/2019-10-08/bodge-nuklear-stable-16f52766-git.tgz 1867351 5a3230800bb5e1e50b25c981bbbcaa40 ce626e9ea26731e7c3fbfdc08fd6efb73daa6cf6 bodge-nuklear-stable-16f52766-git bodge-nuklear.asd +bodge-ode http://beta.quicklisp.org/archive/bodge-ode/2019-10-08/bodge-ode-stable-3a5fbcea-git.tgz 2343673 24d965361477cf314b4fa50f7d851edd 64b63a2426df1b0fcce1d98958bb78c76b5ccf53 bodge-ode-stable-3a5fbcea-git bodge-ode.asd +bodge-openal http://beta.quicklisp.org/archive/bodge-openal/2019-10-08/bodge-openal-stable-9dc6ea9c-git.tgz 956800 d8eb0bfaf88c75e94014aeb8c8ecee42 6287f84f6e9b32976f4d528a0359534701f0377b bodge-openal-stable-9dc6ea9c-git bodge-openal.asd +bodge-sndfile http://beta.quicklisp.org/archive/bodge-sndfile/2019-10-08/bodge-sndfile-stable-e57475a5-git.tgz 3099841 d2eb07bf885c7f2215cab2056a7bd0cd 7bbd1e3bb5afc3294d76e2b158c8a45214405ee3 bodge-sndfile-stable-e57475a5-git bodge-sndfile.asd +bordeaux-fft http://beta.quicklisp.org/archive/bordeaux-fft/2015-06-08/bordeaux-fft-20150608-http.tgz 13857 99bee7dc569e71f40783551c792295bd a0caf5c27a3c3734178472333279926177ffb23a bordeaux-fft-20150608-http bordeaux-fft.asd +bordeaux-threads http://beta.quicklisp.org/archive/bordeaux-threads/2019-11-30/bordeaux-threads-v0.8.7.tgz 21951 071b427dd047999ffe038a2ef848ac13 b947d6b5d66b895a715f6d60044ff6d3de8afcf3 bordeaux-threads-v0.8.7 bordeaux-threads.asd +bourbaki http://beta.quicklisp.org/archive/bourbaki/2011-01-10/bourbaki-20110110-http.tgz 133787 64d23b156e8cf295c76a144e6522749b c224635f433be2ab0e45fd2e0ec13c6d735751ab bourbaki-20110110-http bourbaki.asd +bp http://beta.quicklisp.org/archive/bp/2019-12-27/bp-20191227-git.tgz 37999 079f202bf3c7eb3f3dcd4f5ed31333bc a157e736ffd5f5b70e19001a89435d5a3c937553 bp-20191227-git bp.asd +bst http://beta.quicklisp.org/archive/bst/2019-07-10/bst-20190710-git.tgz 18426 52ed6faee1e8761e061cba6bbb73936c 7c5cf9987cc1340a4241ef941c5ed473b4e72e3c bst-20190710-git bst.asd +bt-semaphore http://beta.quicklisp.org/archive/bt-semaphore/2018-07-11/bt-semaphore-20180711-git.tgz 4185 f70c869eaf18e277056a16eb3a21fd4a 23d9c3966166a46e5c42bbdacab7a2f684bfcd0c bt-semaphore-20180711-git bt-semaphore-test.asd bt-semaphore.asd +btrie http://beta.quicklisp.org/archive/btrie/2014-07-13/btrie-20140713-git.tgz 6389 1fdf3a46133861b59f7a1063f5fe6696 9d9e506112d4b87225944df068090c68d4b2c563 btrie-20140713-git btrie.asd +bubble-operator-upwards http://beta.quicklisp.org/archive/bubble-operator-upwards/2012-11-25/bubble-operator-upwards-1.0.tgz 2943 390c6f1aad23154fc613a1941ab0ee90 e5c62a9e32928fc4e4d38f9949acd9b30b0a7187 bubble-operator-upwards-1.0 bubble-operator-upwards.asd +buildapp http://beta.quicklisp.org/archive/buildapp/2015-12-18/buildapp-1.5.6.tgz 16389 b6c1450b19370d7e4ac21bf565b62c89 33832bc72acbd9b3c4a097b054bd0de1921b873a buildapp-1.5.6 buildapp.asd +buildnode http://beta.quicklisp.org/archive/buildnode/2017-04-03/buildnode-20170403-git.tgz 66725 b917f0d6c20489febbef0d5b954c350d dfe5d7aec7c73eb6797069f1d5b7fdc2d60fb610 buildnode-20170403-git buildnode-excel.asd buildnode-html5.asd buildnode-kml.asd buildnode-xhtml.asd buildnode-xul.asd buildnode.asd +burgled-batteries http://beta.quicklisp.org/archive/burgled-batteries/2016-08-25/burgled-batteries-20160825-git.tgz 42019 d20613a907e062fd32128fe25aead746 3124f87459f2bf2ad793179593df364aa383c3b1 burgled-batteries-20160825-git burgled-batteries-tests.asd burgled-batteries.asd +burgled-batteries.syntax http://beta.quicklisp.org/archive/burgled-batteries.syntax/2016-03-18/burgled-batteries.syntax-20160318-git.tgz 8126 ffdbbba14dbf3205ba0fe9ac6fae0bb0 b2801c136e8ecf705eb05c3f39e882eb56c706bb burgled-batteries.syntax-20160318-git burgled-batteries.syntax-test.asd burgled-batteries.syntax.asd +bytecurry.asdf-ext http://beta.quicklisp.org/archive/bytecurry.asdf-ext/2015-05-05/bytecurry.asdf-ext-20150505-git.tgz 2750 9fb33756e2edcb3ab0074dd8c32b73e4 32af33d3211f1d3aa8cb3a32d125ee5e49ae4236 bytecurry.asdf-ext-20150505-git bytecurry.asdf-ext.asd +bytecurry.mocks http://beta.quicklisp.org/archive/bytecurry.mocks/2015-05-05/bytecurry.mocks-20150505-git.tgz 4281 fa669aeb93a4beeb2457b3d30718adf2 648c6215a6c87842c35f9d9db578b71a7bcd2536 bytecurry.mocks-20150505-git bytecurry.mocks.asd +cacau http://beta.quicklisp.org/archive/cacau/2019-12-27/cacau-20191227-git.tgz 316777 b02aec6139693a06b09972690c6c20bb 9268f540d65c3439ff4fd186f2d22b539613010c cacau-20191227-git cacau-asdf.asd cacau-test.asd cacau.asd examples/asdf-intregration/cacau-examples-asdf-integration-test.asd examples/asdf-intregration/cacau-examples-asdf-integration.asd +cacle http://beta.quicklisp.org/archive/cacle/2019-05-21/cacle-20190521-git.tgz 16699 8ea845a295a43d0794dc43c22d36ec2c edfe4bf4dc852fac85daf536ae908816aa269d28 cacle-20190521-git cacle.asd +calispel http://beta.quicklisp.org/archive/calispel/2017-08-30/calispel-20170830-git.tgz 28640 1fba6e4b2055f5d1f0a78387e29552b1 1035e7249ad45cc5fb7aa5d6e362b0a80fefb7b8 calispel-20170830-git calispel.asd +cambl http://beta.quicklisp.org/archive/cambl/2018-12-10/cambl-20181210-git.tgz 45991 e5857aaf953cfdb3ebb1c4c49a02e92c 8d9ad22f71869a88fa184ae7e2510e73ff7c669e cambl-20181210-git cambl-test.asd cambl.asd fprog.asd +can http://beta.quicklisp.org/archive/can/2018-03-28/can-20180328-git.tgz 2565 6ef0d28d5aa6bc2936078cc116b70f39 0e6ad110295f63dba70e4f4d5f467734c8b52e20 can-20180328-git can-test.asd can.asd +caramel http://beta.quicklisp.org/archive/caramel/2013-04-20/caramel-20130420-git.tgz 4745 b6e6020c467971a5118dd7dba8276270 5d89e63be813fb25e31975f4d42db250aa2aecb2 caramel-20130420-git caramel.asd +cardiogram http://beta.quicklisp.org/archive/cardiogram/2019-08-13/cardiogram-20190813-git.tgz 9994 ebf310b3df23d141ccfaf09abd264bee 939ff797658ae8ab074cb73d4de03bc75d46b305 cardiogram-20190813-git cardiogram.asd +cari3s http://beta.quicklisp.org/archive/cari3s/2019-07-10/cari3s-20190710-git.tgz 25064 f6b7bad1691bd59f46c9e2128ce18faa 473ce6a22fb69dd67c617d9d3c15eb6c5690d634 cari3s-20190710-git cari3s.asd +carrier http://beta.quicklisp.org/archive/carrier/2018-12-10/carrier-20181210-git.tgz 3881 f831e7a8f590a9c634eaacdc8f145fe5 d2f6c847ae390bf95b2b392f562fbe17e6530563 carrier-20181210-git carrier.asd +cartesian-product-switch http://beta.quicklisp.org/archive/cartesian-product-switch/2012-09-09/cartesian-product-switch-2.0.tgz 4502 0f48da4205f8cd3b201eae1e07131fcd 82200c07f66d5d80ebeb62388108699e03e27f49 cartesian-product-switch-2.0 cartesian-product-switch.asd +caveman http://beta.quicklisp.org/archive/caveman/2019-08-13/caveman-20190813-git.tgz 29873 09d7223fd528757eaf1285dd99105ed6 63f6dd0215e1d5dc7321ee12e2c52edb31fe674c caveman-20190813-git caveman-middleware-dbimanager.asd caveman-test.asd caveman.asd caveman2-db.asd caveman2-test.asd caveman2.asd +caveman2-widgets http://beta.quicklisp.org/archive/caveman2-widgets/2018-02-28/caveman2-widgets-20180228-git.tgz 115350 960ba92d1ac86f49ce553bffd7136b25 446246d6fb1f1a2891175b7e88f45704fa72c728 caveman2-widgets-20180228-git caveman2-widgets-test.asd caveman2-widgets.asd +caveman2-widgets-bootstrap http://beta.quicklisp.org/archive/caveman2-widgets-bootstrap/2018-02-28/caveman2-widgets-bootstrap-20180228-git.tgz 4962 b6fc04d5468c9b3d6a502024eaaa8750 7ce56c2e7c5eb75f32208c90695e44a3006c10be caveman2-widgets-bootstrap-20180228-git caveman2-widgets-bootstrap-test.asd caveman2-widgets-bootstrap.asd +ccl-compat http://beta.quicklisp.org/archive/ccl-compat/2017-11-30/ccl-compat-20171130-git.tgz 7068 3229bd0be4ffa2a90e882433253a0100 fc117e973fdd6c08994c81baf99e5cc025877654 ccl-compat-20171130-git ccl-compat.asd +ccldoc http://beta.quicklisp.org/archive/ccldoc/2018-01-31/ccldoc-20180131-git.tgz 46896 d35e98910bbb163d9e2e27d156b274f8 93b40acb846828ba4f51e19cf47feed6391a511f ccldoc-20180131-git source/ccldoc-libraries.asd source/ccldoc.asd +cells http://beta.quicklisp.org/archive/cells/2018-03-28/cells-20180328-git.tgz 20813259 c28d3bfb8ee51a0d8fae9c2357b6833a 49c5235fd154b630c785941523c910666b970a64 cells-20180328-git cells-test.asd cells.asd +cepl http://beta.quicklisp.org/archive/cepl/2019-10-07/cepl-release-quicklisp-635f3483-git.tgz 434389 900d85f9a403def693c93db2b8f147d0 baea38b63add26c6aee73e0658ebbe2d7453b3d3 cepl-release-quicklisp-635f3483-git cepl.asd cepl.build.asd +cepl.camera http://beta.quicklisp.org/archive/cepl.camera/2018-02-28/cepl.camera-release-quicklisp-1292212a-git.tgz 3590 ea3319909269d1defe329ae8e126a314 6ef8df0aa73f50df2b63f462301c0bf9331d6007 cepl.camera-release-quicklisp-1292212a-git cepl.camera.asd +cepl.devil http://beta.quicklisp.org/archive/cepl.devil/2018-02-28/cepl.devil-release-quicklisp-ea5f8514-git.tgz 1930 3ca7236c320de5b217c7cd924bf8e063 6b6f880612fd28a8573cc6b4795bfa663131cf83 cepl.devil-release-quicklisp-ea5f8514-git cepl.devil.asd +cepl.drm-gbm http://beta.quicklisp.org/archive/cepl.drm-gbm/2019-05-21/cepl.drm-gbm-20190521-git.tgz 4081 1303fc696e495ec12e2ece9ee4dc6344 b74136275913799eaae407b967c32eac5baec46c cepl.drm-gbm-20190521-git cepl.drm-gbm.asd +cepl.glop http://beta.quicklisp.org/archive/cepl.glop/2018-02-28/cepl.glop-release-quicklisp-8ec09801-git.tgz 2915 33579536bbfc7037efe4ee830ecaed5f b72f80288063b5d214cf27257d1bcdf8b703878b cepl.glop-release-quicklisp-8ec09801-git cepl.glop.asd +cepl.sdl2 http://beta.quicklisp.org/archive/cepl.sdl2/2018-02-28/cepl.sdl2-release-quicklisp-6da5a030-git.tgz 4119 8e30fec5d59a4cf8f21525d1cdb9f7d3 61e4d1868d907fc092236d7f6ad8b36b685b181c cepl.sdl2-release-quicklisp-6da5a030-git cepl.sdl2.asd +cepl.sdl2-image http://beta.quicklisp.org/archive/cepl.sdl2-image/2018-02-28/cepl.sdl2-image-release-quicklisp-94a77649-git.tgz 2449 7e83fbc6868c8a13579dd590377c15fa c784ddba948e3260da76df22b18b7cc41fba7fda cepl.sdl2-image-release-quicklisp-94a77649-git cepl.sdl2-image.asd +cepl.sdl2-ttf http://beta.quicklisp.org/archive/cepl.sdl2-ttf/2018-01-31/cepl.sdl2-ttf-release-quicklisp-11b498a3-git.tgz 2404 d5e31a84c08ec2bf453a0a9cf00fa4e9 7c4640f10b7220bee04db63eef4cbf6ecae2f757 cepl.sdl2-ttf-release-quicklisp-11b498a3-git cepl.sdl2-ttf.asd +cepl.skitter http://beta.quicklisp.org/archive/cepl.skitter/2018-02-28/cepl.skitter-release-quicklisp-f52b9240-git.tgz 1755 64a97da55e6074842428311cafc99bed 63f431bc9eaa088c5c77dda2f4d983c9aa17bfdb cepl.skitter-release-quicklisp-f52b9240-git cepl.skitter.glop.asd cepl.skitter.sdl2.asd +cepl.spaces http://beta.quicklisp.org/archive/cepl.spaces/2018-03-28/cepl.spaces-release-quicklisp-c7f83f26-git.tgz 24762 53d77882ea7a52043103f436138b5496 765133bddb709078ff096c43c9ff4d98cf8fabe2 cepl.spaces-release-quicklisp-c7f83f26-git cepl.spaces.asd +ceramic http://beta.quicklisp.org/archive/ceramic/2019-11-30/ceramic-20191130-git.tgz 86783 fe8e29a2f02e11260e50449dc17d9a2d 79c7d3bfc3315beb09afa2f9fcc36f08f54e0af8 ceramic-20191130-git ceramic.asd examples/hello-world/ceramic-hello-world.asd t/app/ceramic-test-app.asd +cerberus http://beta.quicklisp.org/archive/cerberus/2019-02-02/cerberus-20190202-git.tgz 3247973 993b538eb39bdc9fa976eb688f8aaf71 6aabeae31748df0b54550e00993e3b758b344581 cerberus-20190202-git cerberus.asd +cesdi http://beta.quicklisp.org/archive/cesdi/2019-08-13/cesdi_1.0.tgz 6241 3db5a8c77f7b5facf158ef91f2161d28 77436237165035312da19ea32641b3e2dfd57c58 cesdi_1.0 cesdi.asd tests/cesdi_tests.asd +cffi http://beta.quicklisp.org/archive/cffi/2019-07-10/cffi_0.20.1.tgz 260119 b8a8337465a7b4c1be05270b777ce14f 9f0940f1693b5d19ac354a426b218734d45fb6ef cffi_0.20.1 cffi-examples.asd cffi-grovel.asd cffi-libffi.asd cffi-tests.asd cffi-toolchain.asd cffi-uffi-compat.asd cffi.asd +chameleon http://beta.quicklisp.org/archive/chameleon/2019-11-30/chameleon-v1.1.0.tgz 4071 5d1819290c08797f2cd42cdeae0f4795 48012faabe08d783071117c747b80414550e3915 chameleon-v1.1.0 chameleon.asd +chancery http://beta.quicklisp.org/archive/chancery/2019-12-27/chancery-20191227-hg.tgz 15232 ac00423a87aa78b85a877eafa97056a8 c42e7495ac578efec42d4019cf306bd4d8e20e53 chancery-20191227-hg chancery.asd chancery.test.asd +changed-stream http://beta.quicklisp.org/archive/changed-stream/2013-01-28/changed-stream-20130128-git.tgz 233624 08dfb9234851b9bbe3d2b774efc809b6 153aecf366d19d2091f7e4c8a4aa22293cd0a66b changed-stream-20130128-git changed-stream.asd changed-stream.test.asd +chanl http://beta.quicklisp.org/archive/chanl/2019-11-30/chanl-20191130-git.tgz 27265 f3101f6d31943f48b2f963d9f4c54172 457163482b344b4976527d435e097451c65942aa chanl-20191130-git chanl.asd +cheat-js http://beta.quicklisp.org/archive/cheat-js/2012-10-13/cheat-js-20121013-git.tgz 27000 d23fc2a4dfd3a0ce8c7fb42c773feb2d 288b962ed29320e097d0bf871dcd0189aa5de94d cheat-js-20121013-git cheat-js.asd +check-it http://beta.quicklisp.org/archive/check-it/2015-07-09/check-it-20150709-git.tgz 19988 0baae55e5a9c8c884202cbc51e634c42 49933b16fc112096734546df0d91bb76bef3044e check-it-20150709-git check-it.asd +checkl http://beta.quicklisp.org/archive/checkl/2018-03-28/checkl-20180328-git.tgz 8294 a5050385e2ef2977ba2112ea88128535 aca1cf3498cb81a443772c0bc306b11e037d5dd6 checkl-20180328-git checkl-docs.asd checkl-test.asd checkl.asd +chemical-compounds http://beta.quicklisp.org/archive/chemical-compounds/2011-10-01/chemical-compounds-1.0.2.tgz 5119 05d45cf42a61e9dabab409d345b778c1 1fc077075d4b580f4b363a131f670bab602e8886 chemical-compounds-1.0.2 chemical-compounds.asd +chillax http://beta.quicklisp.org/archive/chillax/2015-03-02/chillax-20150302-git.tgz 207342 f173c34bb131fe6192f5c6c87bf1be7e 860cd942dd71757d22f1b81d24919e36cca850c5 chillax-20150302-git chillax.asd chillax.core.asd chillax.jsown.asd chillax.view-server.asd chillax.yason.asd +chipmunk-blob http://beta.quicklisp.org/archive/chipmunk-blob/2018-01-31/chipmunk-blob-stable-55c6bf5b-git.tgz 758650 179214dca154f48185307aa331e7318f 54b0bf182e9eaf483d9287cd8499f33d9ea49090 chipmunk-blob-stable-55c6bf5b-git chipmunk-blob.asd +chipz http://beta.quicklisp.org/archive/chipz/2019-02-02/chipz-20190202-git.tgz 37110 e3533408ca6899fe996eede390e820c7 b2a2321ae7eab3609bf20ffa01f7bddc307bf087 chipz-20190202-git chipz.asd +chirp http://beta.quicklisp.org/archive/chirp/2019-07-10/chirp-20190710-git.tgz 86852 f55281d67bea97ea0348500ae6713d70 a05e8372d96a09bf5a8676e286b35ea476ba200a chirp-20190710-git chirp-core.asd chirp-dexador.asd chirp-drakma.asd chirp.asd +chrome-native-messaging http://beta.quicklisp.org/archive/chrome-native-messaging/2015-03-02/chrome-native-messaging-20150302-git.tgz 1973 3fae36a2473eb7095d50f8472d31bd6c beeb53f51396f5fd05217c00b07306835a566943 chrome-native-messaging-20150302-git chrome-native-messaging.asd +chronicity http://beta.quicklisp.org/archive/chronicity/2019-02-02/chronicity-20190202-git.tgz 30517 43ca1a6e3f5f16f3c3fa8708aa6f8abb 8d561cd975aec6eceaabd245b8fc4e26f9450081 chronicity-20190202-git chronicity-test.asd chronicity.asd +chtml-matcher http://beta.quicklisp.org/archive/chtml-matcher/2011-10-01/chtml-matcher-20111001-git.tgz 9772 b78c982a080fa6264d0524f5aabb6440 c328ea450fd88170ce98235761bcd3973ce2fc1e chtml-matcher-20111001-git chtml-matcher.asd +chunga http://beta.quicklisp.org/archive/chunga/2018-01-31/chunga-20180131-git.tgz 20552 044b684535b11b1eee1cf939bec6e14a 674f398ede85b384db80b21d93d5a4fae335a982 chunga-20180131-git chunga.asd +ci-utils http://beta.quicklisp.org/archive/ci-utils/2019-12-27/ci-utils-20191227-git.tgz 16686 d0c3f9cc75bca68b50276a39a8a0a705 ce9949fcdb5a8e75c2c674e527ff649d39af0960 ci-utils-20191227-git ci-utils-features.asd ci-utils.asd +circular-streams http://beta.quicklisp.org/archive/circular-streams/2016-12-04/circular-streams-20161204-git.tgz 3335 2383f3b82fa3335d9106e1354a678db8 aaeec87552396bc112300d66e93905c546e2c0ec circular-streams-20161204-git circular-streams-test.asd circular-streams.asd +city-hash http://beta.quicklisp.org/archive/city-hash/2016-08-25/city-hash-20160825-git.tgz 31639 d6ea890c84c4745bbc435b97eaa0457d 76b2a1f9c2a3e1388b89f682c5d6d493e8f25e2c city-hash-20160825-git city-hash-test.asd city-hash.asd +cl+ssl http://beta.quicklisp.org/archive/cl+ssl/2019-11-30/cl+ssl-20191130-git.tgz 52704 995aaef02ec5112a0de78b2533691629 96dd6269d2044cbe4ee3cf3f3c2abd9b7fa17110 cl+ssl-20191130-git cl+ssl.asd cl+ssl.test.asd +cl-6502 http://beta.quicklisp.org/archive/cl-6502/2015-09-23/cl-6502-20150923-git.tgz 67684 b4396714cfa3693fd1f40d3464622304 f55e04108665aa220401d15ec2b08b8cf6739e35 cl-6502-20150923-git cl-6502.asd +cl-abnf http://beta.quicklisp.org/archive/cl-abnf/2019-05-21/cl-abnf-20190521-git.tgz 7966 59e6c617f7183ae62eb9626ae12d836f 8b6f0a0f9162ba4df5fea4046bc32b4e8108189c cl-abnf-20190521-git abnf.asd +cl-abstract-classes http://beta.quicklisp.org/archive/cl-abstract-classes/2019-03-07/cl-abstract-classes-20190307-hg.tgz 4719 9f70affac8015d8fc4e29f16c642890e 9c691e814b9e541e024751edd4e3e26c87082b0b cl-abstract-classes-20190307-hg abstract-classes.asd singleton-classes.asd +cl-acronyms http://beta.quicklisp.org/archive/cl-acronyms/2015-03-02/cl-acronyms-20150302-git.tgz 927131 99e7304da8f6408227323fdab76e07db 695aaa263b152453e6f8130afb6cfcea1165a463 cl-acronyms-20150302-git cl-acronyms.asd +cl-algebraic-data-type http://beta.quicklisp.org/archive/cl-algebraic-data-type/2019-10-07/cl-algebraic-data-type-20191007-git.tgz 7396 022de40e52b252919ea9c7f77ab90435 eec9f2941bcad980c2f76a5f94df20f1f920c87f cl-algebraic-data-type-20191007-git cl-algebraic-data-type.asd +cl-all http://beta.quicklisp.org/archive/cl-all/2019-07-10/cl-all-20190710-git.tgz 5429 7927a2782ba49b86ed0ce365841bbb70 b5c956f55bea28fa792c632e86bef7a6f65e7fc1 cl-all-20190710-git cl-all.asd +cl-amqp http://beta.quicklisp.org/archive/cl-amqp/2019-10-08/cl-amqp-v0.4.1.tgz 58162 1867a1d1ecdf4606ed8c50d583b1b876 92e5c46f853154df29fb8e8a1a62bbbf23b34332 cl-amqp-v0.4.1 cl-amqp.asd cl-amqp.test.asd +cl-ana http://beta.quicklisp.org/archive/cl-ana/2019-07-10/cl-ana-20190710-git.tgz 526237 a22444bc080a90f4ff3e2b08a1ad0595 036cf75968c23e91fbe6819a2a6ecf6c4a59387b cl-ana-20190710-git binary-tree/cl-ana.binary-tree.asd calculus/cl-ana.calculus.asd cl-ana.asd clos-utils/cl-ana.clos-utils.asd columnar-table/cl-ana.columnar-table.asd csv-table/cl-ana.csv-table.asd error-propogation/cl-ana.error-propogation.asd file-utils/cl-ana.file-utils.asd fitting/cl-ana.fitting.asd functional-utils/cl-ana.functional-utils.asd generic-math/cl-ana.generic-math.asd gnuplot-interface/cl-ana.gnuplot-interface.asd gsl-cffi/cl-ana.gsl-cffi.asd hash-table-utils/cl-ana.hash-table-utils.asd hdf-cffi/cl-ana.hdf-cffi.asd hdf-table/cl-ana.hdf-table.asd hdf-typespec/cl-ana.hdf-typespec.asd hdf-utils/cl-ana.hdf-utils.asd histogram/cl-ana.histogram.asd int-char/cl-ana.int-char.asd linear-algebra/cl-ana.linear-algebra.asd list-utils/cl-ana.list-utils.asd lorentz/cl-ana.lorentz.asd macro-utils/cl-ana.macro-utils.asd makeres-block/cl-ana.makeres-block.asd makeres-branch/cl-ana.makeres-branch.asd makeres-graphviz/cl-ana.makeres-graphviz.asd makeres-macro/cl-ana.makeres-macro.asd makeres-progress/cl-ana.makeres-progress.asd makeres-table/cl-ana.makeres-table.asd makeres-utils/cl-ana.makeres-utils.asd makeres/cl-ana.makeres.asd map/cl-ana.map.asd math-functions/cl-ana.math-functions.asd memoization/cl-ana.memoization.asd ntuple-table/cl-ana.ntuple-table.asd package-utils/cl-ana.package-utils.asd pathname-utils/cl-ana.pathname-utils.asd plotting/cl-ana.plotting.asd quantity/cl-ana.quantity.asd reusable-table/cl-ana.reusable-table.asd serialization/cl-ana.serialization.asd statistical-learning/cl-ana.statistical-learning.asd statistics/cl-ana.statistics.asd string-utils/cl-ana.string-utils.asd symbol-utils/cl-ana.symbol-utils.asd table-utils/cl-ana.table-utils.asd table-viewing/cl-ana.table-viewing.asd table/cl-ana.table.asd tensor/cl-ana.tensor.asd typed-table/cl-ana.typed-table.asd typespec/cl-ana.typespec.asd +cl-annot http://beta.quicklisp.org/archive/cl-annot/2015-06-08/cl-annot-20150608-git.tgz 10039 35d8f79311bda4dd86002d11edcd0a21 31e415954f5e033907cd5d88ee4735e4ed940f12 cl-annot-20150608-git cl-annot.asd +cl-annot-prove http://beta.quicklisp.org/archive/cl-annot-prove/2015-09-23/cl-annot-prove-20150923-git.tgz 9244 d7ee8d5c35f1aaa036b77bbd1092b77c 25a765cde6977c027de5adf3067647623e96ba05 cl-annot-prove-20150923-git cl-annot-prove-test.asd cl-annot-prove.asd +cl-anonfun http://beta.quicklisp.org/archive/cl-anonfun/2011-12-03/cl-anonfun-20111203-git.tgz 2163 915bda1a7653d42090f8d20a1ad85d0b a0a38ada878271e7bc8ebc9cb75a0bd7b5cc7aa5 cl-anonfun-20111203-git cl-anonfun.asd +cl-ansi-term http://beta.quicklisp.org/archive/cl-ansi-term/2018-02-28/cl-ansi-term-20180228-git.tgz 48226 abb6d07e957b16e6899144d27ee6019a 1f58dd2298e65b8e28d1a7acd0b16762e486032b cl-ansi-term-20180228-git cl-ansi-term.asd +cl-ansi-text http://beta.quicklisp.org/archive/cl-ansi-text/2015-08-04/cl-ansi-text-20150804-git.tgz 5876 70aa38b40377a5e89a7f22bb68b3f796 2de105750d54136d99a566bbf98d57c85088fb90 cl-ansi-text-20150804-git cl-ansi-text-test.asd cl-ansi-text.asd +cl-apple-plist http://beta.quicklisp.org/archive/cl-apple-plist/2011-11-05/cl-apple-plist-20111105-git.tgz 2720 95b6163c11c22fbb84c1f43c6703e612 b973e5c37b48d524c34b1ea2e8b89f636d69ad06 cl-apple-plist-20111105-git cl-apple-plist.asd +cl-arff-parser http://beta.quicklisp.org/archive/cl-arff-parser/2013-04-21/cl-arff-parser-20130421-git.tgz 4500 8ae977859eb11df65a1694b52436b0b5 d2342be9fa7b9a7aea26935b6268b7f556f7ff81 cl-arff-parser-20130421-git cl-arff-parser.asd +cl-argparse http://beta.quicklisp.org/archive/cl-argparse/2019-12-27/cl-argparse-20191227-git.tgz 6876 199e936fd0f8990d7fe264ef5d0c9101 becc75542c82a1d028a1d99cc74cec61448f2c78 cl-argparse-20191227-git src/cl-argparse.asd +cl-arrows http://beta.quicklisp.org/archive/cl-arrows/2016-03-18/cl-arrows-20160318-git.tgz 2072 3098c08f52480279d64bd1314e72d50c 91c9b1d1fb60d4e188647797785ace68d9bc4d5e cl-arrows-20160318-git cl-arrows.asd +cl-arxiv-api http://beta.quicklisp.org/archive/cl-arxiv-api/2017-04-03/cl-arxiv-api-20170403-git.tgz 9013 3537c564323f050ba434a8198e525455 7c066716a5453b08d60181849bfb302517009806 cl-arxiv-api-20170403-git cl-arxiv-api.asd +cl-ascii-art http://beta.quicklisp.org/archive/cl-ascii-art/2017-10-19/cl-ascii-art-20171019-git.tgz 2500481 cf7fe4d84658d5d65d899e5b2c2f88fe 1fce75ccdd44c7ff91be24c51e6d570f009ccd94 cl-ascii-art-20171019-git cl-ascii-art.asd +cl-ascii-table http://beta.quicklisp.org/archive/cl-ascii-table/2017-12-27/cl-ascii-table-20171227-git.tgz 3493 4a48649958049fd2a147ec6dcc2f4dea 83858d3fd90d9f3f41e7057bcdeefc583178d42a cl-ascii-table-20171227-git cl-ascii-table.asd +cl-association-rules http://beta.quicklisp.org/archive/cl-association-rules/2017-04-03/cl-association-rules-20170403-git.tgz 4370 641b30a4fcf913cf91acbe6aaf2cae1a cf2b99cd6350ac6eef1a1301b6f80d5d27d5e305 cl-association-rules-20170403-git cl-association-rules.asd +cl-async http://beta.quicklisp.org/archive/cl-async/2019-11-30/cl-async-20191130-git.tgz 56759 3850bc827b4c41b6047b962e3892bcb2 a958e4d8f40c64c4e0c2f0da80624af120bfb7cd cl-async-20191130-git cl-async-repl.asd cl-async-ssl.asd cl-async-test.asd cl-async.asd +cl-async-future http://beta.quicklisp.org/archive/cl-async-future/2015-01-13/cl-async-future-20150113-git.tgz 5719 961dbcb0bad3515ac7170f96dfd626ef 50751c2b573e0323f4c4687427df1d15b901cc38 cl-async-future-20150113-git cl-async-future.asd +cl-autorepo http://beta.quicklisp.org/archive/cl-autorepo/2018-07-11/cl-autorepo-20180711-git.tgz 2223 333fc8779ce41c4e87ed5bdae6a18047 93fa8ee37a34306d513fbdcdfef0b32b6e50723d cl-autorepo-20180711-git cl-autorepo.asd +cl-autowrap http://beta.quicklisp.org/archive/cl-autowrap/2019-05-21/cl-autowrap-20190521-git.tgz 76125 be601951cafd465e1445586a16024e0b b337ff6c7c98ded0be3c1b92853815a5fd38d23c cl-autowrap-20190521-git cl-autowrap-test.asd cl-autowrap.asd cl-plus-c.asd +cl-azure http://beta.quicklisp.org/archive/cl-azure/2016-08-25/cl-azure-20160825-git.tgz 16121 b85ed39bbbe3dc96b008dba7f7832365 e6bc24f54ee60ad9c51143995e36e9344f450b57 cl-azure-20160825-git cl-azure.asd +cl-base32 http://beta.quicklisp.org/archive/cl-base32/2013-04-20/cl-base32-20130420-git.tgz 3417 e5066e4e4947e6f9d4debcbb38c008b9 ae9f24b9a9f4055650d2cc5aafd986cd4251b19b cl-base32-20130420-git cl-base32.asd +cl-base58 http://beta.quicklisp.org/archive/cl-base58/2015-01-13/cl-base58-20150113-git.tgz 2327 18cbd835ced24e94b0eff6380d7ee088 114d203cecd45d09c54756b5042d493c31f37d51 cl-base58-20150113-git cl-base58-test.asd cl-base58.asd +cl-base64 http://beta.quicklisp.org/archive/cl-base64/2015-09-23/cl-base64-20150923-git.tgz 8589 560d0601eaa86901611f1484257b9a57 429e68ef554c75d437f2f109d670c28fd877bf0a cl-base64-20150923-git cl-base64.asd +cl-batis http://beta.quicklisp.org/archive/cl-batis/2019-01-07/cl-batis-20190107-git.tgz 9418 5dece883bcc69d11ed1f7e4a00b35671 a68412091d2bbbe32919dc0238ff3d504d5bacae cl-batis-20190107-git batis-test.asd batis.asd cl-batis.asd +cl-bayesnet http://beta.quicklisp.org/archive/cl-bayesnet/2013-04-20/cl-bayesnet-20130420-git.tgz 1176067 bfbc8a2a51d5b76c4c53993d2280d94f ff6228f63582e6f4a5665fb845bce62df365347a cl-bayesnet-20130420-git cl-bayesnet.asd +cl-beanstalk http://beta.quicklisp.org/archive/cl-beanstalk/2011-06-19/cl-beanstalk-20110619-git.tgz 8888 a0cc4fd21e978722d70185c8cb908053 657eca4550127ddf554db273999f89f5a4e1b7e7 cl-beanstalk-20110619-git cl-beanstalk.asd +cl-bencode http://beta.quicklisp.org/archive/cl-bencode/2018-02-28/cl-bencode-20180228-git.tgz 6343 4eaa85d018a4fbb35378c07c727bf585 0548331a29e838863d1f0573ca8c788647ea8196 cl-bencode-20180228-git bencode.asd +cl-bert http://beta.quicklisp.org/archive/cl-bert/2014-11-06/cl-bert-20141106-git.tgz 3107 146379540abc497d942ef89d33df9672 d7082e37cc22c2d99b2dba50f6cf8ea1060f85a9 cl-bert-20141106-git bert.asd +cl-bibtex http://beta.quicklisp.org/archive/cl-bibtex/2018-12-10/cl-bibtex-20181210-git.tgz 76724 83cf40c69b449a4b543538f67fdf69cd 05c1cf877743b2f32a2d8f87fc871858d9b403a5 cl-bibtex-20181210-git bibtex.asd +cl-bip39 http://beta.quicklisp.org/archive/cl-bip39/2018-07-11/cl-bip39-20180711-git.tgz 10742 a791287d7b55d8a813f3239016b321ea f24dffe751c80eaa3e0042545289be79c7447be2 cl-bip39-20180711-git cl-bip39.asd +cl-bloom http://beta.quicklisp.org/archive/cl-bloom/2018-02-28/cl-bloom-20180228-git.tgz 4302 89f0727b66223ccb6aeb294fc0cc011f ad6f0142aefcc1bfbeeec81e09627a2a74e78047 cl-bloom-20180228-git cl-bloom.asd +cl-bnf http://beta.quicklisp.org/archive/cl-bnf/2019-11-30/cl-bnf-20191130-git.tgz 5694 2a6d8add79f964ed0e4028dda0c3b3c0 8c26582251999166575d7d9d9fb379c8ae73f83b cl-bnf-20191130-git cl-bnf-examples.asd cl-bnf-tests.asd cl-bnf.asd +cl-bootstrap http://beta.quicklisp.org/archive/cl-bootstrap/2018-08-31/cl-bootstrap-20180831-git.tgz 161893 cee57823b000ebedbf0ca2a5bc745e8b 832338aec105f68f8982c4e6ecdc1209361ce3e8 cl-bootstrap-20180831-git cl-bootstrap-demo.asd cl-bootstrap-test.asd cl-bootstrap.asd +cl-bplustree http://beta.quicklisp.org/archive/cl-bplustree/2018-03-28/cl-bplustree-20180328-git.tgz 8921 e5a31bafa8e9e42a5da16d675b852697 84702c33e5625e787ea4df04d7d5c2cf82336bde cl-bplustree-20180328-git cl-bplustree.asd +cl-bson http://beta.quicklisp.org/archive/cl-bson/2017-04-03/cl-bson-20170403-git.tgz 35505 c9359beeeb67fde4566ca3fdcd2e7ba6 74baa529bd8c1038f4dc509baabba84f545f001f cl-bson-20170403-git cl-bson-test.asd cl-bson.asd +cl-buchberger http://beta.quicklisp.org/archive/cl-buchberger/2011-05-22/cl-buchberger-20110522-git.tgz 7989 8a993756267bd3eea16fdaaab023ad59 d0df1a56821d2187a97c578441b95980fbe92ec7 cl-buchberger-20110522-git cl-buchberger.asd +cl-bunny http://beta.quicklisp.org/archive/cl-bunny/2016-03-18/cl-bunny-0.4.5.tgz 44478 240ffda23fedfbb0b2cd1fcd51bb8a5d a02dfc2e897e1f9ffa2b6b3883bae1a3c7cc5f4e cl-bunny-0.4.5 cl-bunny.asd cl-bunny.examples.asd cl-bunny.test.asd +cl-ca http://beta.quicklisp.org/archive/cl-ca/2016-12-04/cl-ca-20161204-git.tgz 4056 e20a120a4bdea1da122f67d1c748c164 250c6a1fd47118fd4634c1ca7b67f6eec8822e29 cl-ca-20161204-git cl-ca.asd +cl-cache-tables http://beta.quicklisp.org/archive/cl-cache-tables/2017-10-19/cl-cache-tables-20171019-git.tgz 5219 24fcc0c7e5c4b56aa4d3c0ccf8013804 8467ba23db68b1b2136216eb37934664bbc56560 cl-cache-tables-20171019-git cl-cache-tables.asd +cl-cairo2 http://beta.quicklisp.org/archive/cl-cairo2/2016-05-31/cl-cairo2-20160531-git.tgz 219593 aa81d669f8c3feb77dd952f0e4d41719 34fc6c321105781ff8edce95e921dddf81f85a40 cl-cairo2-20160531-git a-cl-cairo2-loader.asd cl-cairo2-demos.asd cl-cairo2-gtk2.asd cl-cairo2-xlib.asd cl-cairo2.asd +cl-case-control http://beta.quicklisp.org/archive/cl-case-control/2014-11-06/cl-case-control-20141106-git.tgz 4262 9bd926eaf15cc7053ef7e6676491aa23 a2d273abfa6ff8f0680f0f9d6545064ba133908a cl-case-control-20141106-git cl-case-control.asd +cl-cffi-gtk http://beta.quicklisp.org/archive/cl-cffi-gtk/2019-07-10/cl-cffi-gtk-20190710-git.tgz 6290692 4ab4d1eabe6fd639f40cb1053ef002b9 788f1a286b96e4d0062e12e68d81e58c3dcb0a6c cl-cffi-gtk-20190710-git cairo/cl-cffi-gtk-cairo.asd demo/cairo-demo/cl-cffi-gtk-demo-cairo.asd demo/glib-demo/cl-cffi-gtk-demo-glib.asd demo/gobject-demo/cl-cffi-gtk-demo-gobject.asd demo/gtk-example/cl-cffi-gtk-example-gtk.asd demo/opengl-demo/cl-cffi-gtk-opengl-demo.asd gdk-pixbuf/cl-cffi-gtk-gdk-pixbuf.asd gdk/cl-cffi-gtk-gdk.asd gio/cl-cffi-gtk-gio.asd glib/cl-cffi-gtk-glib.asd gobject/cl-cffi-gtk-gobject.asd gtk/cl-cffi-gtk.asd pango/cl-cffi-gtk-pango.asd +cl-change-case http://beta.quicklisp.org/archive/cl-change-case/2019-10-07/cl-change-case-20191007-git.tgz 6031 385245df04b1f1514b9fd709a08c4082 5a754242c13cfc0b59832b63053c4fc1fdde0b3d cl-change-case-20191007-git cl-change-case-test.asd cl-change-case.asd +cl-charms http://beta.quicklisp.org/archive/cl-charms/2018-12-10/cl-charms-20181210-git.tgz 26980 19641e2e670b34fe8d8be493d48cb2b3 f00cd4c3c8afae0920c4c5e5181673550b6c1d90 cl-charms-20181210-git cl-charms-paint.asd cl-charms-timer.asd cl-charms.asd +cl-cheshire-cat http://beta.quicklisp.org/archive/cl-cheshire-cat/2012-11-25/cl-cheshire-cat-20121125-git.tgz 23482 729d03cde121deedf97f3669c262e82e d2797915bed6422d5516abeb9f3c4a33809c306b cl-cheshire-cat-20121125-git cl-cheshire-cat.asd +cl-clblas http://beta.quicklisp.org/archive/cl-clblas/2018-10-18/cl-clblas-20181018-git.tgz 8535 ae2ac2ceba89561bc472677ab373017f ecca33c74178a2f77c94fdb3f40a9fee5e87c399 cl-clblas-20181018-git cl-clblas-test.asd cl-clblas.asd +cl-cli http://beta.quicklisp.org/archive/cl-cli/2015-12-18/cl-cli-20151218-git.tgz 6467 820e5c7dde6800fcfa44b1fbc7a9d62b 95d3aaf9325b6317343844e8b40efdf7c302a47f cl-cli-20151218-git cl-cli.asd +cl-cli-parser http://beta.quicklisp.org/archive/cl-cli-parser/2015-06-08/cl-cli-parser-20150608-git.tgz 8093 38fc199ad50a98819a3cd0d82665fe68 a7e3a4d60a6069b08ecd5ebf477609c6927710c3 cl-cli-parser-20150608-git cli-parser.asd +cl-clon http://beta.quicklisp.org/archive/cl-clon/2018-02-28/clon-1.0b24.tgz 191003 7d74fc146a2de5be70a9cb2c5a94312e fa0a4d3ed8bf00ddbdb104b6764a272e21fd0e65 clon-1.0b24 core/net.didierverna.clon.core.asd net.didierverna.clon.asd setup/net.didierverna.clon.setup.asd termio/net.didierverna.clon.termio.asd +cl-closure-template http://beta.quicklisp.org/archive/cl-closure-template/2015-08-04/cl-closure-template-20150804-git.tgz 98945 d2b36fa36a3bbb532c7898c2ff6211f7 b58d01914b50c26a7a43ed1e0848562a212017b3 cl-closure-template-20150804-git closure-template.asd +cl-clsparse http://beta.quicklisp.org/archive/cl-clsparse/2019-08-13/cl-clsparse-20190813-git.tgz 5431 f52ee9a080bc55364c817ea7c032588d e9b211b3f6c39cca6e07516292673c76271b2349 cl-clsparse-20190813-git cl-clsparse.asd +cl-cognito http://beta.quicklisp.org/archive/cl-cognito/2018-12-10/cl-cognito-20181210-git.tgz 10532 6372b22b37cd2f092542cf4add7f336b a31ce281d683c6d15bd458f2dc366ea5ba641b86 cl-cognito-20181210-git cl-cognito.asd +cl-collider http://beta.quicklisp.org/archive/cl-collider/2019-12-27/cl-collider-20191227-git.tgz 54466 f20f5b92d3c9ff4ed7d3fdfabeda763a f30661c617108d845cd4d0144db0106a52019347 cl-collider-20191227-git cl-collider.asd osc/sc-osc.asd +cl-colors http://beta.quicklisp.org/archive/cl-colors/2018-03-28/cl-colors-20180328-git.tgz 14566 5e59ea59b32a0254df9610a5662ae2ec 08d7a2af682802fce159e47ff3511112f24e892a cl-colors-20180328-git cl-colors.asd +cl-colors2 http://beta.quicklisp.org/archive/cl-colors2/2018-10-18/cl-colors2-20181018-git.tgz 21403 ccf1cc214fbce1d11caba8124e844df7 d3a297fade1aa485fe17326c4f2e424558d0feba cl-colors2-20181018-git cl-colors2.asd +cl-conllu http://beta.quicklisp.org/archive/cl-conllu/2019-05-21/cl-conllu-20190521-git.tgz 41333 996654fc068fa6c548868e0455587d9f 2a807ef4d732e413d752212f0804b57c82c52e31 cl-conllu-20190521-git cl-conllu.asd +cl-conspack http://beta.quicklisp.org/archive/cl-conspack/2017-04-03/cl-conspack-20170403-git.tgz 46289 43b17d3d9bb969ffd1919f7c05453c14 6f2acf5bb1d4c2d18573fc5f6eec367325131924 cl-conspack-20170403-git cl-conspack-test.asd cl-conspack.asd +cl-cont http://beta.quicklisp.org/archive/cl-cont/2011-02-19/cl-cont-20110219-darcs.tgz 11715 204ad0178da3de604e92fab5ac1c20b6 f24ffb4d90a98f4ab82841279f29ac64615069de cl-cont-20110219-darcs cl-cont-test.asd cl-cont.asd +cl-containers http://beta.quicklisp.org/archive/cl-containers/2017-04-03/cl-containers-20170403-git.tgz 229279 17123cd2b018cd3eb048eceef78be3f8 3b0e0761995c807fa27cdc74ef97fecf1ba48339 cl-containers-20170403-git cl-containers-test.asd cl-containers.asd +cl-cookie http://beta.quicklisp.org/archive/cl-cookie/2019-10-07/cl-cookie-20191007-git.tgz 4880 37595a6705fdd77415b859aea90d30bc c1dad8b9e287398c5f909af268f1b3908dabc760 cl-cookie-20191007-git cl-cookie-test.asd cl-cookie.asd +cl-coroutine http://beta.quicklisp.org/archive/cl-coroutine/2016-09-29/cl-coroutine-20160929-git.tgz 3335 d89c78cb0a94768603c8f581227af23f 934dcbb769a9199affe633368462e104fbf2c03f cl-coroutine-20160929-git cl-coroutine-test.asd cl-coroutine.asd +cl-coveralls http://beta.quicklisp.org/archive/cl-coveralls/2019-10-07/cl-coveralls-20191007-git.tgz 6629 39f50fddc88f80f9129a17027cfeb6d5 3806f18146a0cbf543329d39508ae55e9607e8fc cl-coveralls-20191007-git cl-coveralls-test.asd cl-coveralls.asd +cl-cpus http://beta.quicklisp.org/archive/cl-cpus/2018-04-30/cl-cpus-20180430-git.tgz 2505 8144fd890f060d558d896c2b10538f02 1c38814243fe2a8f437189d7a7496cd51574f1bb cl-cpus-20180430-git cl-cpus.asd +cl-crc64 http://beta.quicklisp.org/archive/cl-crc64/2014-07-13/cl-crc64-20140713-git.tgz 3436 d97cf9231647235a938707e64a1766ad 3140afa99b2ee11f7cda85f9563b975c45cdb9d2 cl-crc64-20140713-git cl-crc64.asd +cl-creditcard http://beta.quicklisp.org/archive/cl-creditcard/2015-01-13/cl-creditcard-20150113-git.tgz 10834 35f506d0dcef15f26a46b6419c0f060b 0b816115dbedc264e2d3724088267220a8e43a5a cl-creditcard-20150113-git cl-authorize-net.asd cl-creditcard.asd +cl-cron http://beta.quicklisp.org/archive/cl-cron/2019-03-07/cl-cron-20190307-hg.tgz 15874 d5d1bace9780975f4f4144e0c0f4b0fc 35ccdd808c6e532928a100f25fc95bb5fcaf5b2a cl-cron-20190307-hg cl-cron.asd +cl-crypt http://beta.quicklisp.org/archive/cl-crypt/2012-05-20/cl-crypt-20120520-git.tgz 7279 0e6b5ba0cd7a565686e847197622698f f66ea06ec261e994f5ba7d71236c93a3a4edd113 cl-crypt-20120520-git crypt.asd +cl-css http://beta.quicklisp.org/archive/cl-css/2014-09-14/cl-css-20140914-git.tgz 4907 a91f5a5d6a751af31d5c4fd8170f6ece 0b25eb863296f4d83523535c606514502ad6aac5 cl-css-20140914-git cl-css.asd +cl-csv http://beta.quicklisp.org/archive/cl-csv/2018-08-31/cl-csv-20180831-git.tgz 25961 4bd0ef366dea9d48c4581ed73a208cf3 8d16eafebdbb7557ca46f0c3a9b7b8c61f06dcae cl-csv-20180831-git cl-csv-clsql.asd cl-csv-data-table.asd cl-csv.asd +cl-cuda http://beta.quicklisp.org/archive/cl-cuda/2019-10-08/cl-cuda-20191008-git.tgz 72953 bb1ed940f70994c6c078d25337ab343e 653bc8f9cdb6d04c1a1d1909ba278d1d327ace86 cl-cuda-20191008-git cl-cuda-examples.asd cl-cuda-interop-examples.asd cl-cuda-interop.asd cl-cuda-misc.asd cl-cuda.asd +cl-custom-hash-table http://beta.quicklisp.org/archive/cl-custom-hash-table/2017-11-30/cl-custom-hash-table-20171130-git.tgz 7684 c7f9c269174fb5b42717c55d3beed364 42bfbb4a958a3b3259e645d7ae2b434ec84d79a7 cl-custom-hash-table-20171130-git cl-custom-hash-table-test.asd cl-custom-hash-table.asd +cl-cut http://beta.quicklisp.org/archive/cl-cut/2018-01-31/cl-cut-20180131-git.tgz 5001 e020c977e8064ff8b5a6e00c43b2612e 6a7a89a4568e71e2d4b41cb711cd54c4a63ef928 cl-cut-20180131-git cl-cut.asd cl-cut.test.asd +cl-cxx http://beta.quicklisp.org/archive/cl-cxx/2019-05-21/cl-cxx-20190521-git.tgz 6123 2faa57c1c9a2b33b6b5a90828ad24b9f c1455566260bad2f68e58dfdca25b4cfbebbf2b4 cl-cxx-20190521-git cxx-test.asd cxx.asd +cl-darksky http://beta.quicklisp.org/archive/cl-darksky/2018-07-11/cl-darksky-20180711-git.tgz 2006 c62b43b0d00975df19b5c5e72433b462 4b55a096708a83a7fa703813c4ddb02178e45ab3 cl-darksky-20180711-git cl-darksky-test.asd cl-darksky.asd +cl-data-format-validation http://beta.quicklisp.org/archive/cl-data-format-validation/2014-07-13/cl-data-format-validation-20140713-git.tgz 37403 2d13446e593b3b0c46fb83ee9fc5da7f 0a085113a3c0e2c28735f4709b31ff46ee54b68b cl-data-format-validation-20140713-git data-format-validation.asd +cl-data-frame http://beta.quicklisp.org/archive/cl-data-frame/2017-11-30/cl-data-frame-20171130-git.tgz 8813 fdd3f478710440340ac70bffa48a1d73 6db4200be1705e935dc9c72a7e619cdaf47d1d8d cl-data-frame-20171130-git cl-data-frame.asd +cl-date-time-parser http://beta.quicklisp.org/archive/cl-date-time-parser/2014-07-13/cl-date-time-parser-20140713-git.tgz 10231 a5c384eafcdcf063499341b40c09129a 7633ae11684c9c8cd219f4cf615869bc2b5d2c42 cl-date-time-parser-20140713-git cl-date-time-parser.asd +cl-db3 http://beta.quicklisp.org/archive/cl-db3/2019-07-10/cl-db3-20190710-git.tgz 6063 efbee2cdb4ff1ce12dfd8d6fdea20f49 fca6a1dca15b58bf98bd856028e7ce029f985120 cl-db3-20190710-git db3.asd +cl-dbi http://beta.quicklisp.org/archive/cl-dbi/2019-10-07/cl-dbi-20191007-git.tgz 14683 bf524c4000468d12627fa419ae412abb 5f1c8914dca8ac2ef97a04c6068d988908422b1a cl-dbi-20191007-git cl-dbi.asd dbd-mysql.asd dbd-postgres.asd dbd-sqlite3.asd dbi-test.asd dbi.asd +cl-dbi-connection-pool http://beta.quicklisp.org/archive/cl-dbi-connection-pool/2019-01-07/cl-dbi-connection-pool-20190107-git.tgz 6113 a5724b7fc356695c5767580a86c6df9d d8cc6ce43e8b3fd42149fdbf4da5bd831944aa5c cl-dbi-connection-pool-20190107-git cl-dbi-connection-pool.asd dbi-cp-test.asd dbi-cp.asd +cl-dct http://beta.quicklisp.org/archive/cl-dct/2019-11-30/cl-dct-20191130-git.tgz 6823 6f4faa9be0f2ce2a6a959ea705fe8617 8eff1202d59f2f0e27b94d4587f9e2b142946272 cl-dct-20191130-git dct-test.asd dct.asd +cl-decimals http://beta.quicklisp.org/archive/cl-decimals/2019-07-10/cl-decimals-20190710-git.tgz 8044 978ca67fae1ab66015c551505734a149 14ba8ef7eae9319a141e0141f4d8d571b38d8dbb cl-decimals-20190710-git decimals.asd +cl-devil http://beta.quicklisp.org/archive/cl-devil/2015-03-02/cl-devil-20150302-git.tgz 7271 2386d79fa23a831b46dd3a851b635165 81f0c286536f30795267f35614562d2459c41cea cl-devil-20150302-git cl-devil.asd cl-ilu.asd cl-ilut.asd +cl-diceware http://beta.quicklisp.org/archive/cl-diceware/2015-09-23/cl-diceware-20150923-git.tgz 46217 1effc5add086f20640ecca3ea9fb6d44 26501cee6304c77b9db6320e1f2b3fbba88ede2b cl-diceware-20150923-git cl-diceware.asd +cl-difflib http://beta.quicklisp.org/archive/cl-difflib/2013-01-28/cl-difflib-20130128-git.tgz 11909 e8a3434843a368373b67d09983d2b809 2acef03b40d410454539b26882762b25f60da136 cl-difflib-20130128-git cl-difflib-tests.asd cl-difflib.asd +cl-digraph http://beta.quicklisp.org/archive/cl-digraph/2019-12-27/cl-digraph-20191227-hg.tgz 16154 1b66f04c2af3a2a7e6629f9d5f97c3f8 578cdb45125c0cfcf11d22ca52bfa736792bb8bc cl-digraph-20191227-hg cl-digraph.asd cl-digraph.dot.asd cl-digraph.test.asd +cl-diskspace http://beta.quicklisp.org/archive/cl-diskspace/2018-01-31/cl-diskspace-20180131-git.tgz 5005 e82009d42eb86994120bccb7ac5e85a7 f648ea789bba382408ad523e1117a48885ccf290 cl-diskspace-20180131-git cl-diskspace.asd +cl-disque http://beta.quicklisp.org/archive/cl-disque/2017-12-27/cl-disque-20171227-git.tgz 12120 422f594efe55882f080273d68d26c561 f0a7b26834d07a6b35c03c16ba8aeeae18df6160 cl-disque-20171227-git cl-disque-test.asd cl-disque.asd +cl-docutils http://beta.quicklisp.org/archive/cl-docutils/2013-01-28/cl-docutils-20130128-git.tgz 115606 e83e70398da47984339dd29632a78072 014884afae1335295230482b54b560ed7bc51db6 cl-docutils-20130128-git docutils.asd +cl-dot http://beta.quicklisp.org/archive/cl-dot/2018-01-31/cl-dot-20180131-git.tgz 186442 1a552bdc7365fd5e7d2f00a7e49c2202 c35f35701d4fbebe0fc06836ac412566494e28e8 cl-dot-20180131-git cl-dot.asd +cl-dotenv http://beta.quicklisp.org/archive/cl-dotenv/2018-10-18/cl-dotenv-20181018-git.tgz 5339 ea905b934f2a2dc8ee3bfc88fc35ac49 3fe52852f1350c31baa11f85094ad6b7c433ea42 cl-dotenv-20181018-git cl-dotenv-test.asd cl-dotenv.asd +cl-drm http://beta.quicklisp.org/archive/cl-drm/2016-12-04/cl-drm-20161204-git.tgz 3310 dc45def8e5c9df2d9622193b400aa968 5f5474b54ced85e2eaba592dac37c07eb12f702c cl-drm-20161204-git cl-drm.asd +cl-dropbox http://beta.quicklisp.org/archive/cl-dropbox/2015-06-08/cl-dropbox-20150608-git.tgz 3127 cb8e142a42e59c3ad3ebc51243f0e9fd 692318495dcbb349116b544b33482119a1620ff7 cl-dropbox-20150608-git cl-dropbox.asd +cl-dsl http://beta.quicklisp.org/archive/cl-dsl/2013-07-20/cl-dsl-20130720-git.tgz 14073 fce58e9d8682e3224120cc794922de84 a93b21d4833d1d92609d2399028cbba3e908cbbf cl-dsl-20130720-git cl-dsl.asd +cl-durian http://beta.quicklisp.org/archive/cl-durian/2015-06-08/cl-durian-20150608-git.tgz 4819 9da8dd551e1ee63907a79bea0b1565d3 a0ca0ed4bf0257b86270d66bda9a963d0d30529b cl-durian-20150608-git cl-durian.asd +cl-ecma-48 http://beta.quicklisp.org/archive/cl-ecma-48/2019-10-08/cl-ecma-48-20191008-http.tgz 22772 96f3b42f0e84f9743c5894e6b61e1e61 1d35c8d4bf7dfebe48f449b3a47116e2b7a1402b cl-ecma-48-20191008-http cl-ecma-48.asd +cl-editdistance http://beta.quicklisp.org/archive/cl-editdistance/2019-11-30/cl-editdistance-20191130-git.tgz 11143 a3daec92c5fb9595cec446bfa494ddfc d2c99d886ba1b4febe00a07cd7fa247ea44014c3 cl-editdistance-20191130-git edit-distance-test.asd edit-distance.asd +cl-egl http://beta.quicklisp.org/archive/cl-egl/2019-05-21/cl-egl-20190521-git.tgz 3064 022f1ac3d01a265e700d0aa99ff47d71 03446e74bcaa71e61d1f0e9352c9df99ad3ad403 cl-egl-20190521-git cl-egl.asd +cl-elastic http://beta.quicklisp.org/archive/cl-elastic/2019-11-30/cl-elastic-20191130-git.tgz 5445 f41cde9363a8de98bc677f978a4a76d8 59dcbf6275515d52e7ba4f48bfbdc80fb87eaece cl-elastic-20191130-git cl-elastic-test.asd cl-elastic.asd +cl-emacs-if http://beta.quicklisp.org/archive/cl-emacs-if/2012-03-05/cl-emacs-if-20120305-git.tgz 5080 79a7e7ed0dce7b6b937481da97bc5490 3328115dfa0afe358d2301ce9d0335fb323b7b3f cl-emacs-if-20120305-git cl-emacs-if.asd +cl-emb http://beta.quicklisp.org/archive/cl-emb/2019-05-21/cl-emb-20190521-git.tgz 14557 b27bbe8de2206ab7c461700b58d4d527 04a32481580be674abe707cdfd25f20ff710ac7a cl-emb-20190521-git cl-emb.asd +cl-emoji http://beta.quicklisp.org/archive/cl-emoji/2018-02-28/cl-emoji-20180228-git.tgz 130741 28944d5548ea7fb8a591c1f732edd538 fcaf8cb10f53a4155d3a96a9a3e41356c7fa33d1 cl-emoji-20180228-git cl-emoji-test.asd cl-emoji.asd +cl-enchant http://beta.quicklisp.org/archive/cl-enchant/2019-05-21/cl-enchant-20190521-git.tgz 8136 2a868c280fd5a74f9c298c384567e31b 724cc1533724de27d433c210bd63db8a65ecbdf4 cl-enchant-20190521-git enchant-autoload.asd enchant.asd +cl-enumeration http://beta.quicklisp.org/archive/cl-enumeration/2019-07-10/cl-enumeration-20190710-git.tgz 116101 d7f838b9f923cb925966a4cbc44453e4 8450c2282e83778407a297fb5510c5c32cd83468 cl-enumeration-20190710-git enumerations.asd +cl-env http://beta.quicklisp.org/archive/cl-env/2018-04-30/cl-env-20180430-git.tgz 2808 881867f2aee6a8f22acb2dc1db3b5a62 d79b84e8739451c189fa50a6df245db1d4dd0953 cl-env-20180430-git cl-env.asd +cl-environments http://beta.quicklisp.org/archive/cl-environments/2019-11-30/cl-environments-20191130-git.tgz 39644 b7b04131bb799a90c087eba6644f2e7c 47cbb62c93757d781167d60ad398a3d03346d789 cl-environments-20191130-git cl-environments.asd +cl-epmd http://beta.quicklisp.org/archive/cl-epmd/2014-02-11/cl-epmd-20140211-git.tgz 8497 535d47c3fdcbf90656549f48da838151 1e5e823a18ae86b707ebfae97acd4af7a31ef36e cl-epmd-20140211-git epmd-test.asd epmd.asd +cl-epoch http://beta.quicklisp.org/archive/cl-epoch/2018-12-10/cl-epoch-20181210-git.tgz 772 677d6391a0c4ae9b20e4115cb0681706 3266833985cfc3447642de88f2b808fd0e25d222 cl-epoch-20181210-git cl-epoch.asd +cl-erlang-term http://beta.quicklisp.org/archive/cl-erlang-term/2016-05-31/cl-erlang-term-20160531-git.tgz 19973 fb58d27f4aba01da6e4677ef8a1e4fff 65583551c5793e1c22f20414a65548043814608d cl-erlang-term-20160531-git erlang-term-optima.asd erlang-term-test.asd erlang-term.asd +cl-ev http://beta.quicklisp.org/archive/cl-ev/2015-09-23/cl-ev-20150923-git.tgz 6322 802c3966a9dbd25d22407825271e70fd d90c2e7c18e3710e25ecd2206430926dc4307891 cl-ev-20150923-git ev.asd +cl-events http://beta.quicklisp.org/archive/cl-events/2016-03-18/cl-events-20160318-git.tgz 7199 064df9efa3a6db5b1540d61a91671ca8 21f4cb9f76b3ffd12d7b6d5d17e0960cd8b57819 cl-events-20160318-git cl-events.asd cl-events.test.asd +cl-ewkb http://beta.quicklisp.org/archive/cl-ewkb/2011-06-19/cl-ewkb-20110619-git.tgz 9929 cbcc96a62750e5aee99f2261d4b2171c 262f1978c053c76a4fa288411f8fbd150d29fcbb cl-ewkb-20110619-git cl-ewkb.asd +cl-factoring http://beta.quicklisp.org/archive/cl-factoring/2018-04-30/cl-factoring-20180430-git.tgz 22615 d394be277a6a2639cf86f4547b31e959 773a33d4c38725d5eb0282dc64e2c880c48c38a5 cl-factoring-20180430-git cl-factoring-test.asd cl-factoring.asd +cl-fad http://beta.quicklisp.org/archive/cl-fad/2019-08-13/cl-fad-20190813-git.tgz 24659 7d0405b44fefccb8a807527249ee2700 06a84a76e539e6168fa868abd403ab036892857d cl-fad-20190813-git cl-fad.asd +cl-fam http://beta.quicklisp.org/archive/cl-fam/2012-11-25/cl-fam-20121125-git.tgz 8597 4844d1092223363858a0963b56b09d10 9def84e89f75f5d2449f31db352fc1d6d51c156a cl-fam-20121125-git cl-fam.asd +cl-fastcgi http://beta.quicklisp.org/archive/cl-fastcgi/2019-12-27/cl-fastcgi-20191227-git.tgz 3728 ad0d29720060f795dfb4270d3deb554a 600c0a050de8293f0af7570abcf6c248bf5da8c5 cl-fastcgi-20191227-git cl-fastcgi.asd +cl-fbclient http://beta.quicklisp.org/archive/cl-fbclient/2014-01-13/cl-fbclient-20140113-git.tgz 9685 48d0afd4a519cac7c0b219063d51f6d9 09f3e78c416b6524ebe3c2d75e279eeda08b2277 cl-fbclient-20140113-git cl-fbclient.asd +cl-feedparser http://beta.quicklisp.org/archive/cl-feedparser/2019-07-10/cl-feedparser-20190710-git.tgz 1144159 fbb3d704161400b6fa1d59a067a21e01 ccece16e6ca4b553ce6425e08a33c2ed5c511a1d cl-feedparser-20190710-git cl-feedparser.asd test/cl-feedparser-tests.asd +cl-fixtures http://beta.quicklisp.org/archive/cl-fixtures/2018-04-30/cl-fixtures-20180430-git.tgz 13986 5c3e871d243c4de04b35953c252d05c4 6a159febf5270b88ef432027547a9aa2ce0b8f5c cl-fixtures-20180430-git cl-fixtures-test.asd cl-fixtures.asd +cl-flac http://beta.quicklisp.org/archive/cl-flac/2019-07-10/cl-flac-20190710-git.tgz 290402 a987ae59d6785b72735a7a102cbc9907 399983a24191cc0bc3e9657d3b4ba3bb0c9d6142 cl-flac-20190710-git cl-flac.asd +cl-flat-tree http://beta.quicklisp.org/archive/cl-flat-tree/2019-08-13/cl-flat-tree-20190813-git.tgz 5132 8705ad941f264bdedb08e4a1ad6afcfb 3f0fb91a38e4246e34d9a76d4c1dddb4515063b5 cl-flat-tree-20190813-git flat-tree.asd +cl-flow http://beta.quicklisp.org/archive/cl-flow/2018-08-31/cl-flow-stable-778a219a-git.tgz 5227 821e95bb7e4a43c42e7c581faf4bb7df f4c311f389d822e5b87d20cab264111eae5c056a cl-flow-stable-778a219a-git cl-flow.asd +cl-flowd http://beta.quicklisp.org/archive/cl-flowd/2014-07-13/cl-flowd-20140713-git.tgz 5753 c8ec0147510ab231d0e3377beaf5f897 b5382880a7203fb47f6d55b6b587a5645eb2322e cl-flowd-20140713-git cl-flowd.asd +cl-fluent-logger http://beta.quicklisp.org/archive/cl-fluent-logger/2019-02-02/cl-fluent-logger-20190202-git.tgz 4829 db5f23548d9f4c7c93375456cc12ba6a 4c8b44df1de4e803896bdfe72c55b3f5995738de cl-fluent-logger-20190202-git cl-fluent-logger.asd +cl-fluidinfo http://beta.quicklisp.org/archive/cl-fluidinfo/2013-03-12/cl-fluidinfo-20130312-git.tgz 8963 31baff1a738ad8dcf30b4f466d71366c 0c8485eba076578d271d6190ba75dd853ad5867c cl-fluidinfo-20130312-git cl-fluiddb-test.asd cl-fluiddb.asd cl-fluidinfo.asd +cl-fond http://beta.quicklisp.org/archive/cl-fond/2019-11-30/cl-fond-20191130-git.tgz 328112 15c6094682447b9bc49bfa253a064360 df52e6e1d9515e749da9cca6ee1e54d378153ea3 cl-fond-20191130-git cl-fond.asd +cl-forms http://beta.quicklisp.org/archive/cl-forms/2019-07-10/cl-forms-20190710-git.tgz 841887 6945c01e82db6c989baf74c9b93ed8ac 424fb61fa9483e85d15b977c79c5ea6a33dd0166 cl-forms-20190710-git cl-forms.asd cl-forms.demo.asd cl-forms.djula.asd cl-forms.test.asd cl-forms.who.asd +cl-freeimage http://beta.quicklisp.org/archive/cl-freeimage/2017-04-03/cl-freeimage-20170403-git.tgz 10611 92c8fff7a488a73ff5793f43145cb641 ca94e56e0a67d03b054160c6a78c705b0172f14d cl-freeimage-20170403-git cl-freeimage.asd +cl-freetype2 http://beta.quicklisp.org/archive/cl-freetype2/2019-10-07/cl-freetype2-20191007-git.tgz 43368 0d4482c5201de0ff9b959deac59d1d25 ca147fa768c83e540583b780d38067bec7314d48 cl-freetype2-20191007-git cl-freetype2-tests.asd cl-freetype2.asd +cl-fsnotify http://beta.quicklisp.org/archive/cl-fsnotify/2015-03-02/cl-fsnotify-20150302-git.tgz 5979 54fe23d75d2baa6f404aef9c4da39449 6a6f82a1fc13f6286e1e9ae071e4a827830192d4 cl-fsnotify-20150302-git cl-fsnotify.asd +cl-ftp http://beta.quicklisp.org/archive/cl-ftp/2015-06-08/cl-ftp-20150608-http.tgz 9367 0743157a9fe2eea7c4a3a79874df1d55 e2ffb352da8b73a6895499ab6a1c1004e8bc5198 cl-ftp-20150608-http cl-ftp.asd ftp.asd +cl-fuse http://beta.quicklisp.org/archive/cl-fuse/2019-12-27/cl-fuse-20191227-git.tgz 23534 3c6f85db7797a2890d8303d11595100d 632def3847f0cff4ed2cc39ccbdeabb69e39802d cl-fuse-20191227-git cl-fuse.asd +cl-fuse-meta-fs http://beta.quicklisp.org/archive/cl-fuse-meta-fs/2019-07-10/cl-fuse-meta-fs-20190710-git.tgz 16844 461f7023274fb273e6c759e881bdd636 ab7279115b939e7a1d701d8d74538109313db2dc cl-fuse-meta-fs-20190710-git cl-fuse-meta-fs.asd +cl-fuzz http://beta.quicklisp.org/archive/cl-fuzz/2018-10-18/cl-fuzz-20181018-git.tgz 4141 22e715b370ea886bbff1e09db20c4e32 bd6ff387648fcf0c47266b2be40c7214b6e84bb3 cl-fuzz-20181018-git cl-fuzz.asd +cl-gambol http://beta.quicklisp.org/archive/cl-gambol/2016-03-18/cl-gambol-20160318-git.tgz 14886 887b54fee9fa3d77865a3eb3caaeac3e 5e9f5015bb42df0d9c70be356ce15dbec537c295 cl-gambol-20160318-git gambol.asd +cl-gamepad http://beta.quicklisp.org/archive/cl-gamepad/2019-07-10/cl-gamepad-20190710-git.tgz 107573 28a21a3aff9d9ad530fe9b69257cd72a 501a2372777fc5a55a723b1316c964e09a5494c5 cl-gamepad-20190710-git cl-gamepad-visualizer.asd cl-gamepad.asd +cl-gap-buffer http://beta.quicklisp.org/archive/cl-gap-buffer/2019-03-07/cl-gap-buffer-20190307-hg.tgz 4587 48de07c260d666659464734743de3646 05aa46f3548f072197a6e75c075b1b8ae60d15f7 cl-gap-buffer-20190307-hg cl-gap-buffer.asd +cl-gbm http://beta.quicklisp.org/archive/cl-gbm/2018-04-30/cl-gbm-20180430-git.tgz 2187 d5f7e5c5d37248986d4a882b44ac43a9 b504515681fb74f54f2e0c3dd4e05226a72ae03c cl-gbm-20180430-git cl-gbm.asd +cl-gd http://beta.quicklisp.org/archive/cl-gd/2017-11-30/cl-gd-20171130-git.tgz 203897 eef761d6507da1576b60da09f49d1dbb f8918ce5cc783b2474d73fc19a600644ae5b0f5b cl-gd-20171130-git cl-gd-test.asd cl-gd.asd +cl-gdata http://beta.quicklisp.org/archive/cl-gdata/2017-11-30/cl-gdata-20171130-git.tgz 31765 94763ae151858d354d5e9d8af3bdc538 cbcb9f87b27846e757bf70cf5cea38394ec414d4 cl-gdata-20171130-git cl-gdata.asd +cl-gearman http://beta.quicklisp.org/archive/cl-gearman/2015-09-23/cl-gearman-20150923-git.tgz 7680 6d7496a301f9cbb2d69e16bea12e2760 b39af5a987148d2492c7f85d0b58ae67b97b6f61 cl-gearman-20150923-git cl-gearman-test.asd cl-gearman.asd +cl-gendoc http://beta.quicklisp.org/archive/cl-gendoc/2018-08-31/cl-gendoc-20180831-git.tgz 6187 f74903585bca304a72b9739261c5c980 c0b1fec403200e417008b960c5ddbb6bb6bc9f53 cl-gendoc-20180831-git cl-gendoc.asd +cl-gene-searcher http://beta.quicklisp.org/archive/cl-gene-searcher/2011-10-01/cl-gene-searcher-20111001-git.tgz 3309 1350073f7965574a146421e59533bb00 35abc2a2a5b5091f0bb821269bfc6980260ed1fa cl-gene-searcher-20111001-git cl-gene-searcher.asd +cl-general-accumulator http://beta.quicklisp.org/archive/cl-general-accumulator/2019-05-21/cl-general-accumulator-20190521-git.tgz 5408 a60a9c5cff36fd49591f3f4cfd8c1cfd f68acdcdf203c36c6ed525bffd8884a59d3a931f cl-general-accumulator-20190521-git general-accumulator.asd +cl-generator http://beta.quicklisp.org/archive/cl-generator/2019-03-07/cl-generator-20190307-git.tgz 4308 e5ea88e49ed25ffacc11cdab4c6d77f6 5f7b67551d6628ea14667d8a54e95368016e1adb cl-generator-20190307-git cl-generator-test.asd cl-generator.asd +cl-generic-arithmetic http://beta.quicklisp.org/archive/cl-generic-arithmetic/2019-03-07/cl-generic-arithmetic-20190307-hg.tgz 5684 66225b9a7b00a5c36c86e8ae35002dfc 918705d37a97aff0cd98b31066b1b799a166407f cl-generic-arithmetic-20190307-hg cl-generic-arithmetic.asd +cl-geocode http://beta.quicklisp.org/archive/cl-geocode/2019-08-13/cl-geocode-20190813-git.tgz 583489 9c5dea4fa9d4d25ecb5a12d58ca518d3 a6b99dd47185ed88a289271cc668ba1c6d5a9961 cl-geocode-20190813-git cl-geocode.asd +cl-geoip http://beta.quicklisp.org/archive/cl-geoip/2013-06-15/cl-geoip-20130615-git.tgz 1698 2d174e9d08cead4ae9a320273c332844 08916ca6c4253b06adce2a03210916935d88e797 cl-geoip-20130615-git cl-geoip.asd +cl-geometry http://beta.quicklisp.org/archive/cl-geometry/2016-05-31/cl-geometry-20160531-git.tgz 17003 c0aaccbb4e2df6c504e6c1cd15155353 940f33dadfdfc8be044a94b0166ad99b29893865 cl-geometry-20160531-git cl-geometry-tests.asd cl-geometry.asd +cl-geos http://beta.quicklisp.org/archive/cl-geos/2018-07-11/cl-geos-20180711-git.tgz 18007 087b13649ed86240dead36394b5fea89 a32b0710b2ab3febb1af0fccec6a9e294675abb3 cl-geos-20180711-git cl-geos.asd +cl-gimei http://beta.quicklisp.org/archive/cl-gimei/2018-03-28/cl-gimei-20180328-git.tgz 148851 14be1ab4a8a88f11d8ad44c14f66a57b e1115122633adac652992deb4777015ed62f9444 cl-gimei-20180328-git cl-gimei.asd +cl-gists http://beta.quicklisp.org/archive/cl-gists/2018-02-28/cl-gists-20180228-git.tgz 10807 adbd22dbdccd05776ad5589add0983b8 1d8c375299852e4a7de3e5495eaa066147cb445d cl-gists-20180228-git cl-gists-test.asd cl-gists.asd +cl-git http://beta.quicklisp.org/archive/cl-git/2015-07-09/cl-git-20150709-git.tgz 60507 cbe03f1b837c775729c0b66fa707577f c3e37ce1e8437f76664b6779bd35b40b9485a8b4 cl-git-20150709-git cl-git.asd +cl-github-v3 http://beta.quicklisp.org/archive/cl-github-v3/2019-12-27/cl-github-v3-20191227-git.tgz 2857 e116ddd20a76120573acfe6583c24cb3 353704ab1cf6849d9e4a12e9e0f4dfb9c99d2135 cl-github-v3-20191227-git cl-github-v3.asd +cl-glfw http://beta.quicklisp.org/archive/cl-glfw/2015-03-02/cl-glfw-20150302-git.tgz 461048 c939bd97538b254d445f4b0904bbb8fa 03b779d59b8807cc72bdc2a5d407a393f24fa7fd cl-glfw-20150302-git cl-glfw-ftgl.asd cl-glfw-glu.asd cl-glfw-opengl-core.asd cl-glfw-opengl-version_1_0.asd cl-glfw-opengl-version_1_1.asd cl-glfw-opengl-version_1_2.asd cl-glfw-opengl-version_1_3.asd cl-glfw-opengl-version_1_4.asd cl-glfw-opengl-version_1_5.asd cl-glfw-opengl-version_2_0.asd cl-glfw-opengl-version_2_1.asd cl-glfw-types.asd cl-glfw.asd lib/cl-glfw-opengl-3dfx_multisample.asd lib/cl-glfw-opengl-3dfx_tbuffer.asd lib/cl-glfw-opengl-3dfx_texture_compression_fxt1.asd lib/cl-glfw-opengl-amd_blend_minmax_factor.asd lib/cl-glfw-opengl-amd_depth_clamp_separate.asd lib/cl-glfw-opengl-amd_draw_buffers_blend.asd lib/cl-glfw-opengl-amd_multi_draw_indirect.asd lib/cl-glfw-opengl-amd_name_gen_delete.asd lib/cl-glfw-opengl-amd_performance_monitor.asd lib/cl-glfw-opengl-amd_sample_positions.asd lib/cl-glfw-opengl-amd_seamless_cubemap_per_texture.asd lib/cl-glfw-opengl-amd_vertex_shader_tesselator.asd lib/cl-glfw-opengl-apple_aux_depth_stencil.asd lib/cl-glfw-opengl-apple_client_storage.asd lib/cl-glfw-opengl-apple_element_array.asd lib/cl-glfw-opengl-apple_fence.asd lib/cl-glfw-opengl-apple_float_pixels.asd lib/cl-glfw-opengl-apple_flush_buffer_range.asd lib/cl-glfw-opengl-apple_object_purgeable.asd lib/cl-glfw-opengl-apple_rgb_422.asd lib/cl-glfw-opengl-apple_row_bytes.asd lib/cl-glfw-opengl-apple_specular_vector.asd lib/cl-glfw-opengl-apple_texture_range.asd lib/cl-glfw-opengl-apple_transform_hint.asd lib/cl-glfw-opengl-apple_vertex_array_object.asd lib/cl-glfw-opengl-apple_vertex_array_range.asd lib/cl-glfw-opengl-apple_vertex_program_evaluators.asd lib/cl-glfw-opengl-apple_ycbcr_422.asd lib/cl-glfw-opengl-arb_blend_func_extended.asd lib/cl-glfw-opengl-arb_color_buffer_float.asd lib/cl-glfw-opengl-arb_copy_buffer.asd lib/cl-glfw-opengl-arb_depth_buffer_float.asd lib/cl-glfw-opengl-arb_depth_clamp.asd lib/cl-glfw-opengl-arb_depth_texture.asd lib/cl-glfw-opengl-arb_draw_buffers.asd lib/cl-glfw-opengl-arb_draw_buffers_blend.asd lib/cl-glfw-opengl-arb_draw_elements_base_vertex.asd lib/cl-glfw-opengl-arb_draw_indirect.asd lib/cl-glfw-opengl-arb_draw_instanced.asd lib/cl-glfw-opengl-arb_es2_compatibility.asd lib/cl-glfw-opengl-arb_fragment_program.asd lib/cl-glfw-opengl-arb_fragment_shader.asd lib/cl-glfw-opengl-arb_framebuffer_object.asd lib/cl-glfw-opengl-arb_framebuffer_object_deprecated.asd lib/cl-glfw-opengl-arb_framebuffer_srgb.asd lib/cl-glfw-opengl-arb_geometry_shader4.asd lib/cl-glfw-opengl-arb_get_program_binary.asd lib/cl-glfw-opengl-arb_gpu_shader5.asd lib/cl-glfw-opengl-arb_gpu_shader_fp64.asd lib/cl-glfw-opengl-arb_half_float_pixel.asd lib/cl-glfw-opengl-arb_half_float_vertex.asd lib/cl-glfw-opengl-arb_imaging.asd lib/cl-glfw-opengl-arb_imaging_deprecated.asd lib/cl-glfw-opengl-arb_instanced_arrays.asd lib/cl-glfw-opengl-arb_map_buffer_range.asd lib/cl-glfw-opengl-arb_matrix_palette.asd lib/cl-glfw-opengl-arb_multisample.asd lib/cl-glfw-opengl-arb_multitexture.asd lib/cl-glfw-opengl-arb_occlusion_query.asd lib/cl-glfw-opengl-arb_occlusion_query2.asd lib/cl-glfw-opengl-arb_pixel_buffer_object.asd lib/cl-glfw-opengl-arb_point_parameters.asd lib/cl-glfw-opengl-arb_point_sprite.asd lib/cl-glfw-opengl-arb_provoking_vertex.asd lib/cl-glfw-opengl-arb_robustness.asd lib/cl-glfw-opengl-arb_sample_shading.asd lib/cl-glfw-opengl-arb_sampler_objects.asd lib/cl-glfw-opengl-arb_seamless_cube_map.asd lib/cl-glfw-opengl-arb_separate_shader_objects.asd lib/cl-glfw-opengl-arb_shader_objects.asd lib/cl-glfw-opengl-arb_shader_subroutine.asd lib/cl-glfw-opengl-arb_shading_language_100.asd lib/cl-glfw-opengl-arb_shading_language_include.asd lib/cl-glfw-opengl-arb_shadow.asd lib/cl-glfw-opengl-arb_shadow_ambient.asd lib/cl-glfw-opengl-arb_tessellation_shader.asd lib/cl-glfw-opengl-arb_texture_border_clamp.asd lib/cl-glfw-opengl-arb_texture_buffer_object.asd lib/cl-glfw-opengl-arb_texture_buffer_object_rgb32.asd lib/cl-glfw-opengl-arb_texture_compression.asd lib/cl-glfw-opengl-arb_texture_compression_bptc.asd lib/cl-glfw-opengl-arb_texture_compression_rgtc.asd lib/cl-glfw-opengl-arb_texture_cube_map.asd lib/cl-glfw-opengl-arb_texture_cube_map_array.asd lib/cl-glfw-opengl-arb_texture_env_combine.asd lib/cl-glfw-opengl-arb_texture_env_dot3.asd lib/cl-glfw-opengl-arb_texture_float.asd lib/cl-glfw-opengl-arb_texture_gather.asd lib/cl-glfw-opengl-arb_texture_mirrored_repeat.asd lib/cl-glfw-opengl-arb_texture_multisample.asd lib/cl-glfw-opengl-arb_texture_rectangle.asd lib/cl-glfw-opengl-arb_texture_rg.asd lib/cl-glfw-opengl-arb_texture_rgb10_a2ui.asd lib/cl-glfw-opengl-arb_texture_swizzle.asd lib/cl-glfw-opengl-arb_timer_query.asd lib/cl-glfw-opengl-arb_transform_feedback2.asd lib/cl-glfw-opengl-arb_transpose_matrix.asd lib/cl-glfw-opengl-arb_uniform_buffer_object.asd lib/cl-glfw-opengl-arb_vertex_array_bgra.asd lib/cl-glfw-opengl-arb_vertex_array_object.asd lib/cl-glfw-opengl-arb_vertex_attrib_64bit.asd lib/cl-glfw-opengl-arb_vertex_blend.asd lib/cl-glfw-opengl-arb_vertex_buffer_object.asd lib/cl-glfw-opengl-arb_vertex_program.asd lib/cl-glfw-opengl-arb_vertex_shader.asd lib/cl-glfw-opengl-arb_vertex_type_2_10_10_10_rev.asd lib/cl-glfw-opengl-arb_viewport_array.asd lib/cl-glfw-opengl-arb_window_pos.asd lib/cl-glfw-opengl-ati_draw_buffers.asd lib/cl-glfw-opengl-ati_element_array.asd lib/cl-glfw-opengl-ati_envmap_bumpmap.asd lib/cl-glfw-opengl-ati_fragment_shader.asd lib/cl-glfw-opengl-ati_map_object_buffer.asd lib/cl-glfw-opengl-ati_meminfo.asd lib/cl-glfw-opengl-ati_pixel_format_float.asd lib/cl-glfw-opengl-ati_pn_triangles.asd lib/cl-glfw-opengl-ati_separate_stencil.asd lib/cl-glfw-opengl-ati_text_fragment_shader.asd lib/cl-glfw-opengl-ati_texture_env_combine3.asd lib/cl-glfw-opengl-ati_texture_float.asd lib/cl-glfw-opengl-ati_texture_mirror_once.asd lib/cl-glfw-opengl-ati_vertex_array_object.asd lib/cl-glfw-opengl-ati_vertex_attrib_array_object.asd lib/cl-glfw-opengl-ati_vertex_streams.asd lib/cl-glfw-opengl-ext_422_pixels.asd lib/cl-glfw-opengl-ext_abgr.asd lib/cl-glfw-opengl-ext_bgra.asd lib/cl-glfw-opengl-ext_bindable_uniform.asd lib/cl-glfw-opengl-ext_blend_color.asd lib/cl-glfw-opengl-ext_blend_equation_separate.asd lib/cl-glfw-opengl-ext_blend_func_separate.asd lib/cl-glfw-opengl-ext_blend_minmax.asd lib/cl-glfw-opengl-ext_blend_subtract.asd lib/cl-glfw-opengl-ext_clip_volume_hint.asd lib/cl-glfw-opengl-ext_cmyka.asd lib/cl-glfw-opengl-ext_color_subtable.asd lib/cl-glfw-opengl-ext_compiled_vertex_array.asd lib/cl-glfw-opengl-ext_convolution.asd lib/cl-glfw-opengl-ext_coordinate_frame.asd lib/cl-glfw-opengl-ext_copy_texture.asd lib/cl-glfw-opengl-ext_cull_vertex.asd lib/cl-glfw-opengl-ext_depth_bounds_test.asd lib/cl-glfw-opengl-ext_direct_state_access.asd lib/cl-glfw-opengl-ext_draw_buffers2.asd lib/cl-glfw-opengl-ext_draw_instanced.asd lib/cl-glfw-opengl-ext_draw_range_elements.asd lib/cl-glfw-opengl-ext_fog_coord.asd lib/cl-glfw-opengl-ext_framebuffer_blit.asd lib/cl-glfw-opengl-ext_framebuffer_multisample.asd lib/cl-glfw-opengl-ext_framebuffer_object.asd lib/cl-glfw-opengl-ext_framebuffer_srgb.asd lib/cl-glfw-opengl-ext_geometry_shader4.asd lib/cl-glfw-opengl-ext_gpu_program_parameters.asd lib/cl-glfw-opengl-ext_gpu_shader4.asd lib/cl-glfw-opengl-ext_histogram.asd lib/cl-glfw-opengl-ext_index_array_formats.asd lib/cl-glfw-opengl-ext_index_func.asd lib/cl-glfw-opengl-ext_index_material.asd lib/cl-glfw-opengl-ext_light_texture.asd lib/cl-glfw-opengl-ext_multi_draw_arrays.asd lib/cl-glfw-opengl-ext_multisample.asd lib/cl-glfw-opengl-ext_packed_depth_stencil.asd lib/cl-glfw-opengl-ext_packed_float.asd lib/cl-glfw-opengl-ext_packed_pixels.asd lib/cl-glfw-opengl-ext_paletted_texture.asd lib/cl-glfw-opengl-ext_pixel_buffer_object.asd lib/cl-glfw-opengl-ext_pixel_transform.asd lib/cl-glfw-opengl-ext_point_parameters.asd lib/cl-glfw-opengl-ext_polygon_offset.asd lib/cl-glfw-opengl-ext_provoking_vertex.asd lib/cl-glfw-opengl-ext_secondary_color.asd lib/cl-glfw-opengl-ext_separate_shader_objects.asd lib/cl-glfw-opengl-ext_separate_specular_color.asd lib/cl-glfw-opengl-ext_shader_image_load_store.asd lib/cl-glfw-opengl-ext_stencil_clear_tag.asd lib/cl-glfw-opengl-ext_stencil_two_side.asd lib/cl-glfw-opengl-ext_stencil_wrap.asd lib/cl-glfw-opengl-ext_subtexture.asd lib/cl-glfw-opengl-ext_texture.asd lib/cl-glfw-opengl-ext_texture3d.asd lib/cl-glfw-opengl-ext_texture_array.asd lib/cl-glfw-opengl-ext_texture_buffer_object.asd lib/cl-glfw-opengl-ext_texture_compression_latc.asd lib/cl-glfw-opengl-ext_texture_compression_rgtc.asd lib/cl-glfw-opengl-ext_texture_compression_s3tc.asd lib/cl-glfw-opengl-ext_texture_cube_map.asd lib/cl-glfw-opengl-ext_texture_env_combine.asd lib/cl-glfw-opengl-ext_texture_env_dot3.asd lib/cl-glfw-opengl-ext_texture_filter_anisotropic.asd lib/cl-glfw-opengl-ext_texture_integer.asd lib/cl-glfw-opengl-ext_texture_lod_bias.asd lib/cl-glfw-opengl-ext_texture_mirror_clamp.asd lib/cl-glfw-opengl-ext_texture_object.asd lib/cl-glfw-opengl-ext_texture_perturb_normal.asd lib/cl-glfw-opengl-ext_texture_shared_exponent.asd lib/cl-glfw-opengl-ext_texture_snorm.asd lib/cl-glfw-opengl-ext_texture_srgb.asd lib/cl-glfw-opengl-ext_texture_srgb_decode.asd lib/cl-glfw-opengl-ext_texture_swizzle.asd lib/cl-glfw-opengl-ext_timer_query.asd lib/cl-glfw-opengl-ext_transform_feedback.asd lib/cl-glfw-opengl-ext_vertex_array.asd lib/cl-glfw-opengl-ext_vertex_array_bgra.asd lib/cl-glfw-opengl-ext_vertex_attrib_64bit.asd lib/cl-glfw-opengl-ext_vertex_shader.asd lib/cl-glfw-opengl-ext_vertex_weighting.asd lib/cl-glfw-opengl-gremedy_frame_terminator.asd lib/cl-glfw-opengl-gremedy_string_marker.asd lib/cl-glfw-opengl-hp_convolution_border_modes.asd lib/cl-glfw-opengl-hp_image_transform.asd lib/cl-glfw-opengl-hp_occlusion_test.asd lib/cl-glfw-opengl-hp_texture_lighting.asd lib/cl-glfw-opengl-ibm_cull_vertex.asd lib/cl-glfw-opengl-ibm_multimode_draw_arrays.asd lib/cl-glfw-opengl-ibm_rasterpos_clip.asd lib/cl-glfw-opengl-ibm_texture_mirrored_repeat.asd lib/cl-glfw-opengl-ibm_vertex_array_lists.asd lib/cl-glfw-opengl-ingr_blend_func_separate.asd lib/cl-glfw-opengl-ingr_color_clamp.asd lib/cl-glfw-opengl-ingr_interlace_read.asd lib/cl-glfw-opengl-intel_parallel_arrays.asd lib/cl-glfw-opengl-mesa_pack_invert.asd lib/cl-glfw-opengl-mesa_packed_depth_stencil.asd lib/cl-glfw-opengl-mesa_program_debug.asd lib/cl-glfw-opengl-mesa_resize_buffers.asd lib/cl-glfw-opengl-mesa_shader_debug.asd lib/cl-glfw-opengl-mesa_trace.asd lib/cl-glfw-opengl-mesa_window_pos.asd lib/cl-glfw-opengl-mesa_ycbcr_texture.asd lib/cl-glfw-opengl-mesax_texture_stack.asd lib/cl-glfw-opengl-nv_conditional_render.asd lib/cl-glfw-opengl-nv_copy_depth_to_color.asd lib/cl-glfw-opengl-nv_copy_image.asd lib/cl-glfw-opengl-nv_depth_buffer_float.asd lib/cl-glfw-opengl-nv_depth_clamp.asd lib/cl-glfw-opengl-nv_evaluators.asd lib/cl-glfw-opengl-nv_explicit_multisample.asd lib/cl-glfw-opengl-nv_fence.asd lib/cl-glfw-opengl-nv_float_buffer.asd lib/cl-glfw-opengl-nv_fog_distance.asd lib/cl-glfw-opengl-nv_fragment_program.asd lib/cl-glfw-opengl-nv_fragment_program2.asd lib/cl-glfw-opengl-nv_framebuffer_multisample_coverage.asd lib/cl-glfw-opengl-nv_geometry_program4.asd lib/cl-glfw-opengl-nv_gpu_program4.asd lib/cl-glfw-opengl-nv_gpu_program5.asd lib/cl-glfw-opengl-nv_gpu_shader5.asd lib/cl-glfw-opengl-nv_half_float.asd lib/cl-glfw-opengl-nv_light_max_exponent.asd lib/cl-glfw-opengl-nv_multisample_coverage.asd lib/cl-glfw-opengl-nv_multisample_filter_hint.asd lib/cl-glfw-opengl-nv_occlusion_query.asd lib/cl-glfw-opengl-nv_packed_depth_stencil.asd lib/cl-glfw-opengl-nv_parameter_buffer_object.asd lib/cl-glfw-opengl-nv_pixel_data_range.asd lib/cl-glfw-opengl-nv_point_sprite.asd lib/cl-glfw-opengl-nv_present_video.asd lib/cl-glfw-opengl-nv_primitive_restart.asd lib/cl-glfw-opengl-nv_register_combiners.asd lib/cl-glfw-opengl-nv_register_combiners2.asd lib/cl-glfw-opengl-nv_shader_buffer_load.asd lib/cl-glfw-opengl-nv_shader_buffer_store.asd lib/cl-glfw-opengl-nv_tessellation_program5.asd lib/cl-glfw-opengl-nv_texgen_emboss.asd lib/cl-glfw-opengl-nv_texgen_reflection.asd lib/cl-glfw-opengl-nv_texture_barrier.asd lib/cl-glfw-opengl-nv_texture_env_combine4.asd lib/cl-glfw-opengl-nv_texture_expand_normal.asd lib/cl-glfw-opengl-nv_texture_multisample.asd lib/cl-glfw-opengl-nv_texture_rectangle.asd lib/cl-glfw-opengl-nv_texture_shader.asd lib/cl-glfw-opengl-nv_texture_shader2.asd lib/cl-glfw-opengl-nv_texture_shader3.asd lib/cl-glfw-opengl-nv_transform_feedback.asd lib/cl-glfw-opengl-nv_transform_feedback2.asd lib/cl-glfw-opengl-nv_vertex_array_range.asd lib/cl-glfw-opengl-nv_vertex_array_range2.asd lib/cl-glfw-opengl-nv_vertex_attrib_integer_64bit.asd lib/cl-glfw-opengl-nv_vertex_buffer_unified_memory.asd lib/cl-glfw-opengl-nv_vertex_program.asd lib/cl-glfw-opengl-nv_vertex_program2_option.asd lib/cl-glfw-opengl-nv_vertex_program3.asd lib/cl-glfw-opengl-nv_vertex_program4.asd lib/cl-glfw-opengl-oes_read_format.asd lib/cl-glfw-opengl-oml_interlace.asd lib/cl-glfw-opengl-oml_resample.asd lib/cl-glfw-opengl-oml_subsample.asd lib/cl-glfw-opengl-pgi_misc_hints.asd lib/cl-glfw-opengl-pgi_vertex_hints.asd lib/cl-glfw-opengl-rend_screen_coordinates.asd lib/cl-glfw-opengl-s3_s3tc.asd lib/cl-glfw-opengl-sgi_color_table.asd lib/cl-glfw-opengl-sgi_depth_pass_instrument.asd lib/cl-glfw-opengl-sgis_detail_texture.asd lib/cl-glfw-opengl-sgis_fog_function.asd lib/cl-glfw-opengl-sgis_multisample.asd lib/cl-glfw-opengl-sgis_pixel_texture.asd lib/cl-glfw-opengl-sgis_point_parameters.asd lib/cl-glfw-opengl-sgis_sharpen_texture.asd lib/cl-glfw-opengl-sgis_texture4d.asd lib/cl-glfw-opengl-sgis_texture_color_mask.asd lib/cl-glfw-opengl-sgis_texture_filter4.asd lib/cl-glfw-opengl-sgis_texture_select.asd lib/cl-glfw-opengl-sgix_async.asd lib/cl-glfw-opengl-sgix_depth_texture.asd lib/cl-glfw-opengl-sgix_flush_raster.asd lib/cl-glfw-opengl-sgix_fog_scale.asd lib/cl-glfw-opengl-sgix_fragment_lighting.asd lib/cl-glfw-opengl-sgix_framezoom.asd lib/cl-glfw-opengl-sgix_igloo_interface.asd lib/cl-glfw-opengl-sgix_instruments.asd lib/cl-glfw-opengl-sgix_line_quality_hint.asd lib/cl-glfw-opengl-sgix_list_priority.asd lib/cl-glfw-opengl-sgix_pixel_texture.asd lib/cl-glfw-opengl-sgix_polynomial_ffd.asd lib/cl-glfw-opengl-sgix_reference_plane.asd lib/cl-glfw-opengl-sgix_resample.asd lib/cl-glfw-opengl-sgix_scalebias_hint.asd lib/cl-glfw-opengl-sgix_shadow.asd lib/cl-glfw-opengl-sgix_shadow_ambient.asd lib/cl-glfw-opengl-sgix_slim.asd lib/cl-glfw-opengl-sgix_sprite.asd lib/cl-glfw-opengl-sgix_tag_sample_buffer.asd lib/cl-glfw-opengl-sgix_texture_coordinate_clamp.asd lib/cl-glfw-opengl-sgix_texture_lod_bias.asd lib/cl-glfw-opengl-sgix_texture_multi_buffer.asd lib/cl-glfw-opengl-sgix_ycrcba.asd lib/cl-glfw-opengl-sun_convolution_border_modes.asd lib/cl-glfw-opengl-sun_global_alpha.asd lib/cl-glfw-opengl-sun_mesh_array.asd lib/cl-glfw-opengl-sun_slice_accum.asd lib/cl-glfw-opengl-sun_triangle_list.asd lib/cl-glfw-opengl-sun_vertex.asd lib/cl-glfw-opengl-sunx_constant_data.asd lib/cl-glfw-opengl-win_phong_shading.asd lib/cl-glfw-opengl-win_specular_fog.asd +cl-glfw3 http://beta.quicklisp.org/archive/cl-glfw3/2019-07-10/cl-glfw3-20190710-git.tgz 13946 461eab74ffca4736d99436c73c1c54ad 5dd78157e4f4dc51ba4b9e206aaa9c4bf90c8a9f cl-glfw3-20190710-git cl-glfw3-examples.asd cl-glfw3.asd +cl-gobject-introspection http://beta.quicklisp.org/archive/cl-gobject-introspection/2019-11-30/cl-gobject-introspection-20191130-git.tgz 43736 c590518bb6bfa148e3eb58fe999f92a6 9850965e0bfced4f7cb2f8a1ac0b29fb318043e8 cl-gobject-introspection-20191130-git cl-gobject-introspection.asd +cl-gopher http://beta.quicklisp.org/archive/cl-gopher/2018-07-11/cl-gopher-20180711-git.tgz 10415 44843a10189c3f1b5ac6707512d1ab00 ba36371f358918f0724384537577da53ad71d657 cl-gopher-20180711-git cl-gopher.asd +cl-gpio http://beta.quicklisp.org/archive/cl-gpio/2019-07-10/cl-gpio-20190710-git.tgz 9091 1b490421fce75d573674f59e131a77c2 c69382364c82981b1eda62b5a7b8891e10824237 cl-gpio-20190710-git cl-gpio.asd +cl-grace http://beta.quicklisp.org/archive/cl-grace/2019-03-07/cl-grace-20190307-hg.tgz 13889 b703be6d2cbc1e7673cc5365ef213d08 839ba4127931baa62e6093d9ac15927fad413757 cl-grace-20190307-hg cl-grace.asd +cl-graph http://beta.quicklisp.org/archive/cl-graph/2017-12-27/cl-graph-20171227-git.tgz 60626 b133594d59ade148c07ad6fdec4cbdf6 2163417e2d2d61b2ad9d7c4eac1298d33573cdeb cl-graph-20171227-git cl-graph+hu.dwim.graphviz.asd cl-graph.asd +cl-gravatar http://beta.quicklisp.org/archive/cl-gravatar/2011-03-20/cl-gravatar-20110320-git.tgz 2127 6d4e5c83f238a7c301a572ddc926ef9b ae2e3b442465a3395c5f7d0948346bcd9562664e cl-gravatar-20110320-git gravatar.asd +cl-graylog http://beta.quicklisp.org/archive/cl-graylog/2018-04-30/cl-graylog-20180430-git.tgz 3582 4a821f6c2a6496f3fa7fefb4052186d5 5aa806c058074da350fd0208d5049bf1d4b1e4b9 cl-graylog-20180430-git graylog-log5.asd graylog.asd +cl-grnm http://beta.quicklisp.org/archive/cl-grnm/2018-01-31/cl-grnm-20180131-git.tgz 9511 9442e2489cf6894f4e61f9ec610d5c04 0609e0ac48299f120f71c2b86b7fec1f14897a08 cl-grnm-20180131-git cl-grnm.asd +cl-groupby http://beta.quicklisp.org/archive/cl-groupby/2017-08-30/cl-groupby-20170830-git.tgz 4240 5eab5f4784f0a154087daa7aa0caa930 9d7699457042096e05968c011013ad27b9271613 cl-groupby-20170830-git groupby.asd +cl-growl http://beta.quicklisp.org/archive/cl-growl/2016-12-08/cl-growl-20161208-git.tgz 9956 2a99024043323daf84837ae36fb89b2c 6dd1dfb8cec367fe2602a0b2b1bbaff83130f86c cl-growl-20161208-git cl-growl.asd +cl-gss http://beta.quicklisp.org/archive/cl-gss/2018-02-28/cl-gss-20180228-git.tgz 11188 62e9ab1eb233059a0b7f2276a95814d0 23537f4151f9472047e0725bd9e1f2899e766088 cl-gss-20180228-git cl-gss.asd +cl-gtk2 http://beta.quicklisp.org/archive/cl-gtk2/2012-09-09/cl-gtk2-20120909-git.tgz 377784 c61a7112e72154bf151b55d7ad6d93aa a5dc2aafc070b34b1ab09fdcd59dfed9ddd7b9c0 cl-gtk2-20120909-git cairo/cl-gtk2-cairo.asd gdk/cl-gtk2-gdk.asd glib/cl-gtk2-glib.asd gtk/cl-gtk2-gtk.asd pango/cl-gtk2-pango.asd +cl-hamcrest http://beta.quicklisp.org/archive/cl-hamcrest/2019-10-07/cl-hamcrest-20191007-git.tgz 26134 16b76ac7551db1a1567f511e3658890e f422c740a9c76af725d4235aceda909dc5cf675b cl-hamcrest-20191007-git hamcrest.asd +cl-haml http://beta.quicklisp.org/archive/cl-haml/2018-02-28/cl-haml-20180228-git.tgz 17830 0cc73c605a2f182eec47b645ace67498 474bdbb68dfaea7ffefd3396a6b1c14c63ecdfcb cl-haml-20180228-git cl-haml.asd +cl-hamt http://beta.quicklisp.org/archive/cl-hamt/2017-01-24/cl-hamt-20170124-git.tgz 12778 9b2e57f635917514c9a1f442023754ce 8f8ecbfb85c6c3f81b9f7490fc1ab867a18b8555 cl-hamt-20170124-git cl-hamt-examples.asd cl-hamt-test.asd cl-hamt.asd +cl-hash-table-destructuring http://beta.quicklisp.org/archive/cl-hash-table-destructuring/2016-05-31/cl-hash-table-destructuring-20160531-git.tgz 2604 05fb57c755f09ec4f2f5933fdaaedd4c 40d1d6441dd49fb7c51896d5f518d1addf4d2b7c cl-hash-table-destructuring-20160531-git cl-hash-table-destructuring.asd +cl-hash-util http://beta.quicklisp.org/archive/cl-hash-util/2019-01-07/cl-hash-util-20190107-git.tgz 7291 ff5044132c9684cf49f8b841096c67a2 c39b42dde00c70c608089c1c58c958bf46d152e9 cl-hash-util-20190107-git cl-hash-util-test.asd cl-hash-util.asd +cl-heap http://beta.quicklisp.org/archive/cl-heap/2013-03-12/cl-heap-0.1.6.tgz 26979 a12d71f7bbe22d6acdcc7cf36fb907b0 defa03668605e5a14a0431715adf2febf0aaa65a cl-heap-0.1.6 cl-heap-tests.asd cl-heap.asd +cl-heredoc http://beta.quicklisp.org/archive/cl-heredoc/2010-10-06/cl-heredoc-20101006-git.tgz 17070 122bfa8d85735a7ab83d26d827d83bf5 968e336ddb0fa28cbd963cea118e499a9b651c2a cl-heredoc-20101006-git cl-heredoc-test.asd cl-heredoc.asd +cl-html-diff http://beta.quicklisp.org/archive/cl-html-diff/2013-01-28/cl-html-diff-20130128-git.tgz 4134 70f93e60e968dad9a44ede60856dc343 62480247479faf7bad6c1bbd4f4135ac2485694e cl-html-diff-20130128-git cl-html-diff.asd +cl-html-parse http://beta.quicklisp.org/archive/cl-html-parse/2016-10-31/cl-html-parse-20161031-git.tgz 23507 7fe933c461eaf2dd442da189d6827a72 8dfd0cb5cebd248d33791d558e527c83c50bccbe cl-html-parse-20161031-git cl-html-parse.asd +cl-html5-parser http://beta.quicklisp.org/archive/cl-html5-parser/2019-05-21/cl-html5-parser-20190521-git.tgz 192746 149e5609d0a96c867fac6c22693c5e30 4b9882d952d5cf90ce0c874e0b134a04db64d0a4 cl-html5-parser-20190521-git cl-html5-parser.asd cxml/cl-html5-parser-cxml.asd tests/cl-html5-parser-tests.asd +cl-htmlprag http://beta.quicklisp.org/archive/cl-htmlprag/2016-06-28/cl-htmlprag-20160628-git.tgz 41128 8232a485fcb90e422bca541c4e81c263 3a1eb22bd66998acf5eb018237f4a85e0935d6c8 cl-htmlprag-20160628-git cl-htmlprag.asd +cl-httpsqs http://beta.quicklisp.org/archive/cl-httpsqs/2018-02-28/cl-httpsqs-20180228-git.tgz 2303 4ed58c978ada913cbff3fffa002f15eb 446c6bd9937ed987e9ed7bd0023b44512cb462c8 cl-httpsqs-20180228-git cl-httpsqs.asd +cl-hue http://beta.quicklisp.org/archive/cl-hue/2015-01-13/cl-hue-20150113-git.tgz 2734 c5703adb29241896c35f365be6470811 51c697d52abb18f0a370c50c7d9e83cf8d84c43a cl-hue-20150113-git cl-hue.asd +cl-i18n http://beta.quicklisp.org/archive/cl-i18n/2019-11-30/cl-i18n-20191130-git.tgz 50429 7e5d72d378b6585e8a516bb0361fcca7 a18e556f224065d061d239312633817dead01e55 cl-i18n-20191130-git cl-i18n.asd +cl-iconv http://beta.quicklisp.org/archive/cl-iconv/2017-12-27/cl-iconv-20171227-git.tgz 4909 3b6bccf9f50224194d2d0910cd563a6a 3509872d765d9d3a7557cecaa8fadd804f46fc4c cl-iconv-20171227-git iconv.asd +cl-inflector http://beta.quicklisp.org/archive/cl-inflector/2015-01-13/cl-inflector-20150113-git.tgz 6368 8563dd864200dc23b64648581ccec94f 7ef99cde744b4c4645bac4ea440fc1f2a709fdee cl-inflector-20150113-git cl-inflector.asd +cl-influxdb http://beta.quicklisp.org/archive/cl-influxdb/2018-01-31/cl-influxdb-20180131-git.tgz 15600 a34f8d1f70690f6c19465f9bd65f491c 8eb53449dbba61449beec84d34dcc989b06dd5a3 cl-influxdb-20180131-git cl-influxdb.asd +cl-inotify http://beta.quicklisp.org/archive/cl-inotify/2019-07-10/cl-inotify-20190710-git.tgz 11673 ab48770091489a0f6e177bdfb3794570 44417b941f8a79fd8dac1983cc27f8c8ca33637e cl-inotify-20190710-git cl-inotify-tests.asd cl-inotify.asd +cl-intbytes http://beta.quicklisp.org/archive/cl-intbytes/2015-09-23/cl-intbytes-20150923-git.tgz 3789 690cdfa2b0bc4829eeb1f8606291f0f5 f2a1bf6b3052fbd84755e3589d3370511f86b05c cl-intbytes-20150923-git cl-intbytes-test.asd cl-intbytes.asd +cl-interpol http://beta.quicklisp.org/archive/cl-interpol/2018-07-11/cl-interpol-20180711-git.tgz 43436 b2d6893ef703c5b6e5736fa33ba0794e a82431c7ecb6a7c73f2ba9d4d18e23f65d0e3d0b cl-interpol-20180711-git cl-interpol.asd +cl-ipfs-api2 http://beta.quicklisp.org/archive/cl-ipfs-api2/2019-08-13/cl-ipfs-api2-20190813-git.tgz 24730 90d1fdab8a26af11a2b561ce2e7c4177 b63e9d46ae949100396d31c989bf26bcba0fe805 cl-ipfs-api2-20190813-git cl-ipfs-api2.asd +cl-irc http://beta.quicklisp.org/archive/cl-irc/2015-09-23/cl-irc-0.9.2.tgz 921763 73e8ba73d8e4222cec427704c1a6aabd 8f0bf062ea520bfb6e4b0a0395c85c4250425cfb cl-irc-0.9.2 cl-irc.asd test/cl-irc-test.asd +cl-irregsexp http://beta.quicklisp.org/archive/cl-irregsexp/2016-08-25/cl-irregsexp-20160825-git.tgz 21596 717edf273168ca0ca638dcb8721ce4ac 40dd190eaf28eea03b2208469408590b390d07c2 cl-irregsexp-20160825-git cl-irregsexp.asd +cl-isaac http://beta.quicklisp.org/archive/cl-isaac/2015-08-04/cl-isaac-20150804-git.tgz 8731 03beb7c110fa638fa32c4afcb5a9d604 b879c74b9584ad644172e6cc616d159682e71029 cl-isaac-20150804-git cl-isaac.asd +cl-iterative http://beta.quicklisp.org/archive/cl-iterative/2016-03-18/cl-iterative-20160318-git.tgz 8987 7fc7c0e9e4451fc95b57db27e2e42f2c 85c5a21c03dc6e5c88bc3c9a2c1ece9731732a91 cl-iterative-20160318-git cl-iterative-tests.asd cl-iterative.asd +cl-itertools http://beta.quicklisp.org/archive/cl-itertools/2016-04-21/cl-itertools-20160421-git.tgz 6199 03577f82ecdbba2ed0977237a06c0017 97812f1df7ea506f413fee176e6897c85962a1bd cl-itertools-20160421-git cl-itertools.asd +cl-ixf http://beta.quicklisp.org/archive/cl-ixf/2018-02-28/cl-ixf-20180228-git.tgz 8677 23732795aa317d24c1a40cc321a0e394 7b99b33ef1a21049bc8eac1245f1d87fb38f98ea cl-ixf-20180228-git ixf.asd +cl-jpeg http://beta.quicklisp.org/archive/cl-jpeg/2017-06-30/cl-jpeg-20170630-git.tgz 25088 b6eb4ca5d893f428b5bbe46cd49f76ad 1e8f15736d3c038aae73b8283c5d13b50e23bdd0 cl-jpeg-20170630-git cl-jpeg.asd +cl-jpl-util http://beta.quicklisp.org/archive/cl-jpl-util/2015-10-31/cl-jpl-util-20151031-git.tgz 36026 e294bedace729724873e7633b8265a00 0d6d0d8d68c636de34c02e5b0f15b34758e50ac5 cl-jpl-util-20151031-git jpl-util.asd +cl-json http://beta.quicklisp.org/archive/cl-json/2014-12-17/cl-json-20141217-git.tgz 61399 9d873fa462b93c76d90642d8e3fb4881 a506ef6a9ce15a1b58b4d7fbeb9fd774e24008e2 cl-json-20141217-git cl-json.asd +cl-json-helper http://beta.quicklisp.org/archive/cl-json-helper/2018-12-10/cl-json-helper-20181210-git.tgz 2779 a681ca1edff40c68c65e2a6f4457ac01 38cfe3a53def3c09c9b013bc09a9b0c18577f24a cl-json-helper-20181210-git cl-json-helper.asd +cl-json-pointer http://beta.quicklisp.org/archive/cl-json-pointer/2019-05-21/cl-json-pointer-20190521-git.tgz 19712 927b20d2d60149978be02451a1245273 b582db7176bfda8f66bdd42007e7e21451defbaf cl-json-pointer-20190521-git cl-json-pointer.asd +cl-json-template http://beta.quicklisp.org/archive/cl-json-template/2017-06-30/cl-json-template-20170630-git.tgz 12106 cff23f61f7f349c6e9059e4083d95826 6b7435913677413c99e291886a0fab904128c2f9 cl-json-template-20170630-git json-template.asd +cl-jsx http://beta.quicklisp.org/archive/cl-jsx/2016-02-08/cl-jsx-20160208-git.tgz 6265 4e93808606526155d02fd3262e84e8bb 3e7d40b520e361bd8bc2dcd4c6e1fd92c3933672 cl-jsx-20160208-git cl-jsx-test.asd cl-jsx.asd +cl-junit-xml http://beta.quicklisp.org/archive/cl-junit-xml/2015-01-13/cl-junit-xml-20150113-git.tgz 5173 2a8e063e7431b6380ef6a6d268075af3 3d075953049523bb9b6071878607f59344201121 cl-junit-xml-20150113-git cl-junit-xml.asd cl-junit-xml.lisp-unit.asd cl-junit-xml.lisp-unit2.asd +cl-just-getopt-parser http://beta.quicklisp.org/archive/cl-just-getopt-parser/2019-07-10/cl-just-getopt-parser-20190710-git.tgz 7347 64419b6018a5f8012f7bc9445b2c1e8b 290fb2f9c52cf26680af825d1ab6866f22bafd9a cl-just-getopt-parser-20190710-git just-getopt-parser.asd +cl-k8055 http://beta.quicklisp.org/archive/cl-k8055/2019-07-10/cl-k8055-20190710-git.tgz 32114 4038e38dfb899c604beb50682fc85ace c20da9e467984ec6a920f95d12e1d60b1dcfb322 cl-k8055-20190710-git cl-k8055.asd +cl-kanren http://beta.quicklisp.org/archive/cl-kanren/2019-10-07/cl-kanren-20191007-git.tgz 12189 c6a29b570ac5047d4c5b1eb05a9f3b34 f11814e7348abcc947e9f22cfba4974d1277b691 cl-kanren-20191007-git cl-kanren.asd tests/cl-kanren-test.asd +cl-kanren-trs http://beta.quicklisp.org/archive/cl-kanren-trs/2012-03-05/cl-kanren-trs-20120305-svn.tgz 11024 7be1f8c2a6b396bf2403a51d9f5cd4b2 76bc8c61f0425273e137925aa278072284d5f6ef cl-kanren-trs-20120305-svn cl-kanren-trs/kanren-trs.asd cl-kanren-trs/tests/kanren-trs-test.asd +cl-keycloak http://beta.quicklisp.org/archive/cl-keycloak/2019-07-10/cl-keycloak-20190710-git.tgz 13878 c1fd4adadecb6bb9c8db69ea2a4a731e 08895e7fe14432588a82c1920c30d1865bbe63ea cl-keycloak-20190710-git cl-keycloak.asd +cl-kraken http://beta.quicklisp.org/archive/cl-kraken/2019-12-27/cl-kraken-20191227-git.tgz 21682 80c139f50020267f7091da3ba5a13ed1 e6194ec4c88b63bd629d6e1d9af822598eec7e2a cl-kraken-20191227-git cl-kraken.asd +cl-ksuid http://beta.quicklisp.org/archive/cl-ksuid/2017-08-30/cl-ksuid-20170830-git.tgz 15810 0d6c51c80711463b0d276455fc2d4bf9 63b788ba0f5bb0d1e4c436979e4be5a053b10994 cl-ksuid-20170830-git cl-ksuid.asd +cl-kyoto-cabinet http://beta.quicklisp.org/archive/cl-kyoto-cabinet/2019-11-30/cl-kyoto-cabinet-20191130-git.tgz 11166 e9ec82383fe859240e7711142878f8fa 9921f6a8e5750dfe6c300c3e6a7ccc41543bc203 cl-kyoto-cabinet-20191130-git cl-kyoto-cabinet.asd +cl-l10n http://beta.quicklisp.org/archive/cl-l10n/2016-12-04/cl-l10n-20161204-darcs.tgz 66664 c7cb0bb584b061799abaaaf2bd65c9c5 ea99b5ca38a28b28302222f9861a8c552cac4d67 cl-l10n-20161204-darcs cl-l10n.asd +cl-l10n-cldr http://beta.quicklisp.org/archive/cl-l10n-cldr/2012-09-09/cl-l10n-cldr-20120909-darcs.tgz 3538114 466e776f2f6b931d9863e1fc4d0b514e 6b3a2e8fbf2b933e13d85fb21d87943eac67cbf8 cl-l10n-cldr-20120909-darcs cl-l10n-cldr.asd +cl-langutils http://beta.quicklisp.org/archive/cl-langutils/2012-11-25/cl-langutils-20121125-git.tgz 2482768 ba2d1e4abbc7757c135273d76e8147db 0861ac6408e69c6bb155dc62a637ede5fac467de cl-langutils-20121125-git langutils.asd +cl-las http://beta.quicklisp.org/archive/cl-las/2019-12-27/cl-las-20191227-git.tgz 11248 0fccd424456784cbdeb8285a344afb77 1cbb5f4d24ac50519fa45d180c40b052a64c2579 cl-las-20191227-git cl-las.asd +cl-lastfm http://beta.quicklisp.org/archive/cl-lastfm/2014-07-13/cl-lastfm-0.2.1.tgz 22260 2eb42fa1964fe361108aa752fe7a9089 160d3d3dce74b91fadef38768494f1785882ad5b cl-lastfm-0.2.1 cl-lastfm-test.asd cl-lastfm.asd +cl-launch http://beta.quicklisp.org/archive/cl-launch/2015-10-31/cl-launch-4.1.4.1.tgz 94539 5f3d1dc76a5c734a8fd2dba5e567f2ad e809f8f3dcbb3d0b3f239ef3ade7686005aee383 cl-launch-4.1.4.1 cl-launch.asd +cl-ledger http://beta.quicklisp.org/archive/cl-ledger/2019-08-13/cl-ledger-20190813-git.tgz 1182473 7931d6ef3b6585821388d88cfc28a40c a04ab520522307ff5c748efdd69c6744b04699d5 cl-ledger-20190813-git cl-ledger.asd +cl-lex http://beta.quicklisp.org/archive/cl-lex/2016-09-29/cl-lex-20160929-git.tgz 15959 03ca8860afad55575c8747a12e58370a 249a1fb7e5d2070536213b83e9608bcba9cd79b1 cl-lex-20160929-git cl-lex.asd +cl-lexer http://beta.quicklisp.org/archive/cl-lexer/2019-10-07/cl-lexer-20191007-git.tgz 5477 810e054e68d67b18eaa3859114b62662 e8b213a35c04e07c34ca676ee5f7919548e092e2 cl-lexer-20191007-git cl-lexer.asd +cl-libevent2 http://beta.quicklisp.org/archive/cl-libevent2/2019-01-07/cl-libevent2-20190107-git.tgz 17801 e6cf8f0a5ead1184043107ae05505309 a0f45ed59ab51638f6a3081ab21a476ad495ea5d cl-libevent2-20190107-git cl-libevent2-ssl.asd cl-libevent2.asd +cl-libfarmhash http://beta.quicklisp.org/archive/cl-libfarmhash/2016-10-31/cl-libfarmhash-20161031-git.tgz 14254 18f1d5557e8cb18a8508d5aea161c29b f6246aa6bfc3d7d6add3f2f3cabbe574341a87ae cl-libfarmhash-20161031-git cl-libfarmhash.asd +cl-libhoedown http://beta.quicklisp.org/archive/cl-libhoedown/2016-10-31/cl-libhoedown-20161031-git.tgz 6116 e3e02a0108dd00d7d3d47eb7cb8933ba 8265b5849763171d07d9132a68fdf035e1e61f7e cl-libhoedown-20161031-git cl-libhoedown.asd +cl-libiio http://beta.quicklisp.org/archive/cl-libiio/2019-11-30/cl-libiio-20191130-git.tgz 8149 cc70d023b770af0ecdfd1f9e401ee6ff 2caa1a95b175464b2447926ca089babaa7656877 cl-libiio-20191130-git cl-libiio.asd +cl-libpuzzle http://beta.quicklisp.org/archive/cl-libpuzzle/2015-06-08/cl-libpuzzle-20150608-git.tgz 2604 6721ae95e9eaaac4b5cb23403c43f67c 9515ee0dbfe8dfc9af92c36c5bdd97d2cd754c88 cl-libpuzzle-20150608-git cl-libpuzzle-test.asd cl-libpuzzle.asd +cl-libssh2 http://beta.quicklisp.org/archive/cl-libssh2/2016-05-31/cl-libssh2-20160531-git.tgz 21638 f4fdafbe1ef21b9e9c9e07dd564faacd 479298ef75e5cc50679e6eb052606b3a7ebe8df7 cl-libssh2-20160531-git libssh2.asd libssh2.test.asd +cl-libsvm http://beta.quicklisp.org/archive/cl-libsvm/2014-11-06/cl-libsvm-20141106-git.tgz 295884 bf492a44400d6817b61a3ede9ddc6ed3 91d879748fa3b12f9144a1d1d5d6a4f7080e7201 cl-libsvm-20141106-git cl-liblinear.asd cl-libsvm.asd +cl-libsvm-format http://beta.quicklisp.org/archive/cl-libsvm-format/2018-07-11/cl-libsvm-format-20180711-git.tgz 9951 bac7636204a46c66cdfa135cdd147ca6 87adb8326851e29f2c96f0a02dca122336d95520 cl-libsvm-format-20180711-git cl-libsvm-format-test.asd cl-libsvm-format.asd +cl-libusb http://beta.quicklisp.org/archive/cl-libusb/2019-12-27/cl-libusb-20191227-git.tgz 7682 22a50679b150890000f41a697b7b812e 80035e10a4396dc9582554361fbb47b8f511fbe3 cl-libusb-20191227-git cl-libusb.asd libusb-ffi.asd +cl-libuv http://beta.quicklisp.org/archive/cl-libuv/2019-01-07/cl-libuv-20190107-git.tgz 14487 c09c505dc45812cc773454ffc6fdbd38 d4b0c20548ce1bf54bc44938317f437ec8733d8f cl-libuv-20190107-git cl-libuv.asd +cl-libxml2 http://beta.quicklisp.org/archive/cl-libxml2/2013-06-15/cl-libxml2-20130615-git.tgz 55579 88317bf302b5f1d2c1ac9efa6538fbe0 75977fe851405c2d85d67ed6df8dc3462628c661 cl-libxml2-20130615-git cl-libxml2.asd xfactory.asd xoverlay.asd +cl-libyaml http://beta.quicklisp.org/archive/cl-libyaml/2017-01-24/cl-libyaml-20170124-git.tgz 9324 407d5aa53ac8132fcce4b171feaf5d39 92cfe1f703bfe40ad94a2941d5d2d72c7feceb45 cl-libyaml-20170124-git cl-libyaml-test.asd cl-libyaml.asd +cl-locale http://beta.quicklisp.org/archive/cl-locale/2015-10-31/cl-locale-20151031-git.tgz 3916 7a8fb3678938af6dc5c9fd6431428aff b5e33ecae4ad91db85d6f3ead72a52a02547fd23 cl-locale-20151031-git cl-locale-syntax.asd cl-locale-test.asd cl-locale.asd +cl-locatives http://beta.quicklisp.org/archive/cl-locatives/2019-03-07/cl-locatives-20190307-hg.tgz 2705 f7dc0d49dccf787bc27c859ede74537e 83d8f4cc9457e0d907b44ab9d1422e9f75cec721 cl-locatives-20190307-hg cl-locatives.asd +cl-log http://beta.quicklisp.org/archive/cl-log/2013-01-28/cl-log.1.0.1.tgz 18463 fb960933eb748c14adc3ccb376ac8066 79eba93cc6a981a79d95b35533063b70083c6353 cl-log.1.0.1 cl-log-test.asd cl-log.asd +cl-logic http://beta.quicklisp.org/archive/cl-logic/2014-12-17/cl-logic-20141217-git.tgz 19237 1d2c46cd6d6b22eec42b0634ee6aad02 832125e585ebc79b14bad28a34bab16dede39272 cl-logic-20141217-git cl-logic.asd +cl-ltsv http://beta.quicklisp.org/archive/cl-ltsv/2014-07-13/cl-ltsv-20140713-git.tgz 1768 b0f6141d4d431c30cd3f89ed9b915cf9 78beea35eb74ae8e22963cbe6f5e8b7e03d5a578 cl-ltsv-20140713-git cl-ltsv-test.asd cl-ltsv.asd +cl-lzlib http://beta.quicklisp.org/archive/cl-lzlib/2019-10-07/cl-lzlib-20191007-git.tgz 584416 36b2ee8fac0805527d6a215375300123 c9c2bf1198e7f6e86a47f7cefbe8ff2b2f7f10a4 cl-lzlib-20191007-git lzlib-tests.asd lzlib.asd +cl-lzma http://beta.quicklisp.org/archive/cl-lzma/2019-11-30/cl-lzma-20191130-git.tgz 391732 839b371f342610b221e8455ec0e5ab9e 2d6b69f5e810f08f2c943ed3b5a977041608e1cc cl-lzma-20191130-git cl-lzma.asd +cl-m4 http://beta.quicklisp.org/archive/cl-m4/2013-03-12/cl-m4-20130312-git.tgz 43800 1b3c29d5e7fb294f95afd4a845f4c6b4 7dbee2d1711f7b212ba1f6b9a04ac1ba873f4e31 cl-m4-20130312-git cl-m4-test.asd cl-m4.asd +cl-mango http://beta.quicklisp.org/archive/cl-mango/2019-10-07/cl-mango-20191007-git.tgz 102780 771a85df4b2b62fec50913278fa6f27c 04487c9de38a8ef467c187e2506d5ea040b4c637 cl-mango-20191007-git cl-mango.asd +cl-markdown http://beta.quicklisp.org/archive/cl-markdown/2019-12-27/cl-markdown-20191227-git.tgz 73424 630fdb2615d0c7cd7b31a5d6295ae552 eebe40f532720a42422ecfca77bbb2ef60ecfe19 cl-markdown-20191227-git cl-markdown-comparisons.asd cl-markdown-test.asd cl-markdown.asd +cl-markless http://beta.quicklisp.org/archive/cl-markless/2019-10-07/cl-markless-20191007-git.tgz 73880 e9593b82942910bed2449495b7705323 6b690ae311a74c7f29f71abe87406a422633a291 cl-markless-20191007-git cl-markless-test.asd cl-markless.asd epub/cl-markless-epub.asd markdown/cl-markless-markdown.asd plump/cl-markless-plump.asd standalone/cl-markless-standalone.asd +cl-marklogic http://beta.quicklisp.org/archive/cl-marklogic/2017-04-03/cl-marklogic-20170403-git.tgz 1817555 a68c384b84563fa4d6f330ba6a02fb10 f32bfb51893fd300a1472b4891b86f4dbfe6bd7b cl-marklogic-20170403-git cl-marklogic.asd subsystem/ml-dsl/ml-dsl.asd subsystem/ml-optimizer/ml-optimizer.asd subsystem/ml-test/ml-test.asd +cl-markup http://beta.quicklisp.org/archive/cl-markup/2013-10-03/cl-markup-20131003-git.tgz 5785 3ec36b8e15435933f614959032987848 6aa4346b3ea4f1113934de898307229892252b12 cl-markup-20131003-git cl-markup-test.asd cl-markup.asd +cl-marshal http://beta.quicklisp.org/archive/cl-marshal/2018-03-28/cl-marshal-20180328-git.tgz 11220 2d13dd2a276f1e63965498d10d9406ce 47bdef36e420a338139a40e92003fa5d50401695 cl-marshal-20180328-git marshal-tests.asd marshal.asd +cl-match http://beta.quicklisp.org/archive/cl-match/2012-11-25/cl-match-20121125-git.tgz 23798 790a315e08136b3e9b3a42eaadc558a4 a747badf5dabd5b345df787c4b5765ee1d7bbe78 cl-match-20121125-git cl-match-test.asd cl-match.asd pcl-unit-test.asd standard-cl.asd +cl-mathstats http://beta.quicklisp.org/archive/cl-mathstats/2014-07-13/cl-mathstats-20140713-git.tgz 82601 f42fba86de264be6d626064228d15258 f53ab8b4758c0915a3389eb9d02824d226d128ab cl-mathstats-20140713-git cl-mathstats-test.asd cl-mathstats.asd +cl-maxsat http://beta.quicklisp.org/archive/cl-maxsat/2019-12-27/cl-maxsat-20191227-git.tgz 23197 beb673cdf1be131b12e5f2a6a77cf25e 9c6675f48a41c7ba12247c064ac293affde05e65 cl-maxsat-20191227-git cl-maxsat.asd cl-maxsat.test.asd +cl-mecab http://beta.quicklisp.org/archive/cl-mecab/2018-10-18/cl-mecab-20181018-git.tgz 2767 2ab93a1f4c43bab2428e5175108169a2 785e78ddcb996dc7d517f7796063d78f853c658c cl-mecab-20181018-git cl-mecab-test.asd cl-mecab.asd +cl-mechanize http://beta.quicklisp.org/archive/cl-mechanize/2018-07-11/cl-mechanize-20180711-git.tgz 3722 232d80473f28373048d93ca69f2b67a0 bfb4e5e0fcc4181fb4ba09c65c8b21e6bdafc9cc cl-mechanize-20180711-git cl-mechanize.asd +cl-mediawiki http://beta.quicklisp.org/archive/cl-mediawiki/2016-12-04/cl-mediawiki-20161204-git.tgz 16116 25991d3a28d94bf01f7a3a9464e2c3e9 5b3f1c43c010085a50b3459daec5b6b2fe16bd8a cl-mediawiki-20161204-git cl-mediawiki-test.asd cl-mediawiki.asd +cl-memcached http://beta.quicklisp.org/archive/cl-memcached/2015-06-08/cl-memcached-20150608-git.tgz 16575 d53b92973d51e95558aafaba56942c92 694deb82afc44290d593d4ca6d1242077af14fc9 cl-memcached-20150608-git cl-memcached.asd +cl-messagepack http://beta.quicklisp.org/archive/cl-messagepack/2019-03-07/cl-messagepack-20190307-git.tgz 11449 b106e4f7fa1817f7e15a519a4fca270a b49d4e18564a2a42336dec934eafbfa6509b14e5 cl-messagepack-20190307-git cl-messagepack-tests.asd cl-messagepack.asd +cl-messagepack-rpc http://beta.quicklisp.org/archive/cl-messagepack-rpc/2017-12-27/cl-messagepack-rpc-20171227-git.tgz 11177 6de2befbdd2a7e7ee028e0f9cc82bd7f 7b4c77bdb4dad0a365868591dbd75ad1ae3d4c10 cl-messagepack-rpc-20171227-git cl-messagepack-rpc-tests.asd cl-messagepack-rpc.asd +cl-migrations http://beta.quicklisp.org/archive/cl-migrations/2011-01-10/cl-migrations-20110110-http.tgz 3843 af513b9cd5bf182bd7c0910a98107823 cb5ae65cdda19f45cee7eaf4ad1726eddd3fd794 cl-migrations-20110110-http cl-migrations.asd +cl-mime http://beta.quicklisp.org/archive/cl-mime/2016-02-08/cl-mime-20160208-git.tgz 16217 7d91fe61a9d488bf61b2cfcc40aea430 37c0cfac084fd21c6c698023eff53af23d39357f cl-mime-20160208-git cl-mime.asd +cl-mixed http://beta.quicklisp.org/archive/cl-mixed/2019-07-10/cl-mixed-20190710-git.tgz 354610 c952a3a057a5e9c8cfe789f445e9532a dc47c3a46975ea4cd5ffa33eeccc7703fcb01ab0 cl-mixed-20190710-git cl-mixed.asd +cl-mlep http://beta.quicklisp.org/archive/cl-mlep/2018-04-30/cl-mlep-20180430-git.tgz 219387 378549be18c26b35a2a928b48f20e7c6 2e4e11c788b75de49c76163fb045d0741d33747e cl-mlep-20180430-git mlep-add.asd mlep.asd +cl-mock http://beta.quicklisp.org/archive/cl-mock/2016-04-21/cl-mock-20160421-git.tgz 7754 3d38feb9aa3a7d52b38ad18ff60d8f61 19d10980f1c83730327ca2f68e873586b3870dc5 cl-mock-20160421-git cl-mock-basic.asd cl-mock-tests-basic.asd cl-mock-tests.asd cl-mock.asd +cl-modlisp http://beta.quicklisp.org/archive/cl-modlisp/2015-09-23/cl-modlisp-20150923-git.tgz 10406 95f48447065e734ddfd23a58df53679b 5f92ef72be5b0897ed4ca226adbcbe9311a458bf cl-modlisp-20150923-git modlisp.asd +cl-monad-macros http://beta.quicklisp.org/archive/cl-monad-macros/2011-06-19/cl-monad-macros-20110619-svn.tgz 29833 8bff3b40a3720242b6f8f13932dd7b9e 46a54c95c093f7c263c8963479147624b3d234fd cl-monad-macros-20110619-svn cl-monad-macros.asd +cl-moneris http://beta.quicklisp.org/archive/cl-moneris/2011-04-18/cl-moneris-20110418-git.tgz 6676 ad2527ea7e6d8618757907dd2193224a 572b40deafdbd20a759bb36bc26250f6df64c8ac cl-moneris-20110418-git cl-moneris-test.asd cl-moneris.asd +cl-mongo http://beta.quicklisp.org/archive/cl-mongo/2016-05-31/cl-mongo-20160531-git.tgz 63737 f37c70b58ebbbc36dd855356b196c9a0 65b1c29c5c6bf02f9bbd7d64a260089968c41eec cl-mongo-20160531-git cl-mongo.asd +cl-mongo-id http://beta.quicklisp.org/archive/cl-mongo-id/2018-02-28/cl-mongo-id-20180228-git.tgz 3909 7c3a41a0801e9d8c9f03ce440f8a792f 3711c34c4d1a8f4ac40f014d8400339d2f2fb77d cl-mongo-id-20180228-git cl-mongo-id.asd +cl-monitors http://beta.quicklisp.org/archive/cl-monitors/2019-07-10/cl-monitors-20190710-git.tgz 30426 1c6c7f00915b0301a44f99eb5db282fe 6cbc22dbdf2b5dff91722aa12346e35a9a91f8c9 cl-monitors-20190710-git cl-monitors.asd +cl-mop http://beta.quicklisp.org/archive/cl-mop/2015-01-13/cl-mop-20150113-git.tgz 3524 2fafd8a889b9ad8455e0451d97a60f66 b6fd23f5ff74a7343158fcb9979362f24104a670 cl-mop-20150113-git cl-mop.asd +cl-moss http://beta.quicklisp.org/archive/cl-moss/2017-10-19/cl-moss-20171019-git.tgz 15420 5a242fbf7bc9a257a163dffd37467f1b 33a67534114561c248037d59806161a3c3281a05 cl-moss-20171019-git cl-moss.asd +cl-mount-info http://beta.quicklisp.org/archive/cl-mount-info/2019-12-27/cl-mount-info-20191227-git.tgz 22410 100934867273f68e6aed9da3e709637f 99c4259aa58db89fa480eba7429578233244761d cl-mount-info-20191227-git cl-mount-info.asd +cl-mpg123 http://beta.quicklisp.org/archive/cl-mpg123/2019-07-10/cl-mpg123-20190710-git.tgz 1362662 6a816599e8260a8509e39ba7a5d331aa f598325fa9e18963b96c3d9753370054a3d81d71 cl-mpg123-20190710-git cl-mpg123-example.asd cl-mpg123.asd +cl-mpi http://beta.quicklisp.org/archive/cl-mpi/2019-07-10/cl-mpi-20190710-git.tgz 29951 084a37f38bc915e7cb446f0d659e745c 6aec00040dd9c6d789642e78799a97f93bd15de3 cl-mpi-20190710-git cl-mpi-asdf-integration.asd cl-mpi-extensions.asd cl-mpi-test-suite.asd cl-mpi.asd examples/cl-mpi-examples.asd +cl-mssql http://beta.quicklisp.org/archive/cl-mssql/2019-08-13/cl-mssql-20190813-git.tgz 15740 53dce223161f2c5e015366c6b241d713 762a80f7edb4f0af09e000c3f5ec9afff663646d cl-mssql-20190813-git mssql.asd +cl-mtgnet http://beta.quicklisp.org/archive/cl-mtgnet/2018-07-11/cl-mtgnet-20180711-git.tgz 13584 552af7cb3547102849920f639964c694 91a94bf40fb828bc3c8353ca1a17bdc53b1d4960 cl-mtgnet-20180711-git cl-mtgnet-async.asd cl-mtgnet-sync.asd cl-mtgnet.asd +cl-murmurhash http://beta.quicklisp.org/archive/cl-murmurhash/2019-12-27/cl-murmurhash-20191227-git.tgz 6973 71f7d56d247ea19fef5880f8e5f04cb9 3fa7acea151a7124d4dcfcf0573ed08bcb0f5334 cl-murmurhash-20191227-git cl-murmurhash.asd +cl-mustache http://beta.quicklisp.org/archive/cl-mustache/2015-09-23/cl-mustache-20150923-git.tgz 15598 8eaa6901f070bd04cb30aed0c87ba252 c32a2a223da7d39568cc9337153492dfb55aef91 cl-mustache-20150923-git cl-mustache-test.asd cl-mustache.asd +cl-muth http://beta.quicklisp.org/archive/cl-muth/2018-07-11/cl-muth-stable-64e722c5-git.tgz 4920 0759a5f528c77b078bc00264f803d134 99d6871946b18f992c99d14f9c6d48b15c066860 cl-muth-stable-64e722c5-git cl-muth.asd +cl-mw http://beta.quicklisp.org/archive/cl-mw/2015-04-07/cl-mw-20150407-git.tgz 89150 688397a73badb51c626bb5633cfbf9bb 4a3d5e5a5d6413396e759c0895838bc03f70b93d cl-mw-20150407-git cl-mw.asd cl-mw.examples.argument-processing.asd cl-mw.examples.hello-world.asd cl-mw.examples.higher-order.asd cl-mw.examples.monte-carlo-pi.asd cl-mw.examples.ping.asd cl-mw.examples.with-task-policy.asd +cl-mysql http://beta.quicklisp.org/archive/cl-mysql/2017-10-19/cl-mysql-20171019-git.tgz 25620 e1021da4d35cbb584d4df4f0d7e2bbb9 629d419c6d0a1ab3ebb5cb2dadeb0efbc2988564 cl-mysql-20171019-git cl-mysql-test.asd cl-mysql.asd +cl-naive-store http://beta.quicklisp.org/archive/cl-naive-store/2019-12-27/cl-naive-store-20191227-git.tgz 30052 6e45ba6f62992382b70c37ded923235b 9903789369a53dc7af5f10daa4f1c41e02c1e594 cl-naive-store-20191227-git cl-naive-store.asd data-type-defs/cl-naive-data-type-defs.asd data-types/cl-naive-data-types.asd naive-indexed/cl-naive-indexed.asd naive-items/cl-naive-items.asd tests/cl-naive-store-tests.asd +cl-ncurses http://beta.quicklisp.org/archive/cl-ncurses/2010-10-06/cl-ncurses_0.1.4.tgz 23603 60cde15b3c037f394e0c24eb55ad56f8 8d7cfd9bb56ba8c2e6f98bcb298bfc121f8d51bd cl-ncurses_0.1.4 cl-ncurses.asd +cl-neo4j http://beta.quicklisp.org/archive/cl-neo4j/2013-01-28/cl-neo4j-release-b8ad637a-git.tgz 9194 cb073877ef9a06784c7d1964e0c9266d f8a127e60e89f6a419ac4c59f4e734ce3f513258 cl-neo4j-release-b8ad637a-git cl-neo4j.asd +cl-neovim http://beta.quicklisp.org/archive/cl-neovim/2019-05-21/cl-neovim-20190521-git.tgz 28387 c74dc12e6ebcac2f55b0c5f510740734 a47dc4c6b386f74eb24f8370b14ebe489a70753c cl-neovim-20190521-git cl-neovim.asd +cl-netpbm http://beta.quicklisp.org/archive/cl-netpbm/2019-12-27/cl-netpbm-20191227-hg.tgz 406726 456baffc4d3e3cd1c96a5bfc96831c3c 31ce4b59811ce99f0b9bb3bc6a5afbaf9d491be0 cl-netpbm-20191227-hg cl-netpbm.asd +cl-netstring-plus http://beta.quicklisp.org/archive/cl-netstring-plus/2015-07-09/cl-netstring-plus-20150709-git.tgz 4433 6e8765afb3524b15982841b1351e1f8c 21e3f577bcb812b607b5a1b180e97ee8763cf6c1 cl-netstring-plus-20150709-git cl-netstring+.asd +cl-netstrings http://beta.quicklisp.org/archive/cl-netstrings/2012-10-13/cl-netstrings-20121013-git.tgz 3736 8869774ca304843bb00041d63d80ba1e 9bf9f017e4e1b95c067e38c9fdc1e6db85a1457a cl-netstrings-20121013-git cl-netstrings.asd +cl-ntp-client http://beta.quicklisp.org/archive/cl-ntp-client/2019-07-10/cl-ntp-client-20190710-git.tgz 3473 2053825ff92db3e37d533619e64045ad 6b4472231012fda91a1e99de6b8cd930636898d1 cl-ntp-client-20190710-git cl-ntp-client.asd +cl-ntriples http://beta.quicklisp.org/archive/cl-ntriples/2019-03-07/cl-ntriples-20190307-hg.tgz 6167 118afd8c0a65aad8e83e92f19e31117b e6bbc4ad2c50a998124d50ec4b8fdc8eb99f807a cl-ntriples-20190307-hg cl-ntriples.asd +cl-num-utils http://beta.quicklisp.org/archive/cl-num-utils/2013-12-11/cl-num-utils-20131211-git.tgz 64210 a715b9ef4288025bb87a0f4d259763c5 f875e1452b9a0df2729ef874fe4b041557c8905d cl-num-utils-20131211-git cl-num-utils.asd +cl-nxt http://beta.quicklisp.org/archive/cl-nxt/2015-06-08/cl-nxt-20150608-git.tgz 25121 a63efb53921dfb220e9085b7c67a989a c453129fbccbffe7dc25c77c1fe974b453d97b32 cl-nxt-20150608-git nxt-proxy.asd nxt.asd +cl-oauth http://beta.quicklisp.org/archive/cl-oauth/2015-08-04/cl-oauth-20150804-git.tgz 22871 280ca181aaf219d292dfcc5795d68b01 b2dcc9fde0faa4a38dc07d20f523182e0d6ccb21 cl-oauth-20150804-git cl-oauth.asd +cl-oclapi http://beta.quicklisp.org/archive/cl-oclapi/2018-08-31/cl-oclapi-20180831-git.tgz 17154 e80585c65e677f1ad10c5ae6b10879fd 1e73f38e41e931301d229a751cb8eb7e7bd2e27b cl-oclapi-20180831-git cl-oclapi-test.asd cl-oclapi.asd +cl-octet-streams http://beta.quicklisp.org/archive/cl-octet-streams/2018-03-28/cl-octet-streams-20180328-git.tgz 16943 70aa3af68ea8ffa0d69312260f5e5287 5aaf8f807b502d33706fa0f5318cd8fa19a0e1b7 cl-octet-streams-20180328-git cl-octet-streams.asd +cl-ode http://beta.quicklisp.org/archive/cl-ode/2016-06-28/cl-ode-20160628-git.tgz 10617 21c1ba1c91b5910a201cfb824c45fbf0 756649c7ff0912184bb0fa7c8a7e6abafc20273e cl-ode-20160628-git cl-ode.asd +cl-odesk http://beta.quicklisp.org/archive/cl-odesk/2015-06-08/cl-odesk-20150608-git.tgz 6930 e19a70b04c5f7204d46b7bd33a14e054 ab5f306a08b087e175dfe6389e1634444e147adb cl-odesk-20150608-git odesk.asd +cl-ohm http://beta.quicklisp.org/archive/cl-ohm/2018-02-28/cl-ohm-20180228-git.tgz 18129 988fa480a9196cd349782dfefb91b173 e18484324b8fdb9c372d0ad9aa3ebd150c328ec7 cl-ohm-20180228-git cl-ohm.asd +cl-olefs http://beta.quicklisp.org/archive/cl-olefs/2015-07-09/cl-olefs-20150709-git.tgz 21367 e2051eb090625ecf6ef295bbee5e3f65 7dd0fb6d14d42fdb4d3f331c1f15770d8277eda4 cl-olefs-20150709-git cl-olefs.asd +cl-one-time-passwords http://beta.quicklisp.org/archive/cl-one-time-passwords/2017-10-19/cl-one-time-passwords-20171019-git.tgz 4901 c565262b547110b1d5528671483a6166 4b5b6788ed4c8c3b80d1d573779dfff638a30c9a cl-one-time-passwords-20171019-git cl-one-time-passwords-test.asd cl-one-time-passwords.asd +cl-online-learning http://beta.quicklisp.org/archive/cl-online-learning/2019-12-27/cl-online-learning-20191227-git.tgz 47081 8c6d99b9550ce542482229b43d8ac610 0e8108d5f5263a6482b1b94bbec46c661a6daadd cl-online-learning-20191227-git cl-online-learning-test.asd cl-online-learning.asd +cl-openal http://beta.quicklisp.org/archive/cl-openal/2015-03-02/cl-openal-20150302-git.tgz 10197 f85c83d057edf2f6273b0d9f89adfde9 6e4d3ead3768a92da6ab01cc41b88e54c37d7172 cl-openal-20150302-git cl-alc.asd cl-alut.asd cl-openal-examples.asd cl-openal.asd +cl-opengl http://beta.quicklisp.org/archive/cl-opengl/2019-11-30/cl-opengl-20191130-git.tgz 439215 c5387f051960e9179b2ed32fafb67e72 12c358b808eb731ea8519ef6bed602c3c7438cfa cl-opengl-20191130-git cl-glu.asd cl-glut-examples.asd cl-glut.asd cl-opengl.asd +cl-openstack-client http://beta.quicklisp.org/archive/cl-openstack-client/2019-10-07/cl-openstack-client-20191007-git.tgz 15217 21d5f62c63d36ec3b51bac01be54122c ac507feb7962ce6654e7c434f8abd3bfd59edad1 cl-openstack-client-20191007-git cl-openstack-client-test.asd cl-openstack-client.asd +cl-opsresearch http://beta.quicklisp.org/archive/cl-opsresearch/2017-04-03/cl-opsresearch-20170403-git.tgz 169006 3f9d2d4fa2e5bd0bd262c3e7d8473933 d5ec56c8385fdecddd862753f1941f476b6c4797 cl-opsresearch-20170403-git cl-opsresearch.asd subsystem/or-cluster/or-cluster.asd subsystem/or-fann/or-fann.asd subsystem/or-glpk/or-glpk.asd subsystem/or-gsl/or-gsl.asd subsystem/or-test/or-test.asd +cl-org-mode http://beta.quicklisp.org/archive/cl-org-mode/2010-12-07/cl-org-mode-20101207-git.tgz 16460 f4220fc89b86010c37f682b937e48758 4bb1c14e15eaacc107bbf539fc308766cd8f90d0 cl-org-mode-20101207-git cl-org-mode.asd +cl-out123 http://beta.quicklisp.org/archive/cl-out123/2019-07-10/cl-out123-20190710-git.tgz 793012 fe497cc028c073c1b28390c704a98e56 13f4bf99dd9d41f7f326f39c7d2acf561fc63b40 cl-out123-20190710-git cl-out123.asd +cl-pack http://beta.quicklisp.org/archive/cl-pack/2018-04-30/cl-pack-20180430-git.tgz 13791 cb9f9b4929d4d175316b3f3c7f0bff64 d9740ef0fe2d1dc2cd1897511e0b83cc8aac1e9c cl-pack-20180430-git cl-pack.asd +cl-package-locks http://beta.quicklisp.org/archive/cl-package-locks/2011-12-03/cl-package-locks-20111203-git.tgz 3225 27ed43ed35ef89c3b1d7c5b2594f854c 1cb55bc796f5325a251868413e66a915596477cb cl-package-locks-20111203-git cl-package-locks.asd +cl-pango http://beta.quicklisp.org/archive/cl-pango/2017-04-03/cl-pango-20170403-git.tgz 14796 3a55e08abc5f99a853b80c835edb868d 3a8f8780b761e9f58b803a743928c98741be4a4c cl-pango-20170403-git cl-pango.asd +cl-parallel http://beta.quicklisp.org/archive/cl-parallel/2013-03-12/cl-parallel-20130312-git.tgz 3888 246f314b0ffa627a311e775b00dd0b65 b1d4c6defe936a70b5a9bbe431e94c65f8d0c023 cl-parallel-20130312-git cl-parallel.asd +cl-parser-combinators http://beta.quicklisp.org/archive/cl-parser-combinators/2013-11-11/cl-parser-combinators-20131111-git.tgz 36429 25ad9b1459901738a6394422a41b8fec a708a8b6996a18c3aed1d9d909f9c52477c72fba cl-parser-combinators-20131111-git parser-combinators-cl-ppcre.asd parser-combinators-debug.asd parser-combinators-tests.asd parser-combinators.asd +cl-pass http://beta.quicklisp.org/archive/cl-pass/2018-02-28/cl-pass-20180228-git.tgz 2758 feb6fe90104a78686b6255ed8f88c3ed 20e7a18ffafe8683aa0a00f0cbd07b6b925fe29a cl-pass-20180228-git cl-pass-test.asd cl-pass.asd +cl-password-store http://beta.quicklisp.org/archive/cl-password-store/2018-02-28/cl-password-store-20180228-git.tgz 19029 77cc428e880cd136d7c2c0fe279ee90c 3ebe2c16fb1b89913040e2a21c10319ef959b335 cl-password-store-20180228-git cl-password-store.asd +cl-pattern http://beta.quicklisp.org/archive/cl-pattern/2014-07-13/cl-pattern-20140713-git.tgz 5143 cf8e74def535c66a358df1ada9d89785 cab8b56cdf63e359614d33840ef2faa539b351f3 cl-pattern-20140713-git cl-pattern-benchmark.asd cl-pattern.asd +cl-patterns http://beta.quicklisp.org/archive/cl-patterns/2019-12-27/cl-patterns-20191227-git.tgz 95628 a5aacb40f62573d42220d44e67b95a3b cf180356d08ad0ea68c6863ed997884a27c4d0f5 cl-patterns-20191227-git cl-patterns.asd +cl-paymill http://beta.quicklisp.org/archive/cl-paymill/2013-11-11/cl-paymill-20131111-git.tgz 7224 1c240a7da7b22b55d16f7e6922191aa9 95e9052fb40ff1dbbf7925287e1e4f1409198e7a cl-paymill-20131111-git cl-paymill.asd +cl-paypal http://beta.quicklisp.org/archive/cl-paypal/2010-10-06/cl-paypal-20101006-git.tgz 1701376 b24dd8ccbdb60e1dd220076d8a5baa4d 9cf3a3bba7d5ff0feea25875639f6728ac5b2d6a cl-paypal-20101006-git cl-paypal.asd +cl-pcg http://beta.quicklisp.org/archive/cl-pcg/2019-12-27/cl-pcg-20191227-git.tgz 11396 49d212680e99f7bcd2c76dbaa3fa2aab 0834c4cfec434c4d5e04b7590a5e2e1d8981d3ec cl-pcg-20191227-git cl-pcg.asd cl-pcg.test.asd +cl-pdf http://beta.quicklisp.org/archive/cl-pdf/2019-10-07/cl-pdf-20191007-git.tgz 477591 edde2f2da08ec10be65364737ed5fa5c f3740ece395f03b06e573054353d9ef7db6041dc cl-pdf-20191007-git cl-pdf-parser.asd cl-pdf.asd +cl-performance-tuning-helper http://beta.quicklisp.org/archive/cl-performance-tuning-helper/2013-06-15/cl-performance-tuning-helper-20130615-git.tgz 3639 79f43c12d4c35fc6ae10d28467fa5318 2ef8321821c30635eb0eedee03d9cba474b2f2c3 cl-performance-tuning-helper-20130615-git cl-performance-tuning-helper-test.asd cl-performance-tuning-helper.asd +cl-permutation http://beta.quicklisp.org/archive/cl-permutation/2019-10-07/cl-permutation-20191007-git.tgz 59069 bc3408a44f85fc6427c1b70f21015d87 fee0ab3a41141b552e98fad21654819852fc2ea3 cl-permutation-20191007-git cl-permutation-examples.asd cl-permutation-tests.asd cl-permutation.asd +cl-photo http://beta.quicklisp.org/archive/cl-photo/2015-09-23/cl-photo-20150923-git.tgz 12618 1cdf69f41104fcfb0a4ae99a01023148 16a6d27a0e01fc224be9741fb6dd4f0d4a568ef3 cl-photo-20150923-git cl-photo-tests.asd cl-photo.asd +cl-piglow http://beta.quicklisp.org/archive/cl-piglow/2019-12-27/cl-piglow-20191227-git.tgz 6186 2224abe7e444cbc90e6543165635a650 a58791224824666be3dabf06be83d257fa32ac7a cl-piglow-20191227-git cl-piglow.asd +cl-pixman http://beta.quicklisp.org/archive/cl-pixman/2017-08-30/cl-pixman-20170830-git.tgz 11694 5c0938bdf43ebe65574e446b47353e33 77f127fb3a0e55b4814a9796390070c86cc9ee94 cl-pixman-20170830-git pixman.asd +cl-plplot http://beta.quicklisp.org/archive/cl-plplot/2018-02-28/cl-plplot-20180228-git.tgz 289049 e4ac142b064ed3b20bdedd18c602e2c7 21da728b21572839150f71995713c7d54690bd70 cl-plplot-20180228-git cl-plplot.asd +cl-plumbing http://beta.quicklisp.org/archive/cl-plumbing/2018-10-18/cl-plumbing-20181018-git.tgz 3296 835188b1879ae9ad323bafb9cca36c0f fe1c2c004ee5f93822ecb669486ab9c5d6137c88 cl-plumbing-20181018-git cl-plumbing-test.asd cl-plumbing.asd +cl-ply http://beta.quicklisp.org/archive/cl-ply/2015-05-05/cl-ply-20150505-git.tgz 5845 54d8a7725a43455cd4d49ad6e2f1552b 16e20f501dd49b7c965542ee799b6e17c285fdfd cl-ply-20150505-git cl-ply-test.asd cl-ply.asd +cl-png http://beta.quicklisp.org/archive/cl-png/2019-07-10/cl-png-vl-anyversion-04dbb706-git.tgz 8510528 3bff5677a5fb7eecdb348b0f5ad3b2f9 f90b5c9d8b9b75e30872a4139e98687ade71be83 cl-png-vl-anyversion-04dbb706-git png.asd test/bmp-test.asd test/image-test.asd test/ops-test.asd test/png-test.asd +cl-poker-eval http://beta.quicklisp.org/archive/cl-poker-eval/2015-08-04/cl-poker-eval-20150804-git.tgz 15226 7771236a5bda08d88c85a4e33f30047d 5f1611423e82f6132b0ecbc1286f88083642566f cl-poker-eval-20150804-git cl-poker-eval.asd +cl-pop http://beta.quicklisp.org/archive/cl-pop/2011-04-18/cl-pop-20110418-http.tgz 50142 95c0c3418f4740938467514787857bf7 2f413630bb3a0bd507e7a6314f7063f8415c64eb cl-pop-20110418-http cl-pop.asd +cl-portaudio http://beta.quicklisp.org/archive/cl-portaudio/2017-12-27/cl-portaudio-20171227-git.tgz 262470 8a6c175dace75c13eea2378746e6f610 525f6d244842268db1ca65954d57d98854a04c7a cl-portaudio-20171227-git cl-portaudio.asd +cl-portmanteau http://beta.quicklisp.org/archive/cl-portmanteau/2018-10-18/cl-portmanteau-20181018-git.tgz 4041 69dc35a5efd5a58644a86291f114d0ae 1873a59021da676c57cb60a8624ca62231445ab4 cl-portmanteau-20181018-git portmanteau-tests.asd portmanteau.asd +cl-postgres-datetime http://beta.quicklisp.org/archive/cl-postgres-datetime/2019-05-21/cl-postgres-datetime-20190521-git.tgz 2835 2a8346142cf960438f21504a76b48f14 45becc2cce71b8582c605e5727c51f650d3fdf11 cl-postgres-datetime-20190521-git cl-postgres-datetime.asd +cl-postgres-plus-uuid http://beta.quicklisp.org/archive/cl-postgres-plus-uuid/2018-10-18/cl-postgres-plus-uuid-20181018-git.tgz 2270 2fe4f3d80a987192c303695d8629f522 4ca2391fa2cf146d789969453d066da82962af5d cl-postgres-plus-uuid-20181018-git cl-postgres-plus-uuid.asd +cl-ppcre http://beta.quicklisp.org/archive/cl-ppcre/2019-05-21/cl-ppcre-20190521-git.tgz 155009 a980b75c1b386b49bcb28107991eb4ec d6593d8f842bcf6af810ff93c6c02b757bd49ecf cl-ppcre-20190521-git cl-ppcre-unicode.asd cl-ppcre.asd +cl-prevalence http://beta.quicklisp.org/archive/cl-prevalence/2019-11-30/cl-prevalence-20191130-git.tgz 21174 7615cb79ec797a5520941aedc3101390 17538f96a0b5c73cc87d576dbaa63ecd1cbfd713 cl-prevalence-20191130-git cl-prevalence.asd test/cl-prevalence-test.asd +cl-primality http://beta.quicklisp.org/archive/cl-primality/2015-06-08/cl-primality-20150608-git.tgz 5079 e1590227314e5b4edee345232e8a4904 7698c3bcc32494cc4acf4ee91166745160668904 cl-primality-20150608-git cl-primality-test.asd cl-primality.asd +cl-prime-maker http://beta.quicklisp.org/archive/cl-prime-maker/2015-03-02/cl-prime-maker-20150302-git.tgz 5286 018c603dd74eb6a2f760188c1e9e581b b25b00051812d0c302e0e894dd3f3b6cb57cb4c9 cl-prime-maker-20150302-git cl-prime-maker.asd +cl-progress-bar http://beta.quicklisp.org/archive/cl-progress-bar/2018-10-18/cl-progress-bar-20181018-git.tgz 3607 c98f7a9ee6062e19c2a995d1c4952ecb 5de1c70cd16e6463ce9b21de87f3ed0b04f4dc3c cl-progress-bar-20181018-git cl-progress-bar.asd +cl-proj http://beta.quicklisp.org/archive/cl-proj/2019-03-07/cl-proj-20190307-git.tgz 27086 22f867c1041bf6483839be8f96201347 264035de8164730017178560ca47528b6cf53b87 cl-proj-20190307-git cl-proj.asd +cl-project http://beta.quicklisp.org/archive/cl-project/2019-05-21/cl-project-20190521-git.tgz 5426 1468189ff8880f43034c44adc317274f 879f47ff471149e1ad26ac3dfef124aeaceabd95 cl-project-20190521-git cl-project-test.asd cl-project.asd +cl-prolog2 http://beta.quicklisp.org/archive/cl-prolog2/2019-12-27/cl-prolog2-20191227-git.tgz 15590 9d662a6a868c59b66ddb91eae285a959 e09fa6b9921d8986e94738f7fc04a17426b08f27 cl-prolog2-20191227-git bprolog/cl-prolog2.bprolog.asd bprolog/cl-prolog2.bprolog.test.asd cl-prolog2.asd cl-prolog2.test.asd gprolog/cl-prolog2.gprolog.asd gprolog/cl-prolog2.gprolog.test.asd swi/cl-prolog2.swi.asd swi/cl-prolog2.swi.test.asd xsb/cl-prolog2.xsb.asd xsb/cl-prolog2.xsb.test.asd yap/cl-prolog2.yap.asd yap/cl-prolog2.yap.test.asd +cl-protobufs http://beta.quicklisp.org/archive/cl-protobufs/2018-03-28/cl-protobufs-20180328-git.tgz 590732 6573322beb8f27653f0c9b418c5f5b92 85505d3372e06de350a639f55e0e297cd364bcbd cl-protobufs-20180328-git cl-protobufs.asd tests/cl-protobufs-tests.asd +cl-pslib http://beta.quicklisp.org/archive/cl-pslib/2019-12-27/cl-pslib-20191227-git.tgz 41611 89c65c71420ab24a673c60fb68fc317f 14da423eee96d3ac21b4cee5481c85c2628eaf99 cl-pslib-20191227-git cl-pslib.asd +cl-pslib-barcode http://beta.quicklisp.org/archive/cl-pslib-barcode/2019-05-21/cl-pslib-barcode-20190521-git.tgz 25499 fa5459d7daee9546d972c859633d6fe9 3e954175d90c4b76c2b1697f97993f1ada1e67a3 cl-pslib-barcode-20190521-git cl-pslib-barcode.asd +cl-punch http://beta.quicklisp.org/archive/cl-punch/2019-01-07/cl-punch-20190107-git.tgz 1994 b5c6400872ae19221bf5a17f34750c63 e85b56b80563b86ab01b174561df88628c1ece7e cl-punch-20190107-git cl-punch-test.asd cl-punch.asd +cl-python http://beta.quicklisp.org/archive/cl-python/2019-08-13/cl-python-20190813-git.tgz 236882 c802663b1ac6cfa03df0e01c027a817a 3b554320dc2a5fdf31a91df9703f33250b2aaecd cl-python-20190813-git clpython.asd +cl-qprint http://beta.quicklisp.org/archive/cl-qprint/2015-08-04/cl-qprint-20150804-git.tgz 33969 74376a69e0b078724c94cc268f69e0f7 2e2600e7a6ea7c1c21df10f3fb37a531fa1c9382 cl-qprint-20150804-git cl-qprint.asd +cl-qrencode http://beta.quicklisp.org/archive/cl-qrencode/2019-10-07/cl-qrencode-20191007-git.tgz 31145 e94ac1137949ef70dea11ca78431e956 0e6589fa846a65032275cbb576bc13d194476b8f cl-qrencode-20191007-git cl-qrencode-test.asd cl-qrencode.asd +cl-quickcheck http://beta.quicklisp.org/archive/cl-quickcheck/2018-12-10/cl-quickcheck-20181210-git.tgz 18643 e17b3f199c97bfce961c1f9fa2c7602b e7eba42a2283c32af232a8e453c4155af6140a33 cl-quickcheck-20181210-git cl-quickcheck.asd +cl-rabbit http://beta.quicklisp.org/archive/cl-rabbit/2019-07-10/cl-rabbit-20190710-git.tgz 19444 1367680ba8d742821e98a0af16f5df48 a5b026d7e660368aae76cb95a1ac6e606818c447 cl-rabbit-20190710-git cl-rabbit-tests.asd cl-rabbit.asd +cl-rail http://beta.quicklisp.org/archive/cl-rail/2017-12-27/cl-rail-20171227-git.tgz 3644 7da276363c4b689b0bfd85edb449b5d2 95cfb2281dd525f4e6597364a7896022dc715939 cl-rail-20171227-git rail.asd +cl-randist http://beta.quicklisp.org/archive/cl-randist/2015-01-13/cl-randist-20150113-git.tgz 29385 3e79d7d52e4410f2dc2c9bd7287a9379 91d4779af0ce0a9d62364950780ac2d7ded03316 cl-randist-20150113-git cl-randist.asd +cl-random http://beta.quicklisp.org/archive/cl-random/2018-03-28/cl-random-20180328-git.tgz 47082 0f302ea0cf77c5120e85cda903a1026e 46bc508532878a29dfc9cd99fe61c0e18c9c88cc cl-random-20180328-git cl-random.asd +cl-random-forest http://beta.quicklisp.org/archive/cl-random-forest/2019-12-27/cl-random-forest-20191227-git.tgz 64264 f6ef2c6fb92a5763efad27aec06be165 60d5aa0fdc5c3570609ef25685946b4b73d4ab9f cl-random-forest-20191227-git cl-random-forest-test.asd cl-random-forest.asd +cl-rcfiles http://beta.quicklisp.org/archive/cl-rcfiles/2011-12-03/cl-rcfiles-20111203-http.tgz 1905 c6d90a1fe1488fba48dfc8174e829c63 58fbfde7a9339e3129ab1f67da5da7fbe13a493d cl-rcfiles-20111203-http com.dvlsoft.rcfiles.asd +cl-rdfxml http://beta.quicklisp.org/archive/cl-rdfxml/2014-07-13/cl-rdfxml-20140713-git.tgz 24185 ec6e7be8c793352109ab0b633c67c9b8 c27a5bb25404175ec960dccb0805fe8ff82caf5e cl-rdfxml-20140713-git cl-rdfxml.asd +cl-rdkafka http://beta.quicklisp.org/archive/cl-rdkafka/2019-11-30/cl-rdkafka-20191130-git.tgz 42963 4a0cf0f90eea364de2832ef973d9fd74 9481c15a668512774ec086b88b5465fa845ce10a cl-rdkafka-20191130-git cl-rdkafka.asd +cl-readline http://beta.quicklisp.org/archive/cl-readline/2019-08-13/cl-readline-20190813-git.tgz 74175 18272faddf5576e08e0976d98d7475c4 a92e5832b658ff3fdf78d3448636839b86eadd35 cl-readline-20190813-git cl-readline.asd +cl-recaptcha http://beta.quicklisp.org/archive/cl-recaptcha/2015-06-08/cl-recaptcha-20150608-git.tgz 2351 02198a25a246df0e1d2326d5a46bb9bb 127298018d8364bbc2b8c6763c772eef5d55651d cl-recaptcha-20150608-git cl-recaptcha.asd +cl-reddit http://beta.quicklisp.org/archive/cl-reddit/2019-05-21/cl-reddit-20190521-git.tgz 10181 23c2901b8bbffaefd648e8cf5e79db72 5f45f83eceb917e3ca830e714a11c3272078e8e3 cl-reddit-20190521-git cl-reddit.asd +cl-redis http://beta.quicklisp.org/archive/cl-redis/2019-11-30/cl-redis-20191130-git.tgz 25337 74f15acfea85009ca1d6807b35565c20 e2d90d578b588fc9ca4af915ef4dca8609b8ab6b cl-redis-20191130-git cl-redis.asd +cl-reexport http://beta.quicklisp.org/archive/cl-reexport/2015-07-09/cl-reexport-20150709-git.tgz 2621 207d02771cbd906d033ff704ca5c3a3d 5c0c92aab4f892e585116168c3622daf86e5f2ca cl-reexport-20150709-git cl-reexport-test.asd cl-reexport.asd +cl-rethinkdb http://beta.quicklisp.org/archive/cl-rethinkdb/2016-08-25/cl-rethinkdb-20160825-git.tgz 32793 b08605b7cfdc8351472c3764c1c86120 2d087d3e621659974f63a6c3a5fb28c1f22244bc cl-rethinkdb-20160825-git cl-rethinkdb-test.asd cl-rethinkdb.asd +cl-rfc2047 http://beta.quicklisp.org/archive/cl-rfc2047/2015-08-04/cl-rfc2047-20150804-git.tgz 6167 18e4a78b37f0b6bfb650907cb1dc8a17 4554d0124034923310e5134da555a5ac86c810e8 cl-rfc2047-20150804-git cl-rfc2047.asd test/cl-rfc2047-test.asd +cl-riff http://beta.quicklisp.org/archive/cl-riff/2018-01-31/cl-riff-20180131-git.tgz 3545 ab459dd87a44dea617ff845d4fc71191 4469a44389e88b68dff496dfa0b65c9530676400 cl-riff-20180131-git cl-riff.asd +cl-rlimit http://beta.quicklisp.org/archive/cl-rlimit/2015-06-08/cl-rlimit-20150608-git.tgz 3785 ea8d2343b95011bce0de3b699adf0cee 96e1fb8e23a5ad62b865930843dd6150488b8d84 cl-rlimit-20150608-git cl-rlimit.asd +cl-rmath http://beta.quicklisp.org/archive/cl-rmath/2018-03-28/cl-rmath-20180328-git.tgz 5219 0a7e999618e9381b458fea9703774f45 eb85ac5db3f73bba9f919287232e4ea895354424 cl-rmath-20180328-git cl-rmath.asd +cl-routes http://beta.quicklisp.org/archive/cl-routes/2017-01-24/cl-routes-20170124-git.tgz 16959 00cf290e3908eae5cfe4291da87fb7ec b6cf44512de1794cd364a428bd184b9663e8dfc6 cl-routes-20170124-git routes.asd +cl-rrd http://beta.quicklisp.org/archive/cl-rrd/2013-01-28/cl-rrd-20130128-git.tgz 6990 6ed1292cb978445d9952e464d547d149 e820e55875b893f4014ae7358768e480f0d1a28c cl-rrd-20130128-git cl-rrd.asd +cl-rrt http://beta.quicklisp.org/archive/cl-rrt/2015-06-08/cl-rrt-20150608-git.tgz 120843 eeb595209ff5b0c7a6c8c03b918c21c1 25c4808063a57c1af41122e1e17e17159ecc8568 cl-rrt-20150608-git cl-rrt.asd cl-rrt.benchmark.asd cl-rrt.rtree.asd cl-rrt.test.asd +cl-rss http://beta.quicklisp.org/archive/cl-rss/2015-09-23/cl-rss-20150923-git.tgz 6625 9aef52d11324357d191bd4f08cfb8db8 f53cfacd06eb140c1676eca5b1fb953546d5db5f cl-rss-20150923-git rss.asd +cl-rsvg2 http://beta.quicklisp.org/archive/cl-rsvg2/2012-01-07/cl-rsvg2-20120107-git.tgz 52077 a3843a8d8bb4a009252eb70b1cb6cf5d dac64d5abfdaca3743acf1d3b9f8cdf78fba659d cl-rsvg2-20120107-git cl-rsvg2-pixbuf.asd cl-rsvg2-test.asd cl-rsvg2.asd +cl-rules http://beta.quicklisp.org/archive/cl-rules/2019-07-10/cl-rules-20190710-git.tgz 19882 1630f82d032594f14e3eb73afa7cca02 30a3aa278f1df25ed0279dd26a755164d559c2e3 cl-rules-20190710-git cl-rules-test.asd cl-rules.asd +cl-s3 http://beta.quicklisp.org/archive/cl-s3/2013-01-28/cl-s3-20130128-git.tgz 5843 4d064571012b9604f35d38b54d394357 07603d2daf79010091a344f9818c07b435c2d5f2 cl-s3-20130128-git cl-s3.asd +cl-sam http://beta.quicklisp.org/archive/cl-sam/2015-06-08/cl-sam-20150608-git.tgz 4054488 63b1c3bb023e3ef06e5f3855e6144b24 b3e8816022b2cbed60171db86596242905c0edf3 cl-sam-20150608-git cl-sam-test.asd cl-sam.asd +cl-sandbox http://beta.quicklisp.org/archive/cl-sandbox/2018-01-31/cl-sandbox-20180131-git.tgz 6539 86be3668d5ac97547a5043a48f155303 fc1e5b23275df9e8fadea34ac67a19a52b6e1073 cl-sandbox-20180131-git cl-sandbox.asd +cl-sane http://beta.quicklisp.org/archive/cl-sane/2015-06-08/cl-sane-20150608-git.tgz 9398 eb13c4f10552e26bc25a3a262416b71d c956a99e26239fb1c7a7646a9372c1fe7d616c24 cl-sane-20150608-git sane.asd +cl-sanitize http://beta.quicklisp.org/archive/cl-sanitize/2013-07-20/cl-sanitize-20130720-git.tgz 14858 704397eb4bfd6eef71f7bdbba5a672bf 2cf5ca23dcb811cad0796d45ee062d30cc4ad682 cl-sanitize-20130720-git sanitize.asd +cl-sasl http://beta.quicklisp.org/archive/cl-sasl/2019-05-21/cl-sasl-v0.3.2.tgz 7083 61105fc8faf396a39fc9d9c3400b3c21 bed7a2a1a1908c83f5ee47d8d698aba828a12d83 cl-sasl-v0.3.2 cl-sasl.asd +cl-sat http://beta.quicklisp.org/archive/cl-sat/2019-08-13/cl-sat-20190813-git.tgz 18954 3f787f59692c9e962d2d37b2bec74da4 31adeffae9e4d430ac294ca80bb96302ba013372 cl-sat-20190813-git cl-sat.asd cl-sat.test.asd +cl-sat.glucose http://beta.quicklisp.org/archive/cl-sat.glucose/2019-08-13/cl-sat.glucose-20190813-git.tgz 2987 dc40b48ee3f9dcf7cbe9ab4a7c30f8a3 e8c69c7a3bf8f00b18c30cb271af3a96400a3a7d cl-sat.glucose-20190813-git cl-sat.glucose.asd cl-sat.glucose.test.asd +cl-sat.minisat http://beta.quicklisp.org/archive/cl-sat.minisat/2019-08-13/cl-sat.minisat-20190813-git.tgz 2868 25c3abddf6c4cbf76772862bd0d53ee6 9f63b2656623707b841a20d3af40557d3b374e87 cl-sat.minisat-20190813-git cl-sat.minisat.asd cl-sat.minisat.test.asd +cl-scram http://beta.quicklisp.org/archive/cl-scram/2015-09-23/cl-scram-20150923-git.tgz 5503 a010b20d5532a08fc85c2c532ddea09f 3e7475151f474a9d54817daebef5590da99a78a1 cl-scram-20150923-git cl-scram.asd +cl-scribd http://beta.quicklisp.org/archive/cl-scribd/2013-03-12/cl-scribd-20130312-git.tgz 3363 b87c90e9a765d543c2edf464479d5f88 c7995da5ad011d99cd74fee78889138678cf71d2 cl-scribd-20130312-git cl-scribd.asd +cl-scripting http://beta.quicklisp.org/archive/cl-scripting/2017-04-03/cl-scripting-20170403-git.tgz 3953 796475a259527bf7519811c2f567c4ec b56d960acee0ae374f0593ecb72c6900dacb5213 cl-scripting-20170403-git cl-scripting.asd +cl-scrobbler http://beta.quicklisp.org/archive/cl-scrobbler/2011-11-05/cl-scrobbler-20111105-git.tgz 10687 367d3741fc72df62a122ef7188117409 e14659ef82c2107a42ae6767c3137597a72202c1 cl-scrobbler-20111105-git cl-scrobbler.asd +cl-scsu http://beta.quicklisp.org/archive/cl-scsu/2019-05-21/cl-scsu-20190521-git.tgz 19345 057ab3d9bb1cfc12d0fae38e3ae4fd9d da65307115d9439ad16ee89359251eecf2ba0de8 cl-scsu-20190521-git cl-scsu-test.asd cl-scsu.asd +cl-sdl2 http://beta.quicklisp.org/archive/cl-sdl2/2019-11-30/cl-sdl2-20191130-git.tgz 1522180 ece07c78f925f43dddc5b99101248fe7 cdfbc6a245d8bf0f94fccfb75592bd0db1471999 cl-sdl2-20191130-git sdl2.asd +cl-sdl2-image http://beta.quicklisp.org/archive/cl-sdl2-image/2019-02-02/cl-sdl2-image-20190202-git.tgz 400442 d0771409506b37b0f56d0258396d31fd da0dd9f2ca73880afd6303d6f9a616ce976ce486 cl-sdl2-image-20190202-git sdl2-image.asd +cl-sdl2-mixer http://beta.quicklisp.org/archive/cl-sdl2-mixer/2018-10-18/cl-sdl2-mixer-20181018-git.tgz 365901 f5206e179e3fac259cce41b819b5e94d a5a406f8ffd8f08549951d63b919b4dc8dc01d0d cl-sdl2-mixer-20181018-git sdl2-mixer.asd +cl-sdl2-ttf http://beta.quicklisp.org/archive/cl-sdl2-ttf/2018-10-18/cl-sdl2-ttf-20181018-git.tgz 857358 4c174535752393ad7ed1e3546602584e b134b8a4a8ab3d4e9e1293fa70e1a7a8308bd395 cl-sdl2-ttf-20181018-git sdl2-ttf-examples.asd sdl2-ttf.asd +cl-selenium http://beta.quicklisp.org/archive/cl-selenium/2016-05-31/cl-selenium-20160531-git.tgz 15740 308b72c1bdad85a13bf79803c822ee95 9fa23dcb879cab1c8894e0bf8e207490c5acd8a3 cl-selenium-20160531-git selenium.asd +cl-selenium-webdriver http://beta.quicklisp.org/archive/cl-selenium-webdriver/2018-03-28/cl-selenium-webdriver-20180328-git.tgz 7935 d9ee1973788ddfd81380a33495c4ec85 1b90f0da0d3ce8d74e408be28b2c4884b7885b2a cl-selenium-webdriver-20180328-git cl-selenium-test.asd cl-selenium.asd +cl-sentiment http://beta.quicklisp.org/archive/cl-sentiment/2013-01-28/cl-sentiment-20130128-git.tgz 15819 2f3445dffa9105370751fa8ba7c2005c fc4a0651df4d453162919d5bd43540cba491c81e cl-sentiment-20130128-git cl-sentiment.asd +cl-server-manager http://beta.quicklisp.org/archive/cl-server-manager/2013-10-03/cl-server-manager-20131003-git.tgz 4564 046913915897f50caec525748a58cc01 8d8183ebce0e93f9e5e8f6a807b915995c1e6359 cl-server-manager-20131003-git cl-server-manager.asd +cl-shellwords http://beta.quicklisp.org/archive/cl-shellwords/2015-09-23/cl-shellwords-20150923-git.tgz 3943 c2c62c6a2ce4ed2590d60707ead2e084 e925f0d8cc96238116bc7f29b75eb3572e9ce325 cl-shellwords-20150923-git cl-shellwords-test.asd cl-shellwords.asd +cl-shlex http://beta.quicklisp.org/archive/cl-shlex/2019-10-07/cl-shlex-20191007-git.tgz 8580 814f4b1055bbd8423263a6ed5bde564a 1f5471b3cbe80db08b4162a413baa26c42b3b6aa cl-shlex-20191007-git shlex.asd +cl-simple-concurrent-jobs http://beta.quicklisp.org/archive/cl-simple-concurrent-jobs/2015-05-05/cl-simple-concurrent-jobs-20150505-git.tgz 4297 01612838d9d398b13eec9a5b0bc28abb ebe1febd1180f311c340458960719d74cb8bda21 cl-simple-concurrent-jobs-20150505-git cl-simple-concurrent-jobs.asd +cl-simple-fsm http://beta.quicklisp.org/archive/cl-simple-fsm/2019-12-27/cl-simple-fsm-20191227-git.tgz 3517 98e5f4fd0a0ab2cb328fe84db00e82c0 643aae5a3f87b97798b4bbac27925ac5dcdc1b5b cl-simple-fsm-20191227-git finite-state-machine.asd +cl-simple-table http://beta.quicklisp.org/archive/cl-simple-table/2013-03-12/cl-simple-table-20130312-git.tgz 5746 6b100dbdefa432b04a9dd2b36a7aa47b 701fddeefc3cbb1220fc31f7fcbd56294c7aa2a2 cl-simple-table-20130312-git cl-simple-table.asd +cl-singleton-mixin http://beta.quicklisp.org/archive/cl-singleton-mixin/2015-05-05/cl-singleton-mixin-20150505-git.tgz 2088 dbe6e7e009c5051cb4920e9965eff799 20a7748134ec477d642afc98e2a6117e817f8588 cl-singleton-mixin-20150505-git cl-singleton-mixin-test.asd cl-singleton-mixin.asd +cl-skip-list http://beta.quicklisp.org/archive/cl-skip-list/2013-06-15/cl-skip-list-20130615-git.tgz 13233 d8c7b91764103aa5f3db7dbf839968a3 999911f84161239c37601b3d87ed5f9792ee74c2 cl-skip-list-20130615-git cl-skip-list.asd +cl-skkserv http://beta.quicklisp.org/archive/cl-skkserv/2019-05-21/cl-skkserv-20190521-git.tgz 28061 10b4fd63908e842dd7b68abfaaf0a0d3 c2f6d01c3ae857e3acf6aba2fb9e35753fd1277a cl-skkserv-20190521-git cl-skkserv.asd +cl-sl4a http://beta.quicklisp.org/archive/cl-sl4a/2015-08-04/cl-sl4a-20150804-git.tgz 1951 dbfee5c96a7f36682929591319236b24 346a2d6dd6942fa65cd5326a15d127b86a3a99b3 cl-sl4a-20150804-git cl-android.asd +cl-slice http://beta.quicklisp.org/archive/cl-slice/2017-11-30/cl-slice-20171130-git.tgz 7633 b83a7a9aa503dc01cba43cf1e494e67d 0b4a4ecdec181ee34d57fca9d02a91d91a31594e cl-slice-20171130-git cl-slice.asd +cl-slp http://beta.quicklisp.org/archive/cl-slp/2014-08-26/cl-slp-20140826-git.tgz 7716 24dfaadf60cd54dfa811aa9d4e37d07e 0e6a27441f94c6e6ce46e0aead20fc9b2db4dfc7 cl-slp-20140826-git cl-slp.asd +cl-slug http://beta.quicklisp.org/archive/cl-slug/2018-02-28/cl-slug-20180228-git.tgz 7416 2b59b63bb9a234cb14959fda6f12fa2e 9512dd1601d8bcc265598fe6e49cdddf772eeb8f cl-slug-20180228-git cl-slug-test.asd cl-slug.asd +cl-smt-lib http://beta.quicklisp.org/archive/cl-smt-lib/2019-10-07/cl-smt-lib-20191007-git.tgz 4112 5c2af5fbcc3ec8863e909cad6cb921a7 be7e36d0edb1697685edd17839b2ca08aa50b91f cl-smt-lib-20191007-git cl-smt-lib.asd +cl-smtp http://beta.quicklisp.org/archive/cl-smtp/2019-11-30/cl-smtp-20191130-git.tgz 37408 880f09b9fd22e358d1b94a3caf3bd34b 9a19db97a6f0d4e1cc90ae2c03a989f723bcba71 cl-smtp-20191130-git cl-smtp.asd +cl-soil http://beta.quicklisp.org/archive/cl-soil/2018-08-31/cl-soil-release-quicklisp-f27087ce-git.tgz 330400 e26e1e23f2a4bf10a4e4d7c8e2fcd70c 6d7ad0c6aef48bb614d85a709222afcefa75c692 cl-soil-release-quicklisp-f27087ce-git cl-soil.asd +cl-soloud http://beta.quicklisp.org/archive/cl-soloud/2019-07-10/cl-soloud-20190710-git.tgz 521503 59b094adf83863dbf491001ec9dc0e33 f028ca7c4cbc2c3aa86a4341fdeb61e3d9482db4 cl-soloud-20190710-git cl-soloud.asd +cl-sophia http://beta.quicklisp.org/archive/cl-sophia/2015-06-08/cl-sophia-20150608-git.tgz 5748 4fa639f26d38c37be18c0d4e0da4b153 186948212d713ac7bac820f476e63a372b591b69 cl-sophia-20150608-git cl-sophia.asd +cl-spark http://beta.quicklisp.org/archive/cl-spark/2015-07-09/cl-spark-20150709-git.tgz 12519 0eec4e41100c4bbb0ab512e779399604 674f1bc695ae33dc00ab02502078af72720bf098 cl-spark-20150709-git cl-spark-test.asd cl-spark.asd +cl-speedy-queue http://beta.quicklisp.org/archive/cl-speedy-queue/2015-03-02/cl-speedy-queue-20150302-git.tgz 3631 509d1acf7e4cfcef99127de75b16521f 476412e42d63703c0b070d23e7e4cbd389d447e9 cl-speedy-queue-20150302-git cl-speedy-queue.asd +cl-sphinx http://beta.quicklisp.org/archive/cl-sphinx/2011-06-19/cl-sphinx-20110619-git.tgz 162782 0aa9e282a8ecc190b788d121071373d6 2ca537aaaac0a4d45151b6a7c8ca71909d10ff5d cl-sphinx-20110619-git sphinx.asd +cl-spidev http://beta.quicklisp.org/archive/cl-spidev/2019-07-10/cl-spidev-20190710-git.tgz 10495 59a6d3341753da1fed9b05864deaabc4 b9338baf09481b93f21f16cea80fc9023b195807 cl-spidev-20190710-git cl-spidev.asd +cl-splicing-macro http://beta.quicklisp.org/archive/cl-splicing-macro/2014-07-13/cl-splicing-macro-20140713-git.tgz 3041 d9ff0c4c0aa1a649ae7f6866ae5ce570 9b0b263f55f29e0dc141c8928f0151ce21bad99f cl-splicing-macro-20140713-git cl-splicing-macro.asd +cl-sqlite http://beta.quicklisp.org/archive/cl-sqlite/2019-08-13/cl-sqlite-20190813-git.tgz 14632 2269773eeb4a101ddd3b33f0f7e05e76 4edb0bfcfc4ec79ab48038c420e415b817c054f8 cl-sqlite-20190813-git sqlite.asd +cl-ssdb http://beta.quicklisp.org/archive/cl-ssdb/2017-08-30/cl-ssdb-20170830-git.tgz 16126 82ae579cf245edd48997fcb45c5a901c 3056cf48da051b98929d584dc5b841a2d15d55bd cl-ssdb-20170830-git cl-ssdb-test.asd cl-ssdb.asd +cl-statsd http://beta.quicklisp.org/archive/cl-statsd/2017-01-24/cl-statsd-20170124-git.tgz 6437 bc58e298a1cf3657375eeb7e9981d993 65edf0606df6f93ff2b212c619c1f315e68a0de1 cl-statsd-20170124-git cl-statsd.asd cl-statsd.test.asd +cl-stdutils http://beta.quicklisp.org/archive/cl-stdutils/2011-10-01/cl-stdutils-20111001-git.tgz 114509 0fa8879ce4004924ff1f534e9fb92dba 4204504d7107cd3eae33550c4e00797fa4dfba98 cl-stdutils-20111001-git stdutils.asd +cl-steamworks http://beta.quicklisp.org/archive/cl-steamworks/2019-08-13/cl-steamworks-20190813-git.tgz 99838 790744d59a1435552a001ed6c32b9c48 d9e683874159eae48619172982b9595248aad946 cl-steamworks-20190813-git cl-steamworks-generator.asd cl-steamworks.asd +cl-stomp http://beta.quicklisp.org/archive/cl-stomp/2019-05-21/cl-stomp-20190521-git.tgz 7487 8f0ec87e3a0bb05e97bf5e4d2509074e a9f15eac2d88439c1d93b7dec9a12a7262dd32f3 cl-stomp-20190521-git cl-stomp.asd +cl-stopwatch http://beta.quicklisp.org/archive/cl-stopwatch/2019-03-07/cl-stopwatch-20190307-hg.tgz 3481 f8aca8aac1dcaa3ff818e558dfb8471b 3963d39f4cdba3e518f0d027124d647592e77545 cl-stopwatch-20190307-hg cl-stopwatch.asd +cl-store http://beta.quicklisp.org/archive/cl-store/2019-11-30/cl-store-20191130-git.tgz 47654 d6052274cd0c6a86bfc2de1e4a8a0886 e486b6ae28113215280cb5d3bbf30f1ad5804613 cl-store-20191130-git cl-store.asd +cl-str http://beta.quicklisp.org/archive/cl-str/2019-12-27/cl-str-20191227-git.tgz 14864 b2800b32209061b274432c7e699d92b4 4b48d2a3a9348897e1318dffa9f8b574d57d5000 cl-str-20191227-git str.asd str.test.asd +cl-stream http://beta.quicklisp.org/archive/cl-stream/2019-05-21/cl-stream-20190521-git.tgz 10083 99bb43715db14c688bb32be11e4fee8b bd4e03b1155b2a3fe9a9a6faaae493f48bc0ad95 cl-stream-20190521-git cl-stream.asd +cl-strftime http://beta.quicklisp.org/archive/cl-strftime/2016-03-18/cl-strftime-20160318-git.tgz 7797 73097d6d00eca45c52ca5bedc99d0146 27c12e403c68bd330feffadd2b766cb9db160347 cl-strftime-20160318-git cl-strftime.asd +cl-string-complete http://beta.quicklisp.org/archive/cl-string-complete/2019-03-07/cl-string-complete-20190307-hg.tgz 5305 e828ace268105ad02b58ed26498ad28f eab194a8bfb0efe55ac8f0c7d8411e5e16408556 cl-string-complete-20190307-hg cl-string-complete.asd +cl-string-match http://beta.quicklisp.org/archive/cl-string-match/2019-03-07/cl-string-match-20190307-hg.tgz 176593 68e27c214f63e7c30f1e0c2ccad86131 7d2a654be746559ace31ef188a977826f86a0bfe cl-string-match-20190307-hg ascii-strings.asd cl-string-match-test.asd cl-string-match.asd simple-scanf.asd +cl-strings http://beta.quicklisp.org/archive/cl-strings/2018-01-31/cl-strings-20180131-git.tgz 11078 c10eee2534f8476b59acf13f34787a56 5256d9d0725aa96208b47d91a565f6e005670bba cl-strings-20180131-git cl-strings.asd +cl-svg http://beta.quicklisp.org/archive/cl-svg/2018-02-28/cl-svg-20180228-git.tgz 83379 672145ecadef2259a3833886dbe68617 1640e08a5ddbcc328a3b4240c13ff91cac3c5454 cl-svg-20180228-git cl-svg.asd +cl-svm http://beta.quicklisp.org/archive/cl-svm/2011-04-18/cl-svm-20110418-git.tgz 435539 c093c5810a77b5258a6b463168c7c8bb 8e4d8ad0cb5ec177c2373b14c251c5932a84615b cl-svm-20110418-git cl-svm.asd +cl-swagger-codegen http://beta.quicklisp.org/archive/cl-swagger-codegen/2018-08-31/cl-swagger-codegen-20180831-git.tgz 43309 5066805afea5280e16e3e58f05cd88e1 9b69504759ff81308c486b266ff3484d2a6e8531 cl-swagger-codegen-20180831-git cl-swagger.asd +cl-sxml http://beta.quicklisp.org/archive/cl-sxml/2016-08-25/cl-sxml-20160825-git.tgz 15206 5bf02bf2dcb4ddf1c1a869a0ff7277df f993c08874902296c2b2b6ddcbc21cae0cfbbbda cl-sxml-20160825-git cl-sxml.asd +cl-syntax http://beta.quicklisp.org/archive/cl-syntax/2015-04-07/cl-syntax-20150407-git.tgz 3102 602b84143aafe59d65f4e08ac20a124a e00e7def72875fd635f7e9d27e24fd3f23076247 cl-syntax-20150407-git cl-syntax-annot.asd cl-syntax-anonfun.asd cl-syntax-clsql.asd cl-syntax-fare-quasiquote.asd cl-syntax-interpol.asd cl-syntax-markup.asd cl-syntax.asd +cl-syslog http://beta.quicklisp.org/archive/cl-syslog/2019-02-02/cl-syslog-20190202-git.tgz 14759 eafff19eb1f38a36a9535c729d2217fe de0c891d0168db0a3079707794b5fafae6d99282 cl-syslog-20190202-git cl-syslog.asd +cl-table http://beta.quicklisp.org/archive/cl-table/2013-01-28/cl-table-20130128-git.tgz 4002 793e1222aebf00d28d4ec58173bd36b5 93e0aa5fb21ae9722e78814471019d1c2c62f6a3 cl-table-20130128-git cl-table.asd +cl-tasukete http://beta.quicklisp.org/archive/cl-tasukete/2018-02-28/cl-tasukete-20180228-git.tgz 5602 f4dc086f01e384684b371fbcf631c29b 793c27bce80661019dd5920e02074e538bd22855 cl-tasukete-20180228-git cl-tasukete-test.asd cl-tasukete.asd +cl-tcod http://beta.quicklisp.org/archive/cl-tcod/2019-03-07/cl-tcod-20190307-hg.tgz 88998 19b214124c8034ef7fab350ee8cac85d 7c1935d7f9d77ec4e954396b175a12e00ff4bb32 cl-tcod-20190307-hg parse-rgb.asd tcod.asd +cl-template http://beta.quicklisp.org/archive/cl-template/2013-06-15/cl-template-20130615-git.tgz 8316 9ff3872864a04535fa4fdd541e5fef70 3407880226be0be8fd02890e3ef18a2c9c8899f6 cl-template-20130615-git cl-template.asd +cl-tesseract http://beta.quicklisp.org/archive/cl-tesseract/2017-11-30/cl-tesseract-20171130-git.tgz 8190 761384aa2cde1733a96d6fca82d00750 98cef4ac03acf09549444079e5da579b19ebdc7a cl-tesseract-20171130-git cl-tesseract.asd +cl-tetris3d http://beta.quicklisp.org/archive/cl-tetris3d/2018-12-10/cl-tetris3d-20181210-git.tgz 5744 66d1a4aa18316e25bc0a7df127be71e7 5ea752a06b16d0d4aff9ad6a1bf5acc3eda92faf cl-tetris3d-20181210-git cl-tetris3d.asd +cl-textmagic http://beta.quicklisp.org/archive/cl-textmagic/2015-12-18/cl-textmagic-20151218-git.tgz 2035 f746d2e7ddea99e9cbe443e4a6c08175 3473012d8f21242b2a9bb6a85544938fe2c4a536 cl-textmagic-20151218-git cl-textmagic-test.asd cl-textmagic.asd +cl-tga http://beta.quicklisp.org/archive/cl-tga/2016-03-18/cl-tga-20160318-git.tgz 312452 84bf8ad6fc66ffd2519b933469ae3660 2d2b8b4fd47dde90818f6600bd73bf3cc0ede60f cl-tga-20160318-git cl-tga.asd +cl-threadpool http://beta.quicklisp.org/archive/cl-threadpool/2018-02-28/cl-threadpool-quickload-current-release-67b33ca4-git.tgz 7043 24d77e379a133b440f1ef61ba375ac68 24ab5b625c94a9dd1521bacc44da7316d4260060 cl-threadpool-quickload-current-release-67b33ca4-git cl-threadpool-test.asd cl-threadpool.asd +cl-tidy http://beta.quicklisp.org/archive/cl-tidy/2017-08-30/cl-tidy-20170830-git.tgz 6451 753b926424eaf57415e3cdb2545f4b51 8510d6d70053a5dcf0471a22507013b245695875 cl-tidy-20170830-git cl-tidy.asd +cl-tiled http://beta.quicklisp.org/archive/cl-tiled/2019-11-30/cl-tiled-20191130-git.tgz 18051 9b235a4a51b858842661c95871f72855 7e6134e180a45e3f52502be2f0f580be5538f25a cl-tiled-20191130-git cl-tiled.asd +cl-tk http://beta.quicklisp.org/archive/cl-tk/2015-06-08/cl-tk-20150608-git.tgz 11254 c6711a6dea114a6c3dec446420eec0f7 a69f6d26b9018482347f83542b91d5f913c13d4c cl-tk-20150608-git cl-tk.asd +cl-tld http://beta.quicklisp.org/archive/cl-tld/2014-09-14/cl-tld-20140914-git.tgz 42598 c1a599db2ff8f0bb76acb206743b8d98 bb55b6b60e8cf822c80fb220117d81b809616325 cl-tld-20140914-git cl-tld.asd +cl-tokyo-cabinet http://beta.quicklisp.org/archive/cl-tokyo-cabinet/2016-08-25/cl-tokyo-cabinet-20160825-git.tgz 19667 00d4bb23e393c6966b4acf17d9184627 9d22fd186290b36752b32010589d8f6b6c31024d cl-tokyo-cabinet-20160825-git cl-tokyo-cabinet-test.asd cl-tokyo-cabinet.asd +cl-toml http://beta.quicklisp.org/archive/cl-toml/2019-11-30/cl-toml-20191130-git.tgz 8835 093bee6524054b0b515d52db070eb300 8cf25c892ca26097b7d4880e49b8d32439ed4095 cl-toml-20191130-git cl-toml-test.asd cl-toml.asd +cl-torrents http://beta.quicklisp.org/archive/cl-torrents/2019-12-27/cl-torrents-20191227-git.tgz 579423 11d40517d088db7dbc506dede11ac452 c0707a0ffcfef7844340d48ea004ea5b6806f4b9 cl-torrents-20191227-git torrents-test.asd torrents.asd +cl-transmission http://beta.quicklisp.org/archive/cl-transmission/2019-11-30/cl-transmission-20191130-git.tgz 8850 403607bb79c4df111d3af41d03607b76 da1f5bf1637e728c1da70439e85a73016cafcee7 cl-transmission-20191130-git cl-transmission-test.asd cl-transmission.asd +cl-trie http://beta.quicklisp.org/archive/cl-trie/2018-02-28/cl-trie-20180228-git.tgz 11400 20a0f0facbed0ccfad54bfeac6dcbba7 3e5dc74d7aeb063b2cdb3a8a267b946606c1e541 cl-trie-20180228-git cl-trie-examples.asd cl-trie.asd +cl-tulip-graph http://beta.quicklisp.org/archive/cl-tulip-graph/2013-06-15/cl-tulip-graph-20130615-git.tgz 14772 eaf9d92e3bffcf93220052fd42b4d002 060726c29d1b14f683149de192541e5b30a99877 cl-tulip-graph-20130615-git cl-tulip-graph.asd +cl-tuples http://beta.quicklisp.org/archive/cl-tuples/2014-07-13/cl-tuples-20140713-git.tgz 28047 8676dd7e0be1af17f5ffa8aac21d0ab3 c977ce6c441bd413c363d63cc99382ff33192dff cl-tuples-20140713-git cl-tuples.asd +cl-twitter http://beta.quicklisp.org/archive/cl-twitter/2018-02-28/cl-twitter-20180228-git.tgz 70934 83638a0508cda507500ef9e633f6cec4 620458f22d28ab5e6f33027c492e7fe1cae28c48 cl-twitter-20180228-git cl-twit-repl.asd cl-twitter.asd twitter-mongodb-driver.asd +cl-typesetting http://beta.quicklisp.org/archive/cl-typesetting/2017-08-30/cl-typesetting-20170830-git.tgz 335971 e12b9f249c60c220c5dc4a0939eb3343 25acaabf4593729cebb2c2ee79d056633f9b2fdb cl-typesetting-20170830-git cl-typesetting.asd contrib/xhtml-renderer/xml-render.asd documentation/lisp-source/cl-pdf-doc.asd +cl-uglify-js http://beta.quicklisp.org/archive/cl-uglify-js/2015-07-09/cl-uglify-js-20150709-git.tgz 17631 f0ac4a43bb9da2478e995802b86df6dd b806550d06d7844466d36235876ff0a1698e854b cl-uglify-js-20150709-git cl-uglify-js.asd +cl-unicode http://beta.quicklisp.org/archive/cl-unicode/2019-05-21/cl-unicode-20190521-git.tgz 590698 04009a1266edbdda4d38902907caba25 58b893a1a34cee2803c9bfcc1ff1ac1056741c96 cl-unicode-20190521-git cl-unicode.asd +cl-unification http://beta.quicklisp.org/archive/cl-unification/2019-01-07/cl-unification-20190107-git.tgz 32390 a7a12789cc48e571b0871d55cef11b7f de98a21a56c2a219afca5cfc43b4cd8f74ed1abb cl-unification-20190107-git cl-unification-lib.asd cl-unification-test.asd cl-unification.asd lib-dependent/cl-ppcre-template.asd +cl-utilities http://beta.quicklisp.org/archive/cl-utilities/2010-10-06/cl-utilities-1.2.4.tgz 22998 c3a4ba38b627448d3ed40ce888048940 187862251617676b95b1386e277fb2c449472bf8 cl-utilities-1.2.4 cl-utilities.asd +cl-variates http://beta.quicklisp.org/archive/cl-variates/2018-01-31/cl-variates-20180131-darcs.tgz 13536 dd441faa5cf87e4f41102c4a2323f95f 0ee1831ebbfe0c3efb4a5a02936f8a01b624abcc cl-variates-20180131-darcs cl-variates.asd +cl-vectors http://beta.quicklisp.org/archive/cl-vectors/2018-02-28/cl-vectors-20180228-git.tgz 31415 9d9629786d4f2c19c15cc6cd3049c343 55f19b15187b1a1026c7fd139fedf3cb7663847b cl-vectors-20180228-git cl-aa-misc.asd cl-aa.asd cl-paths-ttf.asd cl-paths.asd cl-vectors.asd +cl-vhdl http://beta.quicklisp.org/archive/cl-vhdl/2016-04-21/cl-vhdl-20160421-git.tgz 38493 1cae44b3e18d5b1416e9c3afb7382f76 030aa263142eff790f30a947c7b606b7b6021d97 cl-vhdl-20160421-git cl-vhdl.asd +cl-video http://beta.quicklisp.org/archive/cl-video/2018-02-28/cl-video-20180228-git.tgz 9729 1390350148bca3730b1a7d24e298d0e2 82c761ab17ae349f4ec7efff0f438e1dfa57af3d cl-video-20180228-git cl-video-avi.asd cl-video-gif.asd cl-video-player.asd cl-video-wav.asd cl-video.asd +cl-virtualbox http://beta.quicklisp.org/archive/cl-virtualbox/2018-08-31/cl-virtualbox-20180831-git.tgz 5029 f75919b162c344bf5b3bee1bf3f91e32 90de58049f50133366139c8e37e5e8548ff1bce9 cl-virtualbox-20180831-git cl-virtualbox.asd +cl-voxelize http://beta.quicklisp.org/archive/cl-voxelize/2015-07-09/cl-voxelize-20150709-git.tgz 118708 2e3d839d201d64659726f553bebd6ac0 104f867098b7cde4f4ccd449633cd9a407e8ce46 cl-voxelize-20150709-git cl-voxelize-examples.asd cl-voxelize-test.asd cl-voxelize.asd +cl-wadler-pprint http://beta.quicklisp.org/archive/cl-wadler-pprint/2019-10-07/cl-wadler-pprint-20191007-git.tgz 4900 030262f0ac47b84a4cfbfa3e423b7eee c68f97c39c540a1bcd35023df432e026b651ded3 cl-wadler-pprint-20191007-git cl-wadler-pprint.asd +cl-wav http://beta.quicklisp.org/archive/cl-wav/2018-01-31/cl-wav-20180131-git.tgz 3469 c487c47fb702747ad1e0faffe5b7d388 b45d07885c30d4205d3d952b3a20ead799574b2e cl-wav-20180131-git cl-wav.asd +cl-wayland http://beta.quicklisp.org/archive/cl-wayland/2019-03-07/cl-wayland-20190307-git.tgz 44560 31887db1bf34dcf36f3978c8004d4e0f 9a189cafa43b0da7d79a9421afa30bebbf7db6ec cl-wayland-20190307-git cl-wayland.asd +cl-weather-jp http://beta.quicklisp.org/archive/cl-weather-jp/2016-02-08/cl-weather-jp-20160208-git.tgz 3398 705667b6c865f440d1667ccc5f83a8fb 3c40d7f65d92a9485ec4bb8e89c0d0af8d5e73c3 cl-weather-jp-20160208-git cl-weather-jp-test.asd cl-weather-jp.asd +cl-webdav http://beta.quicklisp.org/archive/cl-webdav/2017-08-30/cl-webdav-20170830-git.tgz 77311 9b5b1bbe0b24734a652a464f6924a019 68cbdcabb6c6e8c61ff4757554efa3e83af3e2a1 cl-webdav-20170830-git cl-webdav.asd +cl-webkit http://beta.quicklisp.org/archive/cl-webkit/2017-12-27/cl-webkit-20171227-git.tgz 19659 defcdf910b41f57bc33030b491596f6f 1915c831bf12e3418db939e7828021ec0b35c402 cl-webkit-20171227-git dom/cl-webkit-dom.asd soup/cl-soup.asd tests/cl-webkit2-tests.asd webkit2/cl-webkit2.asd +cl-who http://beta.quicklisp.org/archive/cl-who/2019-07-10/cl-who-20190710-git.tgz 24786 e5bb2856ed62d76528e4cef7b5e701c0 5ef6d9b6609320a8f11655194b9139f5e0a1555a cl-who-20190710-git cl-who.asd +cl-why http://beta.quicklisp.org/archive/cl-why/2018-02-28/cl-why-20180228-git.tgz 25872 00a337f35a516372da41415d25fb879b 86790d0b92642b89a6fde16249597db175cfb407 cl-why-20180228-git cl-why.asd +cl-wordcut http://beta.quicklisp.org/archive/cl-wordcut/2016-04-21/cl-wordcut-20160421-git.tgz 301706 1f251cf2df7f1946887d09c82e3ce968 4b7bbb407529d93d44f9799646a19301c9a81826 cl-wordcut-20160421-git cl-wordcut.asd +cl-xdg http://beta.quicklisp.org/archive/cl-xdg/2017-01-24/cl-xdg-20170124-git.tgz 22666 eaf304bd5c23c58f45f161afe180c2d4 dbdcbe7542181ebf9bfde5c57f120543a937911a cl-xdg-20170124-git cl-xdg.asd +cl-xkb http://beta.quicklisp.org/archive/cl-xkb/2018-02-28/cl-xkb-20180228-git.tgz 2792 97ba20ff9ea183afe00ea2cf7e0469f4 1a9f7395f10de77372af1dceee3b930814ae3173 cl-xkb-20180228-git cl-xkb.asd +cl-xkeysym http://beta.quicklisp.org/archive/cl-xkeysym/2014-09-14/cl-xkeysym-20140914-git.tgz 38246 15ad40d06aa25589bdb59ac5ef485b8c 3d95e7111d9560e75772dbdbd6655b917ede6d47 cl-xkeysym-20140914-git cl-xkeysym.asd +cl-xmlspam http://beta.quicklisp.org/archive/cl-xmlspam/2010-10-06/cl-xmlspam-20101006-http.tgz 10705 6e3a0944e96e17916b1445f4207babb8 82b47ae3227d537486d6bea267c473a068729ecd cl-xmlspam-20101006-http cl-xmlspam.asd +cl-xmpp http://beta.quicklisp.org/archive/cl-xmpp/2010-10-06/cl-xmpp-0.8.1.tgz 15271 303b035edd3bde5aa85c423278298e88 23935110f714202ce650c7e31af12fbbc1f22130 cl-xmpp-0.8.1 cl-xmpp-sasl.asd cl-xmpp-tls.asd cl-xmpp.asd +cl-xul http://beta.quicklisp.org/archive/cl-xul/2016-03-18/cl-xul-20160318-git.tgz 518863 2fbb767b222e632df40a3b7a57aa7f3e 19ad37e6129833ed96d57f92246922462d8f9fb9 cl-xul-20160318-git cl-xul-test.asd cl-xul.asd +cl-yacc http://beta.quicklisp.org/archive/cl-yacc/2010-10-06/cl-yacc-20101006-darcs.tgz 18774 748b9d59de8be3ccfdf0f001e15972ba 7e224cde172cc9db229385fcef1ee411403f9ff6 cl-yacc-20101006-darcs yacc.asd +cl-yaclyaml http://beta.quicklisp.org/archive/cl-yaclyaml/2016-08-25/cl-yaclyaml-20160825-git.tgz 35546 73ddfe97a2b8214e319b366245a216c2 fd3ddd09d55fb1176db7b23f16e3874d6c5018a6 cl-yaclyaml-20160825-git cl-yaclyaml.asd +cl-yahoo-finance http://beta.quicklisp.org/archive/cl-yahoo-finance/2013-03-12/cl-yahoo-finance-20130312-git.tgz 7759 ef1129e9f2bd7afbdde50048db25cc94 9801bb213a303af511c38d63a126b718a2b65085 cl-yahoo-finance-20130312-git cl-yahoo-finance.asd +cl-yaml http://beta.quicklisp.org/archive/cl-yaml/2017-01-24/cl-yaml-20170124-git.tgz 13310 97c545287084ae110c9ef9a76f44285e 5cd19d7b27dde6dfe7322e09729589d5b7839798 cl-yaml-20170124-git cl-yaml-test.asd cl-yaml.asd +cl-yesql http://beta.quicklisp.org/archive/cl-yesql/2019-12-27/cl-yesql-20191227-git.tgz 13398 d3fdef812f1c623db325feddb748449f 4036cd4d7f36483f83c4df9be5c76aa440c90b41 cl-yesql-20191227-git cl-yesql.asd +cl-zmq http://beta.quicklisp.org/archive/cl-zmq/2016-03-18/cl-zmq-20160318-git.tgz 13519 2edc111c3fa50504eb2ef997f9ded9c4 b50410e4f435a9e85b3d91df8101fb2048594ab0 cl-zmq-20160318-git zeromq.asd +cl4store http://beta.quicklisp.org/archive/cl4store/2015-03-02/cl4store-20150302-git.tgz 11305 a1a877db84a10e143004f580317c682f b29433e5ff5be42bdf7cea25e30ff378e22aa935 cl4store-20150302-git cl4store-tests.asd cl4store.asd +clache http://beta.quicklisp.org/archive/clache/2017-11-30/clache-20171130-git.tgz 5875 e319e26205af015787e5cd893eeb58cd 2c09d8401c5e225019bb7393ca899e0056f31790 clache-20171130-git clache-test.asd clache.asd +clack http://beta.quicklisp.org/archive/clack/2019-10-07/clack-20191007-git.tgz 194174 25741855fa1e989d373ac06ddfabf351 b7adffcaef66722766d91b6cd684f2bf1123a839 clack-20191007-git clack-handler-fcgi.asd clack-handler-hunchentoot.asd clack-handler-toot.asd clack-handler-wookie.asd clack-socket.asd clack-test.asd clack-v1-compat.asd clack.asd t-clack-handler-fcgi.asd t-clack-handler-hunchentoot.asd t-clack-handler-toot.asd t-clack-handler-wookie.asd t-clack-v1-compat.asd v1-compat/clack-middleware-auth-basic.asd v1-compat/clack-middleware-clsql.asd v1-compat/clack-middleware-csrf.asd v1-compat/clack-middleware-dbi.asd v1-compat/clack-middleware-oauth.asd v1-compat/clack-middleware-postmodern.asd v1-compat/clack-middleware-rucksack.asd v1-compat/clack-session-store-dbi.asd v1-compat/t-clack-middleware-auth-basic.asd v1-compat/t-clack-middleware-csrf.asd +clack-errors http://beta.quicklisp.org/archive/clack-errors/2019-08-13/clack-errors-20190813-git.tgz 278838 bbae5cf71b4d95e5dbb51c1b8cc11ff0 35df80382645afdbc51214118d2542bd446e3e6a clack-errors-20190813-git clack-errors-demo.asd clack-errors-test.asd clack-errors.asd lack-middleware-clack-errors.asd +clack-pretend http://beta.quicklisp.org/archive/clack-pretend/2017-11-30/clack-pretend-20171130-git.tgz 6573 618f531237dd52bfd5a5a821adaf2e39 a9979ccdd776ed6045de839bbd946f36162610e9 clack-pretend-20171130-git clack-pretend.asd +clack-static-asset-middleware http://beta.quicklisp.org/archive/clack-static-asset-middleware/2016-06-28/clack-static-asset-middleware-20160628-git.tgz 21786 9ee4736d1d084e1481454454a019b6fc 646c3fe12943be8d595913db958b2bc9bdcbaefe clack-static-asset-middleware-20160628-git clack-static-asset-djula-helpers.asd clack-static-asset-middleware-test.asd clack-static-asset-middleware.asd +clad http://beta.quicklisp.org/archive/clad/2019-03-07/clad-20190307-git.tgz 2549 bcac73710bff9ee6179f9c3b58f7da8e 36c35e7c4469b7ae22901c0c24e205fec94dc02e clad-20190307-git clad.asd +classimp http://beta.quicklisp.org/archive/classimp/2017-10-19/classimp-20171019-git.tgz 31643 25b91b1fa7d0b66c2ff89670fd6b54a9 5c31a29f474b74a20e0c91f253d44128450dcafc classimp-20171019-git classimp-samples.asd classimp.asd +classowary http://beta.quicklisp.org/archive/classowary/2019-10-07/classowary-20191007-git.tgz 24900 a2587986780a40251b0327686b817cc6 cce68e75254543ae11458499c408544f67dda874 classowary-20191007-git classowary-test.asd classowary.asd +clath http://beta.quicklisp.org/archive/clath/2017-11-30/clath-20171130-git.tgz 19773 e0c7ad1e7ac1c23f3ff8839ac48df7e8 0dea05c8eb86ad2816a4458cf15b1e5f5ec44a12 clath-20171130-git clath.asd cljwt-custom.asd +clavatar http://beta.quicklisp.org/archive/clavatar/2012-10-13/clavatar-20121013-git.tgz 3375 2861593e34c92b4faa7edb77be6044bb caf33a796f42b398be84fb304753622550cd41f1 clavatar-20121013-git clavatar.asd +clavier http://beta.quicklisp.org/archive/clavier/2017-08-30/clavier-20170830-git.tgz 7176 f6a24e93771e4426843fe5d13a3ff9b9 b3750931a63da718edec5a58e169adb00a3e24a9 clavier-20170830-git clavier.asd clavier.test.asd +claw http://beta.quicklisp.org/archive/claw/2018-08-31/claw-stable-9877cb7d-git.tgz 30850 6395c0bc853474d8ffb7a12754ccaade d9b1acdca9ecfaec7371f87452b6062e13cd81b0 claw-stable-9877cb7d-git claw.asd +clawk http://beta.quicklisp.org/archive/clawk/2011-11-05/clawk-20111105-git.tgz 14059 8ca7378b4dbae7d51644834cd9641f67 eaf0348d0ddcd167ed799e3b19d2eb976982537e clawk-20111105-git clawk.asd +clazy http://beta.quicklisp.org/archive/clazy/2019-01-07/clazy-20190107-git.tgz 24055 e0c29871eb4c7e80658511e9d20de6ea 3eeac3b7b971ea4ef80ebafafacbf650dc0e61f3 clazy-20190107-git clazy.asd +clem http://beta.quicklisp.org/archive/clem/2019-03-07/clem-20190307-git.tgz 84528 444f88b3b087a833d005b2b11f218e39 fd1abd391562801cc472c1e73bb74235b421cc01 clem-20190307-git clem-benchmark.asd clem-test.asd clem.asd +cleric http://beta.quicklisp.org/archive/cleric/2014-11-06/cleric-20141106-git.tgz 19915 2d51ed0118d3e4bd2c72668f109687a7 1226afbf0cd42110008438f9f283d3c52b2bfc46 cleric-20141106-git cleric-test.asd cleric.asd +clesh http://beta.quicklisp.org/archive/clesh/2019-07-10/clesh-20190710-git.tgz 8024 a9ce7e59326ca10074be1b73a1bfe83d e557ae5bff0ff9d20c43c91b63804c24049f6f79 clesh-20190710-git clesh-tests.asd clesh.asd +cletris http://beta.quicklisp.org/archive/cletris/2015-10-31/cletris-20151031-git.tgz 190792 d5b1f4c3a76675498491d191cadc7414 13e5975c8e01aedc97e4d14e5c1355e06c1fa6da cletris-20151031-git cletris-network.asd cletris-test.asd cletris.asd +clfswm http://beta.quicklisp.org/archive/clfswm/2016-12-04/clfswm-20161204-git.tgz 282721 dc976785ef899837ab0fc50a4ed6b740 f745e9682f549b4d92d31e3e7fcec68d561af370 clfswm-20161204-git clfswm.asd +clhs http://beta.quicklisp.org/archive/clhs/2015-04-07/clhs-0.6.3.tgz 2238743 37b804be8696e555a74f240ebc17bbc6 f1c4c385996573194e15316c2f4167f6d3998859 clhs-0.6.3 clhs.asd +clickr http://beta.quicklisp.org/archive/clickr/2014-07-13/clickr-20140713-git.tgz 23238 264cae768921c6e264d909bb4c40e873 af914f21f5a5cac958bfd57128000580dab268e5 clickr-20140713-git clickr.asd +clim-widgets http://beta.quicklisp.org/archive/clim-widgets/2018-02-28/clim-widgets-20180228-git.tgz 12167 b7f7093c7702fc6718c8b693a0ca9a6d db343ca3b774bb82515726ed5a509eb248b5e6a1 clim-widgets-20180228-git clim-widgets.asd +climacs http://beta.quicklisp.org/archive/climacs/2019-01-07/climacs-20190107-git.tgz 111467 a9b75b0f78c15d60ad47f7b87e68c903 c8d7a8ef35285367211e7867e1cd3f66891159bf climacs-20190107-git climacs.asd +climc http://beta.quicklisp.org/archive/climc/2015-09-23/climc-20150923-git.tgz 214296 c6ada8af39d27cf972f269fb2b0e3778 47cb3636d8a6bef908a58b6662d1020bbe6bf40a climc-20150923-git climc-test.asd climc.asd +climon http://beta.quicklisp.org/archive/climon/2015-10-31/climon-20151031-git.tgz 1005444 8e47631f5e0f6157e6581e746c5d3edf 6d02953a6250f423579e25efd65c1b5d2f1b6cec climon-20151031-git climon-test.asd climon.asd +clinch http://beta.quicklisp.org/archive/clinch/2018-02-28/clinch-20180228-git.tgz 15291213 26477d753d550ae020ae95c60315d8b3 232f53345667193c6f4899ab6322d31066e31eef clinch-20180228-git clinch-cairo.asd clinch-classimp.asd clinch-freeimage.asd clinch-pango.asd clinch.asd +clinenoise http://beta.quicklisp.org/archive/clinenoise/2018-01-31/clinenoise-20180131-git.tgz 5651 b72593638356978c952e69dc56fab335 c7837c33b327e4cf7db670804de80652e096d3c3 clinenoise-20180131-git clinenoise.asd +clip http://beta.quicklisp.org/archive/clip/2019-07-10/clip-20190710-git.tgz 23116 3a990d1a030d153c76def305df568c77 a48649b95c51b239c6f11ec4e592dd377c40a31c clip-20190710-git clip.asd +clipper http://beta.quicklisp.org/archive/clipper/2015-09-23/clipper-20150923-git.tgz 30698 a8d3f3fa89f2d31dd864a55a93604973 d45c4f34e7ea6db2ad08811d2f2b104dd9e5afbc clipper-20150923-git clipper-test.asd clipper.asd +clite http://beta.quicklisp.org/archive/clite/2013-06-15/clite-20130615-git.tgz 4207 e9ec17416118a4bc561b7ac0b1c8fe55 a33f68199901025b79110bb113ac204b47008231 clite-20130615-git clite.asd +clml http://beta.quicklisp.org/archive/clml/2018-08-31/clml-20180831-git.tgz 1008543 4c16c4b23748faa9f35e158f782404c2 358e2da5905a6b151724cd72e16d0bbde32aab7f clml-20180831-git addons/fork-future/fork-future.asd addons/future/future.asd association-rule/clml.association-rule.asd blas/clml.blas.asd blas/f2cl-lib.asd classifiers/clml.classifiers.asd clml.asd clustering/clml.clustering.asd data/clml.data.asd data/r-datasets/clml.data.r-datasets.asd decision-tree/clml.decision-tree.asd docs/clml.docs.asd graph/clml.graph.asd hjs/clml.hjs.asd lapack/clml.lapack.asd nearest-search/clml.nearest-search.asd nonparametric/clml.nonparametric.asd numeric/clml.numeric.asd pca/clml.pca.asd som/clml.som.asd statistics/clml.statistics.asd statistics/clml.statistics.rand.asd svm/clml.svm.asd test/clml.test.asd text/clml.text.asd time-series/clml.time-series.asd utility/clml.utility.asd +clnuplot http://beta.quicklisp.org/archive/clnuplot/2013-01-28/clnuplot-20130128-darcs.tgz 31274 0e5dccbbbe3408b3e0aebf639691c6a0 6a2749d3b7ef6bd1325b92160bb9eee35f099c96 clnuplot-20130128-darcs clnuplot.asd +clobber http://beta.quicklisp.org/archive/clobber/2019-05-21/clobber-20190521-git.tgz 6301 2a2d5490aa21ed847eff57bae8148582 f26247f00fc4821bb9a71756359ea4c78515d52c clobber-20190521-git clobber.asd +clod http://beta.quicklisp.org/archive/clod/2019-03-07/clod-20190307-hg.tgz 98259 df582b015aa80397402eee3bb5a13288 c3bc36581145c5abc6126b2c3ba88386f6ba7876 clod-20190307-hg clod.asd +clods-export http://beta.quicklisp.org/archive/clods-export/2017-10-19/clods-export-20171019-git.tgz 19990 342fb1799b9f0c2549666b204f9cb322 6554a4c2d68216e9fa33dc67a6096886c153df40 clods-export-20171019-git clods-export.asd +clon http://beta.quicklisp.org/archive/clon/2011-03-20/clon-20110320-git.tgz 7926 92c40493948d3466d1b149a000985ce0 db47fb37cae16262070c9d711ec49dd01b0075c0 clon-20110320-git clon-test.asd clon.asd +clonsigna http://beta.quicklisp.org/archive/clonsigna/2012-09-09/clonsigna-20120909-git.tgz 42948 3ae74680c33dfd5880914dac3873357c 11bf0a3df0e3309a054015629c01a282148208e5 clonsigna-20120909-git clonsigna.asd +clos-diff http://beta.quicklisp.org/archive/clos-diff/2015-06-08/clos-diff-20150608-git.tgz 14486 88dbce5dc199deb2ee44e7cb73946db0 8825ffc50639addefd79f604addcacf17309f512 clos-diff-20150608-git clos-diff.asd +clos-fixtures http://beta.quicklisp.org/archive/clos-fixtures/2016-08-25/clos-fixtures-20160825-git.tgz 2687 68898ca907a135d733ecdadb3f8b5723 75e8f147882b9e7fb56519a8c8a91d00798b1df7 clos-fixtures-20160825-git clos-fixtures-test.asd clos-fixtures.asd +closer-mop http://beta.quicklisp.org/archive/closer-mop/2019-12-27/closer-mop-20191227-git.tgz 23507 67dda2ff56690bb8eec6131983605031 7e849ccb36b31b485f8bb4b6a84f84ba03ced65c closer-mop-20191227-git closer-mop.asd +closure-common http://beta.quicklisp.org/archive/closure-common/2018-10-18/closure-common-20181018-git.tgz 27833 b09ee60c258a29f0c107960ec4c04ada 42e2f882070d49d3224c15a304354afb29f97841 closure-common-20181018-git closure-common.asd +closure-html http://beta.quicklisp.org/archive/closure-html/2018-07-11/closure-html-20180711-git.tgz 103413 461dc8caa65385da5f2d1cd8dd4f965f d8e52dc5d129aec699cd405c14a9080d01199506 closure-html-20180711-git closure-html.asd +clouchdb http://beta.quicklisp.org/archive/clouchdb/2012-04-07/clouchdb_0.0.16.tgz 33759 d39f8e71a5e1954b40af4291f0c05757 7d254f6edf1a28300e4c4c3fa387b4cfcdf24b28 clouchdb_0.0.16 clouchdb-examples.asd clouchdb.asd +clsql http://beta.quicklisp.org/archive/clsql/2016-02-08/clsql-20160208-git.tgz 968869 d1da7688361337a7de4fe7452c225a06 6cefb5c9d783acecb94b66e288faba7d1d7367e2 clsql-20160208-git clsql-aodbc.asd clsql-cffi.asd clsql-mysql.asd clsql-odbc.asd clsql-postgresql-socket.asd clsql-postgresql-socket3.asd clsql-postgresql.asd clsql-sqlite.asd clsql-sqlite3.asd clsql-tests.asd clsql-uffi.asd clsql.asd +clsql-fluid http://beta.quicklisp.org/archive/clsql-fluid/2017-08-30/clsql-fluid-20170830-git.tgz 4361 cd6191a16e81af2670f3ed84b29995b8 af7e03aca8277efe730c86075f3587be71a357c1 clsql-fluid-20170830-git clsql-fluid.asd +clsql-helper http://beta.quicklisp.org/archive/clsql-helper/2018-01-31/clsql-helper-20180131-git.tgz 31200 e3040bc42b24c8b0845abcd4a74d3db4 b92225c63d358fac585ce63bc132cca4bac1f50c clsql-helper-20180131-git clsql-helper-slot-coercer.asd clsql-helper.asd +clsql-local-time http://beta.quicklisp.org/archive/clsql-local-time/2019-11-30/clsql-local-time-20191130-git.tgz 1688 180d36508b76a5d9728f3e88fda8047d c0d26ade44c4ffbae84db81db346a6de3c727477 clsql-local-time-20191130-git clsql-local-time.asd +clsql-orm http://beta.quicklisp.org/archive/clsql-orm/2016-02-08/clsql-orm-20160208-git.tgz 19760 40b31c2bfbf7b27f35b362fc4cffb6bf 4d07a98d77328076b0844f4708c56087f5618426 clsql-orm-20160208-git clsql-orm.asd +clss http://beta.quicklisp.org/archive/clss/2019-11-30/clss-20191130-git.tgz 20000 9910677b36df00f3046905a9b84122a9 440121bc862ddcd72c421df4ade798ecfb26242a clss-20191130-git clss.asd +cltcl http://beta.quicklisp.org/archive/cltcl/2016-12-04/cltcl-20161204-git.tgz 338065 bb57496aeea233c7adb04e3bb6eca551 8d9140fafe4658324f8b354159cdef6d8c9d174b cltcl-20161204-git cltcl.asd +clump http://beta.quicklisp.org/archive/clump/2016-08-25/clump-20160825-git.tgz 25593 5132d2800138d435ef69f7e68b025c8f 68760a1e2e6e28ecf8f45e5b766774bc3a18e369 clump-20160825-git 2-3-tree/clump-2-3-tree.asd Binary-tree/clump-binary-tree.asd Test/clump-test.asd clump.asd +clunit http://beta.quicklisp.org/archive/clunit/2017-10-19/clunit-20171019-git.tgz 76811 389017f2f05a6287078ddacd0471817e 26340b858b8c784b90cda75ab57470410507d191 clunit-20171019-git clunit.asd +clunit2 http://beta.quicklisp.org/archive/clunit2/2018-10-18/clunit2-20181018-git.tgz 77822 44d69b87557a924fe8d49eaac739c20e cbb4457813e643061d977a5c5817f6a956888ed3 clunit2-20181018-git clunit2.asd +clutz http://beta.quicklisp.org/archive/clutz/2018-02-28/clutz-stable-0a544be0-git.tgz 2523 544e6326659345ecd6db81f774995660 1e9575546d2b360c777fb08aa8db7a61df62e651 clutz-stable-0a544be0-git clutz.asd +clweb http://beta.quicklisp.org/archive/clweb/2018-04-30/clweb-20180430-git.tgz 138871 a57892e3a6fe9fa2dbe7a2c1865e82c6 a37cbe2c941a71c08dbe47a5de7f55b9caeedc84 clweb-20180430-git clweb.asd +clws http://beta.quicklisp.org/archive/clws/2013-08-13/clws-20130813-git.tgz 32371 11a801aadeda244b749c2b36a19b9af9 521463b0aef355a1307f911327fee5ed5d65854d clws-20130813-git clws.asd +clx http://beta.quicklisp.org/archive/clx/2019-11-30/clx-20191130-git.tgz 457343 61e86a60727732df62c9fa383535fc89 0a39c0f03919c2e5c7730ef9c760fdd1f9471f6e clx-20191130-git clx.asd +clx-cursor http://beta.quicklisp.org/archive/clx-cursor/2018-01-31/clx-cursor-20180131-git.tgz 183731 227e05446493e0fc20836aeb90c0e500 6b37027d762656bb0b9fcaf82fa865b2dd57173c clx-cursor-20180131-git clx-cursor.asd +clx-truetype http://beta.quicklisp.org/archive/clx-truetype/2016-08-25/clx-truetype-20160825-git.tgz 376571 7c9dedb21d52dedf727de741ac6d9c60 9902edbe06af953b755beca024521c21d3f068c6 clx-truetype-20160825-git clx-truetype.asd +clx-xembed http://beta.quicklisp.org/archive/clx-xembed/2019-11-30/clx-xembed-20191130-git.tgz 21169 11d35eeb734c0694005a5e5cec4cad22 27ec06dc8e843deb1fd1b01058e78627e5dbf424 clx-xembed-20191130-git xembed.asd +clx-xkeyboard http://beta.quicklisp.org/archive/clx-xkeyboard/2012-08-11/clx-xkeyboard-20120811-git.tgz 47002 4e382b34e05d33f5de8e9c9dea33131c f18ddbbf8f7e5222cb44e2543386a8efd49abb7c clx-xkeyboard-20120811-git xkeyboard.asd +cmake-parser http://beta.quicklisp.org/archive/cmake-parser/2018-08-31/cmake-parser-20180831-git.tgz 5470 901e49335a490ad419aec7bcd4493d47 adc648f94bfc8e9e0834075e88f4098dafd9e982 cmake-parser-20180831-git cmake-parser.asd +cmu-infix http://beta.quicklisp.org/archive/cmu-infix/2018-02-28/cmu-infix-20180228-git.tgz 22615 6baab7e8fdbb211c1b1622073b9521c9 408f16c7594f02f53e39ea8b7684721d12406435 cmu-infix-20180228-git cmu-infix-tests.asd cmu-infix.asd +codata-recommended-values http://beta.quicklisp.org/archive/codata-recommended-values/2017-10-19/codata-recommended-values-20171019-git.tgz 186586 99a0ddb582b1182f499d0c94e41a45e9 628cba44e3699d2bb9194be9ceeac63c453008b5 codata-recommended-values-20171019-git codata-recommended-values.asd +codex http://beta.quicklisp.org/archive/codex/2018-12-10/codex-20181210-git.tgz 185947 7c33d0361d2e50d968aade71461443f4 7d7ee6fbc90ecdaa755d4f2f1b986d24d03ff912 codex-20181210-git codex-templates.asd codex.asd +coleslaw http://beta.quicklisp.org/archive/coleslaw/2019-11-30/coleslaw-20191130-git.tgz 165818 6c356af48e856daacfcd067c9e9a40af ce4f0603534ad09748bdbf16305084433f9ad6a1 coleslaw-20191130-git coleslaw-cli.asd coleslaw-test.asd coleslaw.asd +collectors http://beta.quicklisp.org/archive/collectors/2016-12-04/collectors-20161204-git.tgz 10522 59c8c885a8e512d4f09e73d3e0c97b1f 1e386552e3b2900580e3972c46152fb776dcc28a collectors-20161204-git collectors.asd +colleen http://beta.quicklisp.org/archive/colleen/2018-10-18/colleen-20181018-git.tgz 145758 b20ec13f6a9612e0f496af7eccb24f54 950fa71177e3966ae52eb7a986d9ceeeb5e117ed colleen-20181018-git colleen.asd +colliflower http://beta.quicklisp.org/archive/colliflower/2015-12-18/colliflower-20151218-git.tgz 24042 68f0d511fe9429919859b184e6b564e1 c02b61ea1e6f1732201ce36d3718c3eab9bce190 colliflower-20151218-git colliflower-test.asd colliflower.asd contrib/fset/colliflower-fset.asd garten/garten.asd liter/liter.asd silo/silo.asd +colorize http://beta.quicklisp.org/archive/colorize/2018-02-28/colorize-20180228-git.tgz 39488 1bc08c8f76b747e4d254669a205dc611 e0658fa18ae562a802f987eff7f16a8bc78906f8 colorize-20180228-git colorize.asd +com.clearly-useful.generic-collection-interface http://beta.quicklisp.org/archive/com.clearly-useful.generic-collection-interface/2019-07-10/com.clearly-useful.generic-collection-interface-20190710-git.tgz 14043 b22496129d4171c50de7ab85da024cc0 0dac346508bb07e3237054a0554c2c6d28153020 com.clearly-useful.generic-collection-interface-20190710-git com.clearly-useful.generic-collection-interface.asd com.clearly-useful.generic-collection-interface.test.asd +com.clearly-useful.iterate-plus http://beta.quicklisp.org/archive/com.clearly-useful.iterate-plus/2012-10-13/com.clearly-useful.iterate-plus-20121013-git.tgz 1981 691606442da9344a1b871a986dc83a42 c7a315d2b09d7666def427dc37cad324317caf51 com.clearly-useful.iterate-plus-20121013-git com.clearly-useful.iterate+.asd +com.clearly-useful.iterator-protocol http://beta.quicklisp.org/archive/com.clearly-useful.iterator-protocol/2013-03-12/com.clearly-useful.iterator-protocol-20130312-git.tgz 2846 b6219074982d29677ebf5a7ae1b5a22e 5f9051fdccbd78f3c919112a67acf80587c921d9 com.clearly-useful.iterator-protocol-20130312-git com.clearly-useful.iterator-protocol.asd +com.clearly-useful.protocols http://beta.quicklisp.org/archive/com.clearly-useful.protocols/2013-03-12/com.clearly-useful.protocols-20130312-git.tgz 8625 7a230b991c6f410f2f1f1cc016aa3ae1 174ae8cc771b48bc36f4ae2ee3dfb80fef266d60 com.clearly-useful.protocols-20130312-git com.clearly-useful.protocols.asd +com.google.base http://beta.quicklisp.org/archive/com.google.base/2015-10-31/com.google.base-20151031-git.tgz 6837 3ed818c26feeee4eba6dacbe4be622d5 51b658344270cf398a34798b321a377ca855bb8a com.google.base-20151031-git com.google.base-test.asd com.google.base.asd +command-line-arguments http://beta.quicklisp.org/archive/command-line-arguments/2019-12-27/command-line-arguments-20191227-git.tgz 11927 3ed82e1536b55fc0b7abc79626631aab 213d0538910a379a65c7919b2d39aee3abfe2cab command-line-arguments-20191227-git command-line-arguments.asd +common-doc http://beta.quicklisp.org/archive/common-doc/2016-04-21/common-doc-20160421-git.tgz 51299 516b26eb281a2c7a13161eb2346915f8 1a70ab2230e492f5f3a0bfb6ad8adc3a25332537 common-doc-20160421-git common-doc-contrib.asd common-doc-gnuplot.asd common-doc-graphviz.asd common-doc-include.asd common-doc-split-paragraphs.asd common-doc-test.asd common-doc-tex.asd common-doc.asd +common-doc-plump http://beta.quicklisp.org/archive/common-doc-plump/2016-04-21/common-doc-plump-20160421-git.tgz 6172 5e53d47b0bb2ad2d5bc1d6686b1446ba dc865b5fd8705da9ddbb20a44742ec5454679e12 common-doc-plump-20160421-git common-doc-plump-test.asd common-doc-plump.asd +common-html http://beta.quicklisp.org/archive/common-html/2016-04-21/common-html-20160421-git.tgz 7660 ab70df0dff34edb91d21b9eca3d5ba68 79ba08f283f191a1deeb0952447daded2e44cddf common-html-20160421-git common-html-test.asd common-html.asd +common-lisp-actors http://beta.quicklisp.org/archive/common-lisp-actors/2019-11-30/common-lisp-actors-20191130-git.tgz 4753 890e04c2f7df07e7180cbc7d81ed7bb5 5e927cacbb0fa3a49605423ca50b41626c1af00b common-lisp-actors-20191130-git cl-actors.asd +common-lisp-jupyter http://beta.quicklisp.org/archive/common-lisp-jupyter/2019-10-08/common-lisp-jupyter-20191008-git.tgz 84042 0a4b1e448dcaa528e7e43b2263a6bd59 2e3c7e7c98959c7200b651e744c43527ccdd2bd8 common-lisp-jupyter-20191008-git common-lisp-jupyter.asd +commonqt http://beta.quicklisp.org/archive/commonqt/2019-12-27/commonqt-20191227-git.tgz 61085 ec5826978ee14110ac866417388a24bf aaa433fca64abbf9b30d4714b8e1e9015bc2df37 commonqt-20191227-git qt+libs.asd qt-repl.asd qt-test.asd qt-tutorial.asd qt.asd +computable-reals http://beta.quicklisp.org/archive/computable-reals/2018-03-28/computable-reals-20180328-git.tgz 8146 9b7c4ffa4d91b1197be9f39621141175 f2d454e6bf5d6416d0a37605e9ec9f4a35c087f8 computable-reals-20180328-git computable-reals.asd +concrete-syntax-tree http://beta.quicklisp.org/archive/concrete-syntax-tree/2019-12-27/concrete-syntax-tree-20191227-git.tgz 42755 fc393a473bca784545f877c661e15fc7 36a516d426224a7d5e1e0b8bf06d608154ae7121 concrete-syntax-tree-20191227-git Destructuring/concrete-syntax-tree-destructuring.asd Lambda-list/Test/concrete-syntax-tree-lambda-list-test.asd Lambda-list/concrete-syntax-tree-lambda-list.asd Source-info/concrete-syntax-tree-source-info.asd concrete-syntax-tree-base.asd concrete-syntax-tree.asd +conduit-packages http://beta.quicklisp.org/archive/conduit-packages/2014-08-26/conduit-packages-20140826-http.tgz 5758 44257db8bdf0b87c42c5cb7e33e8efe3 a45e8aa50874f7837c4805df443266f9f496bb2a conduit-packages-20140826-http conduit-packages.asd +conf http://beta.quicklisp.org/archive/conf/2019-12-27/conf-20191227-git.tgz 15652 8b1e1498234b7b4d3ca9cd2f52b66415 9a5e80439fbb82d433465c632c8f901613a4baf5 conf-20191227-git conf.asd +configuration.options http://beta.quicklisp.org/archive/configuration.options/2019-07-10/configuration.options-20190710-git.tgz 129476 2ca51419ca5f6c62566cef94c5bf6c25 6a8c25c3a4ccb040f87f7b346df6d475fb8c415e configuration.options-20190710-git configuration.options-and-mop.asd configuration.options-and-puri.asd configuration.options-and-quri.asd configuration.options-and-service-provider.asd configuration.options-source-commandline.asd configuration.options-syntax-ini.asd configuration.options-syntax-xml.asd configuration.options.asd +conium http://beta.quicklisp.org/archive/conium/2018-08-31/conium-20180831-git.tgz 145062 60d1a37d859310d5bb50be5d2a011a1a 2ef38b57eda9a6bf6820729ab1ee6fddbe74cc2c conium-20180831-git conium.asd +consix http://beta.quicklisp.org/archive/consix/2014-12-17/consix-20141217-git.tgz 15428 6eb2f35075cab83f225f31bc72ffbb4f fb3e12d2614b5ec17d51bcc764990fbb997f4f2f consix-20141217-git consix.asd +constantfold http://beta.quicklisp.org/archive/constantfold/2019-12-27/constantfold-20191227-git.tgz 135729 e9e0021014c6f27280264be16166fee7 378cbed129d745f65125c9f3931f350e92d61c22 constantfold-20191227-git constantfold.asd constantfold.test.asd +contextl http://beta.quicklisp.org/archive/contextl/2019-05-21/contextl-20190521-git.tgz 26348 a4d8c6a69351ed26c0d8e26ebee0b8e1 c7ed0f7757991c10702a48c2d803344105075c23 contextl-20190521-git contextl.asd dynamic-wind.asd +copy-directory http://beta.quicklisp.org/archive/copy-directory/2016-06-28/copy-directory-20160628-git.tgz 2462 b82455b6979b785df488f990e156aa2b fe74b777a2f899c84de338f3c96b732cc1e2d06c copy-directory-20160628-git copy-directory-test.asd copy-directory.asd +corona http://beta.quicklisp.org/archive/corona/2016-08-25/corona-20160825-git.tgz 12412 75fdbf09861689695020ed0bcabb2bb3 bf12260d0c2c3b85f58fab8e872eaa059d9c12ca corona-20160825-git corona-test.asd corona-web.asd corona.asd +cover http://beta.quicklisp.org/archive/cover/2019-02-02/cover-20190202-git.tgz 17172 fdebe8767421553329d3620a2a0fcbc6 644769e371b3d0caaeb3cc676918a33dede6032a cover-20190202-git cover.asd +cqlcl http://beta.quicklisp.org/archive/cqlcl/2014-11-06/cqlcl-20141106-git.tgz 11896 2a63a524e1297e6a2577a29d63bd7ea2 7480e139c03880e1e41bca03ae6fde148a1ce161 cqlcl-20141106-git cqlcl.asd +crane http://beta.quicklisp.org/archive/crane/2016-02-08/crane-20160208-git.tgz 20738 df5119bed5754d9f7811efc770c09d47 d438f1997e83f251bb1b61653a2a0e6a08bccbda crane-20160208-git crane-test.asd crane.asd +croatoan http://beta.quicklisp.org/archive/croatoan/2019-12-27/croatoan-20191227-git.tgz 121276 beeb15e0c4008ad361d7ce20e1b72269 806cdd60ba813226684409a4c61978909343f10e croatoan-20191227-git croatoan-test.asd croatoan.asd +crypto-shortcuts http://beta.quicklisp.org/archive/crypto-shortcuts/2019-07-10/crypto-shortcuts-20190710-git.tgz 7150 2c6df84ebef1bc224c6c54c5112d0e04 bd30d942f16ef49e51a7dac01a799552d23c59fa crypto-shortcuts-20190710-git crypto-shortcuts.asd +cserial-port http://beta.quicklisp.org/archive/cserial-port/2017-04-03/cserial-port-20170403-git.tgz 10621 45e462dce2f7b68d1ca5e61906f115b3 4b2f943955a280573e46f95223f444a525759168 cserial-port-20170403-git cserial-port.asd +css-lite http://beta.quicklisp.org/archive/css-lite/2012-04-07/css-lite-20120407-git.tgz 6073 9b25afb0d2c3f0c32d2303ab1d3f570d 83ad13369198c8170fce93c6171f472fe8d7322a css-lite-20120407-git css-lite.asd +css-selectors http://beta.quicklisp.org/archive/css-selectors/2016-06-28/css-selectors-20160628-git.tgz 14832 28537144b89af4ebe28c2eb365d5569f 67e31993847a16f20b4eda93e1266644a426ff4c css-selectors-20160628-git css-selectors-simple-tree.asd css-selectors-stp.asd css-selectors.asd +csv http://beta.quicklisp.org/archive/csv/2019-07-10/csv-20190710-git.tgz 14041 cecd51e92195eb497c4b20d82c90930a 18cfd80c132c100ddac12ea2f82e9030783e0649 csv-20190710-git csv.asd +csv-parser http://beta.quicklisp.org/archive/csv-parser/2014-07-13/csv-parser-20140713-git.tgz 5012 d8f43b3da734b63f2064b7cd4c6f7550 033d33a6821c836cce4b2299e5ea688807ea12b3 csv-parser-20140713-git csv-parser.asd +cue-parser http://beta.quicklisp.org/archive/cue-parser/2018-02-28/cue-parser-20180228-git.tgz 6196 a762d2f16148e031ac658c19bc35fe95 dde1439487e627ca02f8d1e9641fbe40696b45bd cue-parser-20180228-git cue-parser.asd +curly http://beta.quicklisp.org/archive/curly/2012-04-07/curly-20120407-git.tgz 4647 abbdcfe5c08ee02a8f9014373db6fd86 adfe3715c7311e6a27755ca3da84155bcf93641a curly-20120407-git curly.asd +curry-compose-reader-macros http://beta.quicklisp.org/archive/curry-compose-reader-macros/2019-11-30/curry-compose-reader-macros-20191130-git.tgz 2800 013cf0caa673751961380f5f5d3d61be 25aa6825abe58369592458d8a5d855e7617ce396 curry-compose-reader-macros-20191130-git curry-compose-reader-macros.asd +curve http://beta.quicklisp.org/archive/curve/2013-01-28/curve-20130128-git.tgz 19617 f4c1a224405586a04d65cac6b38a5ccc 000367ed6ad72b814a533a633506ef30fda97271 curve-20130128-git com.elbeno.curve.asd +cxml http://beta.quicklisp.org/archive/cxml/2018-10-18/cxml-20181018-git.tgz 155061 33c5546de7099d65fdb2fbb716fd3de8 2e661fc6f2edb5d0d9c7923a4aa455803a90786b cxml-20181018-git cxml-dom.asd cxml-klacks.asd cxml-test.asd cxml.asd +cxml-rng http://beta.quicklisp.org/archive/cxml-rng/2019-07-10/cxml-rng-20190710-git.tgz 173375 ac7fb180022392f6cb689509bc14bab3 4cd12475c54fe7f34510a5d1d5b5fdb9c6403443 cxml-rng-20190710-git cxml-rng.asd +cxml-rpc http://beta.quicklisp.org/archive/cxml-rpc/2012-10-13/cxml-rpc-20121013-git.tgz 11422 58bca5e93a2f2eb5a5451e689b590c2b 0ada3a401ef59cbf83f0d4601b206895913711f6 cxml-rpc-20121013-git cxml-rpc.asd +cxml-stp http://beta.quicklisp.org/archive/cxml-stp/2019-05-21/cxml-stp-20190521-git.tgz 52265 9e0c99bd2b547e07b23305a5ff72aff6 d33d9dfe96de273f18696d15cf20e48c599f5678 cxml-stp-20190521-git cxml-stp.asd +daemon http://beta.quicklisp.org/archive/daemon/2017-04-03/daemon-20170403-git.tgz 4007 97d52817fa74191a6a07a49cd4a5b907 542f44f5a01f0d8bde303167edfa73cd2b5473cb daemon-20170403-git daemon.asd +dartsclemailaddress http://beta.quicklisp.org/archive/dartsclemailaddress/2016-04-21/dartsclemailaddress-quicklisp-release-48464635-git.tgz 11830 537619b8caa0c43db075a82f732a31ee bc0850e087137a945257bfafdc530b5f256ea5c6 dartsclemailaddress-quicklisp-release-48464635-git darts.lib.email-address-test.asd darts.lib.email-address.asd +dartsclhashtree http://beta.quicklisp.org/archive/dartsclhashtree/2019-11-30/dartsclhashtree-20191130-git.tgz 26824 98695e12a12439121037f85e65601406 2ca276fddec24d9815ad6646c4eb739267d371cf dartsclhashtree-20191130-git darts.lib.hashtree-test.asd darts.lib.hashtrie.asd darts.lib.wbtree.asd +dartsclmessagepack http://beta.quicklisp.org/archive/dartsclmessagepack/2015-05-05/dartsclmessagepack-20150505-git.tgz 8310 3323df326dfc7dc87219de82e14adaf7 5197fa8201d9dc3dccd13795058d49015dfcd57c dartsclmessagepack-20150505-git darts.lib.message-pack-test.asd darts.lib.message-pack.asd +dartsclsequencemetrics http://beta.quicklisp.org/archive/dartsclsequencemetrics/2013-03-12/dartsclsequencemetrics-20130312-git.tgz 8234 2440599722cb58ab64d30a687946166b 2a29fa7b05dff2273678b71dff33d1db79af1ff4 dartsclsequencemetrics-20130312-git darts.lib.sequence-metrics.asd +dartscltools http://beta.quicklisp.org/archive/dartscltools/2019-11-30/dartscltools-20191130-git.tgz 11484 87ea1ba235803b40f427fdcf844253e1 868175cc7f35ef717b1e2b67f55d3cdae4ae5fad dartscltools-20191130-git darts.lib.tools.asd +dartscluuid http://beta.quicklisp.org/archive/dartscluuid/2018-08-31/dartscluuid-20180831-git.tgz 7279 171eb01d8331bf101e4d4a8ca750e3e2 d532f54744a4578ced5481e49788dd034d02a0a0 dartscluuid-20180831-git darts.lib.uuid.asd +data-lens http://beta.quicklisp.org/archive/data-lens/2019-10-07/data-lens-20191007-git.tgz 39424 44764b0bc93f05b680e47c4f3b351a55 c41d78eea00a0beaf13d22a8868d6141842b5c34 data-lens-20191007-git data-lens.asd +data-sift http://beta.quicklisp.org/archive/data-sift/2013-01-28/data-sift-20130128-git.tgz 13070 2d023844d8a181dbbcc69368c3b90a9c 2ca3997e31fd229f29dc332b0a737ab23c62bb62 data-sift-20130128-git data-sift.asd +data-table http://beta.quicklisp.org/archive/data-table/2016-02-08/data-table-20160208-git.tgz 12042 0507150b0fcfdab96e0ef7668d31113c bfa3e175a53bea2d80b7358c7729e944d3781ec8 data-table-20160208-git data-table-clsql.asd data-table.asd +database-migrations http://beta.quicklisp.org/archive/database-migrations/2018-08-31/database-migrations-20180831-git.tgz 3983 2e3f0877c95e8fc8632a9fe7979bfe82 9c364cc2b74d76a3184be7e4a269e156521ae331 database-migrations-20180831-git database-migrations.asd +datafly http://beta.quicklisp.org/archive/datafly/2019-05-21/datafly-20190521-git.tgz 9762 e9f2d71b419516a501a5f9a782bf29d4 cfb320d68b303fa3851a70241bac28ee31aee280 datafly-20190521-git datafly-test.asd datafly.asd +datamuse http://beta.quicklisp.org/archive/datamuse/2019-12-27/datamuse-20191227-git.tgz 5912 a04c3124844336cdfad9bdb77828a11d d41fccf27d49d47e662345fc1e7ea06ef9498d04 datamuse-20191227-git datamuse.asd +date-calc http://beta.quicklisp.org/archive/date-calc/2019-12-27/date-calc-20191227-git.tgz 10417 fda245d738b350711fb614ba18ee01f4 6e55f21ffcedf6a36c8a212fde29a3ebb9f0ce85 date-calc-20191227-git date-calc.asd +datum-comments http://beta.quicklisp.org/archive/datum-comments/2019-08-13/datum-comments-20190813-git.tgz 3625 c3ad1f73fd4ece22e18f3b10106510f4 72113bce610b6b12d800586065c7425c70ae6fc8 datum-comments-20190813-git datum-comments.asd +dbd-oracle http://beta.quicklisp.org/archive/dbd-oracle/2018-03-28/dbd-oracle-20180328-git.tgz 39691 1e82985c46e557525af490981b5006ef fed08c112da3e508042b39d2bd47d59ceb4c3a1c dbd-oracle-20180328-git dbd-oracle-test.asd dbd-oracle.asd +dbus http://beta.quicklisp.org/archive/dbus/2019-05-21/dbus-20190521-git.tgz 23448 59e7ab92086503e4185273ec3f3ba3fc b63649ce3b7aae0107fb13d927a18e2d36cd284e dbus-20190521-git dbus.asd +de.setf.wilbur http://beta.quicklisp.org/archive/de.setf.wilbur/2018-12-10/de.setf.wilbur-20181210-git.tgz 77937 76864fbe1ad7bdf810efa74e2bb4765e 3a699742b7b8738c9f8cf51f391e9571f74b9f15 de.setf.wilbur-20181210-git src/wilbur.asd +declt http://beta.quicklisp.org/archive/declt/2019-11-30/declt-3.0.tgz 63861 3dff95e04c8e2e5b57ae0635b5cd32ec 519ceaae45727e2d7b982a53b657466714cf33bf declt-3.0 core/net.didierverna.declt.core.asd net.didierverna.declt.asd setup/net.didierverna.declt.setup.asd +deeds http://beta.quicklisp.org/archive/deeds/2019-07-10/deeds-20190710-git.tgz 35104 e450e559648cc639d52cd860c3f3acc6 833c7a206bc07c4671717d934d819b65157ec0be deeds-20190710-git deeds.asd +defclass-std http://beta.quicklisp.org/archive/defclass-std/2015-08-04/defclass-std-20150804-git.tgz 8922 cb335ba608a0ba468d3ab4ac8ab7d13c 8d3a192420a1124546d51844d5126732bb06635f defclass-std-20150804-git defclass-std-test.asd defclass-std.asd +defenum http://beta.quicklisp.org/archive/defenum/2019-01-07/defenum-20190107-git.tgz 13085 b6e5252710200ffff90cd26c551315eb aaffa0b7c21837ec518deae878c755be319dd07d defenum-20190107-git defenum.asd +deferred http://beta.quicklisp.org/archive/deferred/2019-07-10/deferred-20190710-git.tgz 5908 0830491b2d6bb9cfbc2a95036b9a7332 438d3927bc5dfe4215aaa39f79207e768ab45444 deferred-20190710-git deferred.asd +define-json-expander http://beta.quicklisp.org/archive/define-json-expander/2014-07-13/define-json-expander-20140713-git.tgz 5026 4f67d0f505ff548d386e3f6f3d24bef9 8ac3161ab7afd1de0a40473d86201b2fff87f17e define-json-expander-20140713-git define-json-expander.asd +definitions http://beta.quicklisp.org/archive/definitions/2019-10-07/definitions-20191007-git.tgz 22808 f108ab481145731b551d7e925658c1a1 e53c14d05bb4326f06e2165b751e5ab102c10761 definitions-20191007-git definitions.asd +definitions-systems http://beta.quicklisp.org/archive/definitions-systems/2018-12-10/definitions-systems-1.0.tgz 7147 611cd6ba8686c7644c6d0247e69e8118 af1e880079f06b7070f926e2a80de74f2d4d500e definitions-systems-1.0 definitions-systems.asd tests/definitions-systems_tests.asd +deflate http://beta.quicklisp.org/archive/deflate/2018-02-28/deflate-20180228-git.tgz 9418 a836910bc7b4b8cd1122d6da73316631 4772d9601c99ea4f91bb956f6e6e705fdb7a8d94 deflate-20180228-git deflate.asd +defmemo http://beta.quicklisp.org/archive/defmemo/2012-04-07/defmemo-20120407-git.tgz 1953 542105d03e8a0d012c21cefffed2f8ad e7d6f9f95ef8866e063c5e35eee1458e6022d7af defmemo-20120407-git defmemo.asd +defpackage-plus http://beta.quicklisp.org/archive/defpackage-plus/2018-01-31/defpackage-plus-20180131-git.tgz 6485 de7af07da901fe5623450d32fd4b7ddc dea6c565dee9b6d821b21a25f4169515e52595df defpackage-plus-20180131-git defpackage-plus.asd +defrec http://beta.quicklisp.org/archive/defrec/2019-03-07/defrec-20190307-hg.tgz 2488 28b1762c6fb45a24487be334d7d5db14 f5ea970dac951fd12455449ba66da09b471596e4 defrec-20190307-hg defrec.asd +defstar http://beta.quicklisp.org/archive/defstar/2014-07-13/defstar-20140713-git.tgz 46970 36db8379ba81239923e5f97dba352d8b 2983be99196ad25ad29404af66a6c61b6eca212a defstar-20140713-git defstar.asd +defsystem-compatibility http://beta.quicklisp.org/archive/defsystem-compatibility/2010-10-06/defsystem-compatibility-20101006-darcs.tgz 9848 ad19788379d30f53165b74683deee776 bc441cffe18d811b971e130cfa94b57938e353ec defsystem-compatibility-20101006-darcs defsystem-compatibility-test.asd defsystem-compatibility.asd +defvariant http://beta.quicklisp.org/archive/defvariant/2014-07-13/defvariant-20140713-git.tgz 10059 34cae097b3a510c71aec8638e6244384 8d43269b616dad7f0d0c9a6725e1614cb5c330c2 defvariant-20140713-git defvariant.asd +delorean http://beta.quicklisp.org/archive/delorean/2013-06-15/delorean-20130615-git.tgz 3788 441d44c6c37939df46fc1f6a549f97d6 f9b4b8ed3e1cf9811a32e19fa64f868598baf1c3 delorean-20130615-git delorean.asd +delta-debug http://beta.quicklisp.org/archive/delta-debug/2018-08-31/delta-debug-20180831-git.tgz 5769 0cfd1860910888e5d129e3a134a58e12 28dd1ae4e76fcd381539b1a09622525b083a7830 delta-debug-20180831-git delta-debug.asd +dendrite http://beta.quicklisp.org/archive/dendrite/2017-10-23/dendrite-release-quicklisp-409b1061-git.tgz 5988 574bb8da79376d36fdf04ae254ba04c5 d14f3b6356f3d6443fd76296e6c1ef32036045ca dendrite-release-quicklisp-409b1061-git dendrite.asd dendrite.micro-l-system.asd dendrite.primitives.asd +deoxybyte-gzip http://beta.quicklisp.org/archive/deoxybyte-gzip/2014-01-13/deoxybyte-gzip-20140113-git.tgz 130916 e6e373d376f3598f7ee3792e586a7dc3 53a1f55a7db874c66d5cf1f1ebf0800559e1584e deoxybyte-gzip-20140113-git deoxybyte-gzip-test.asd deoxybyte-gzip.asd +deoxybyte-io http://beta.quicklisp.org/archive/deoxybyte-io/2014-01-13/deoxybyte-io-20140113-git.tgz 40992 7283270d2df168edda80ec15bede2aa3 b4326e35061b6bed2625cb26cf545dd8984cb0e7 deoxybyte-io-20140113-git deoxybyte-io-test.asd deoxybyte-io.asd +deoxybyte-systems http://beta.quicklisp.org/archive/deoxybyte-systems/2014-01-13/deoxybyte-systems-20140113-git.tgz 3677 cb63033baf4ff3c8aaba80252e77f5d6 c306db96a2de41c23f2284164b9577cc1ba2c718 deoxybyte-systems-20140113-git deoxybyte-systems.asd +deoxybyte-unix http://beta.quicklisp.org/archive/deoxybyte-unix/2014-01-13/deoxybyte-unix-20140113-git.tgz 20104 058d5bc317967f587535fae8ee97a39f 6886a7daf781f97173d9cbb8fa84e3229054d260 deoxybyte-unix-20140113-git deoxybyte-unix-test.asd deoxybyte-unix.asd +deoxybyte-utilities http://beta.quicklisp.org/archive/deoxybyte-utilities/2014-01-13/deoxybyte-utilities-20140113-git.tgz 32707 1d29f3a612c1e7901b0fd053cac93f87 d9fa17f1f96255a973fe1c13b0b982197b303220 deoxybyte-utilities-20140113-git deoxybyte-utilities-test.asd deoxybyte-utilities.asd +deploy http://beta.quicklisp.org/archive/deploy/2019-11-30/deploy-20191130-git.tgz 20923 06a1abb219d7f23670bd3391beaa520a c02e00609dce7d2745ec799ced101a099321bddb deploy-20191130-git deploy-test.asd deploy.asd +descriptions http://beta.quicklisp.org/archive/descriptions/2015-03-02/descriptions-20150302-git.tgz 23662 b16c4d4768515759094d08043f6cd181 bae261da6cae337aabc0daa49fbe0f2d399dcecb descriptions-20150302-git descriptions-test.asd descriptions.asd descriptions.serialization.asd descriptions.validation.asd +destructuring-bind-star http://beta.quicklisp.org/archive/destructuring-bind-star/2018-10-18/destructuring-bind-star-20181018-git.tgz 3212 55e616f9df29c1d948f582cfbc7fe5af 4009c6cdb2aee5c28947b1b974934cd4f07d9584 destructuring-bind-star-20181018-git destructuring-bind-star.asd +dexador http://beta.quicklisp.org/archive/dexador/2019-10-07/dexador-20191007-git.tgz 235731 aa1c435f809a794610fe599987cb73a8 7144517ad2da8038bdbf61bcfabbb5adc7aaa06f dexador-20191007-git dexador-test.asd dexador.asd +diff http://beta.quicklisp.org/archive/diff/2013-08-13/diff-20130813-git.tgz 16642 c13a4545b12b26e6d99c5535048a435d dc6993e2890a59dd59dad95a098771117396e650 diff-20130813-git diff.asd +diff-match-patch http://beta.quicklisp.org/archive/diff-match-patch/2016-10-31/diff-match-patch-20161031-git.tgz 31108 70256cec4e141e3d0f88f0626e4cad8a 5bd2caadf478f6d941cf0771ce522ee02be862b5 diff-match-patch-20161031-git diff-match-patch.asd +dirt http://beta.quicklisp.org/archive/dirt/2017-10-19/dirt-release-quicklisp-0d13ebc2-git.tgz 5590 c3242835717a9db9c2db803d1b25f545 4ba2d03d1d5fad8f92e2683ac9c86e2d23b31678 dirt-release-quicklisp-0d13ebc2-git dirt.asd +disposable http://beta.quicklisp.org/archive/disposable/2016-02-08/disposable-20160208-git.tgz 1504 dd4e4ff956fb44ed624f8dafcaa4bea5 9ddcaa8fbf5ad43195e179882190fc68d4b58039 disposable-20160208-git disposable.asd +dissect http://beta.quicklisp.org/archive/dissect/2019-07-10/dissect-20190710-git.tgz 28483 fb0e90e86fe4c184c08d19c1ef61d4e4 a0330b1b69f02f46221e749956d78105e81d3d39 dissect-20190710-git dissect.asd +djula http://beta.quicklisp.org/archive/djula/2019-12-27/djula-20191227-git.tgz 84165 cc2836b922f4a6a6a09955bca4c2353c b482e8d335b4d44bca6b10173896383b896b0657 djula-20191227-git djula-demo.asd djula-test.asd djula.asd +dlist http://beta.quicklisp.org/archive/dlist/2012-11-25/dlist-20121125-git.tgz 14699 c935ee7e9bf0e30a5fd70ae703195f9e 2b23fc66cf9c4829828d4ef04b61938215c39c0f dlist-20121125-git dlist.asd +dml http://beta.quicklisp.org/archive/dml/2018-10-18/dml-20181018-git.tgz 440514 7423921f88d0a15f12fcba859ff518d9 48be480e302c2dd2151cda1d62ff8df9483c8814 dml-20181018-git dml.asd +do-urlencode http://beta.quicklisp.org/archive/do-urlencode/2018-10-18/do-urlencode-20181018-git.tgz 2318 cb6ab78689fe52680ee1b94cd7738b94 7eaef5c9b5cf8dfe004ad3a8fa101bad8193b3f1 do-urlencode-20181018-git do-urlencode.asd +docbrowser http://beta.quicklisp.org/archive/docbrowser/2019-07-10/docbrowser-20190710-git.tgz 905902 bfc1424c8de6eaf7150bb6e00a0222e7 004c4019482d81f82ffe5654a4fb0bb1f9656d1a docbrowser-20190710-git docbrowser.asd +docparser http://beta.quicklisp.org/archive/docparser/2018-12-10/docparser-20181210-git.tgz 13474 1fe23ad568298e975242358517e9871f 3391e2ee13c6c2c78fb8ed8028c6130ac7bf209e docparser-20181210-git docparser-test-system.asd docparser-test.asd docparser.asd +documentation-template http://beta.quicklisp.org/archive/documentation-template/2014-12-17/documentation-template-0.4.4.tgz 8721 847d38e9131779931cb7063e019afe5d 2cd71d1884d3eff7b76a0f907969b986c4125744 documentation-template-0.4.4 documentation-template.asd +documentation-utils http://beta.quicklisp.org/archive/documentation-utils/2019-07-10/documentation-utils-20190710-git.tgz 8913 4f45f511ac55008b8b8aa04f7feaa2d4 1071335af99636f62943713298b46a0244b5bda4 documentation-utils-20190710-git documentation-utils.asd multilang-documentation-utils.asd +documentation-utils-extensions http://beta.quicklisp.org/archive/documentation-utils-extensions/2018-07-11/documentation-utils-extensions-20180711-git.tgz 4676 e44cb3fbe27b04e2cceeb2240859a716 aaad552e01854bfc2fdd7758dde31edd3a2f5892 documentation-utils-extensions-20180711-git documentation-utils-extensions.asd +donuts http://beta.quicklisp.org/archive/donuts/2012-07-03/donuts-20120703-git.tgz 1232132 5d3e62b6453941a0bf64741c3df70b54 9c8061bcd3b2dd1443a1bccef991115169137482 donuts-20120703-git donuts.asd +doplus http://beta.quicklisp.org/archive/doplus/2019-03-07/doplus-20190307-hg.tgz 26769 6784a90135fc635ee016c490c535a218 014fdd3f79104f08209210fcf7806af3c428e1dd doplus-20190307-hg doplus-fset.asd doplus.asd +doubly-linked-list http://beta.quicklisp.org/archive/doubly-linked-list/2019-07-10/doubly-linked-list-20190710-git.tgz 3464 315b9f70ee726211f694fd81f17f5283 24a1e9aa58ecf2dd19c8a6bd7b82b0acdfc3862c doubly-linked-list-20190710-git doubly-linked-list.asd +drakma http://beta.quicklisp.org/archive/drakma/2019-11-30/drakma-v2.0.7.tgz 74290 f166498aaed67f726060e9e997df10a3 0920ad374a9b5d513efae5dc61af2484dc901d86 drakma-v2.0.7 drakma-test.asd drakma.asd +drakma-async http://beta.quicklisp.org/archive/drakma-async/2015-10-31/drakma-async-20151031-git.tgz 24061 7048777c70eeba4456b19e2cb6ab83ae c4cf9dcbc5a295bbf3187ef39e9b391155f36392 drakma-async-20151031-git drakma-async.asd +draw-cons-tree http://beta.quicklisp.org/archive/draw-cons-tree/2013-10-03/draw-cons-tree-20131003-git.tgz 2252 ce720e2ddf395246927e5765f5116084 94e6c5794403485da7bce440547e4e5cb59afb92 draw-cons-tree-20131003-git draw-cons-tree.asd +dso-lex http://beta.quicklisp.org/archive/dso-lex/2011-01-10/dso-lex-0.3.2.tgz 16481 fe8a4a6b9689c06f93f19c1b5506132d 2fac198fb75b4db2d2a1eb02479c94c0c3fa255a dso-lex-0.3.2 dso-lex.asd +dso-util http://beta.quicklisp.org/archive/dso-util/2011-01-10/dso-util-0.1.2.tgz 11309 ad11cec0f5a04142bcd5e117e53c7267 d861e27a509cd972ede6c7377fdc93abfa2c727a dso-util-0.1.2 dso-util.asd +dufy http://beta.quicklisp.org/archive/dufy/2019-11-30/dufy-20191130-git.tgz 482953 a61931fe902574a80df60eed19bb6805 fcb19f7921d363f04eb2196fb28ec00afa5dced3 dufy-20191130-git dufy.asd +duologue http://beta.quicklisp.org/archive/duologue/2015-04-07/duologue-20150407-git.tgz 6711 c5fca14a43ee08bc81f89e1cec71e0b0 49147aaaed48dcab2e57ce97e2ff07d4bfdced92 duologue-20150407-git duologue.asd +dweet http://beta.quicklisp.org/archive/dweet/2014-12-17/dweet-20141217-git.tgz 3051 68c4fe0638b6f9febe93925d4fd0cc33 b13c3333a955b851ee4286f5bd1583f09e9e8f75 dweet-20141217-git dweet.asd +dyna http://beta.quicklisp.org/archive/dyna/2018-04-30/dyna-20180430-git.tgz 25788 9ee5811b22d4692a11320a3ad9ce1ec5 f9981ccccdbf77753179dab0e77150c57d9a817b dyna-20180430-git dyna-test.asd dyna.asd +dynamic-classes http://beta.quicklisp.org/archive/dynamic-classes/2013-01-28/dynamic-classes-20130128-git.tgz 7148 a6ed01c4f21df2b6a142328b24ac7ba3 641573761b2d4fab3b17196cc10a9d46486ab495 dynamic-classes-20130128-git dynamic-classes-test.asd dynamic-classes.asd +dynamic-collect http://beta.quicklisp.org/archive/dynamic-collect/2019-03-07/dynamic-collect-20190307-hg.tgz 447578 c182c60ccb418c9f996f2fe48478cfbf 13d9d81f629b6c665753741ffa45b646f7caeb56 dynamic-collect-20190307-hg dynamic-collect.asd +dynamic-mixins http://beta.quicklisp.org/archive/dynamic-mixins/2018-10-18/dynamic-mixins-20181018-git.tgz 2492 8b2072af2b472c2c7bbaf28ff38e43be a389ddf18ddec5f634f28e506e349b83117085eb dynamic-mixins-20181018-git dynamic-mixins.asd +eager-future http://beta.quicklisp.org/archive/eager-future/2010-10-06/eager-future-20101006-darcs.tgz 3181 33ec9918cece34f35f2354e1f94a245c 862750b95d33edacbc73b08a636b9689a6167336 eager-future-20101006-darcs eager-future.asd +eager-future2 http://beta.quicklisp.org/archive/eager-future2/2019-11-30/eager-future2-20191130-git.tgz 26961 72298620b0fb2f874d86d887cce4acf0 70c0531898eddae204d38b0f5f2dd7c9d7381e8b eager-future2-20191130-git eager-future2.asd test.eager-future2.asd +easing http://beta.quicklisp.org/archive/easing/2018-02-28/easing-20180228-git.tgz 4636 775f27d44c58ff05c38ead610168f1ee 2e8889e1e4e5ece9d39b0d1f99cbe7b352b55ace easing-20180228-git easing-demo.asd easing-test.asd easing.asd +easy-audio http://beta.quicklisp.org/archive/easy-audio/2019-12-27/easy-audio-20191227-git.tgz 48893 144ad89fb846739df044683e05ee7aac 4c4a7c22d1cc3edb311822fa35d87590d19ef62c easy-audio-20191227-git easy-audio-examples.asd easy-audio-tests.asd easy-audio.asd +easy-bind http://beta.quicklisp.org/archive/easy-bind/2019-02-02/easy-bind-20190202-git.tgz 16880 ee624a12d458bdb17f4b3dfe7772f699 9240ed116049d326453d744303e65213704859c8 easy-bind-20190202-git easy-bind.asd +easy-routes http://beta.quicklisp.org/archive/easy-routes/2019-08-13/easy-routes-20190813-git.tgz 6334 8716f16268ed259deb98ac29662722d9 13649c2cd2a61ec73ab1fe159ee0060bca1387ff easy-routes-20190813-git easy-routes.asd +eazy-documentation http://beta.quicklisp.org/archive/eazy-documentation/2019-12-27/eazy-documentation-20191227-git.tgz 17422 494e67c0a0de0e1c45854129e1551f96 1b0c6db59b09899d8a1f424ed7c419f30f4bc554 eazy-documentation-20191227-git eazy-documentation.asd +eazy-gnuplot http://beta.quicklisp.org/archive/eazy-gnuplot/2018-08-31/eazy-gnuplot-20180831-git.tgz 8339018 5847b95b76c3a6ca908572c01ecd8474 d2ef349292b5c42baf46cd53834aefa9cb2df2cf eazy-gnuplot-20180831-git eazy-gnuplot.asd eazy-gnuplot.test.asd +eazy-process http://beta.quicklisp.org/archive/eazy-process/2015-12-18/eazy-process-20151218-git.tgz 27785 67eb10100308f984571ad75db1f77bf6 98ab4e587b7ccf079c8f77d5a6013289a21a36d1 eazy-process-20151218-git eazy-process.asd eazy-process.test.asd +eazy-project http://beta.quicklisp.org/archive/eazy-project/2019-07-10/eazy-project-20190710-git.tgz 15917 5b365c1ae21d9faf6eb7cfbb79b729cd 1e037cfaa916d41d7192fac829034426042a5bb4 eazy-project-20190710-git eazy-project.asd eazy-project.autoload.asd eazy-project.test.asd +ec2 http://beta.quicklisp.org/archive/ec2/2012-09-09/ec2-20120909-git.tgz 23603 0c6dea76f190aaa25305490b3e048437 d82ca8949aced8d7ef5fe3ca6bc02a1a3f1ab2a7 ec2-20120909-git ec2.asd +eclector http://beta.quicklisp.org/archive/eclector/2019-12-27/eclector-20191227-git.tgz 132183 b63ea9792bb5808adddd17fdedd35a38 3446a00516f7bda6135a5136bcd482f5e73ad969 eclector-20191227-git eclector-concrete-syntax-tree.asd eclector.asd +eco http://beta.quicklisp.org/archive/eco/2019-08-13/eco-20190813-git.tgz 6304 f27079c961c837ffc28f4d8c1a5cf81e 386d0cea4efbb4269e6b22d8387e447986c870cd eco-20190813-git eco-test.asd eco.asd +elb-log http://beta.quicklisp.org/archive/elb-log/2015-09-23/elb-log-20150923-git.tgz 6870 5eb6513fd03c1b015b9f215f96ba9d3b bd104f69efa8db03bdade2bf6fe70c61cd4b58e3 elb-log-20150923-git elb-log-test.asd elb-log.asd +electron-tools http://beta.quicklisp.org/archive/electron-tools/2016-04-21/electron-tools-20160421-git.tgz 2560 70ce32f5c79a23cff6c7fef7677422b4 d3de418ea520e7d7e672ad391a5905e1e72efd06 electron-tools-20160421-git electron-tools-test.asd electron-tools.asd +elf http://beta.quicklisp.org/archive/elf/2019-07-10/elf-20190710-git.tgz 473583 7edebf956ba1892304407f475bf6bdfe 6f7a1bfb3c1930c586d374122158c5a28dc34c56 elf-20190710-git elf.asd +enhanced-eval-when http://beta.quicklisp.org/archive/enhanced-eval-when/2012-11-25/enhanced-eval-when-1.0.tgz 1875 4cf59d63539f41b7b0c412f6d9e89ff5 48f3d1a21ddb4f8440d0c04f5a2b45da9bb4438c enhanced-eval-when-1.0 enhanced-eval-when.asd +enhanced-multiple-value-bind http://beta.quicklisp.org/archive/enhanced-multiple-value-bind/2012-11-25/enhanced-multiple-value-bind-1.0.1.tgz 2589 a0fdb32762b7bf6a8cd4b04f07bb05a1 cf4a330e2b640e43bb70ff5da1c7ab7fc97e8a19 enhanced-multiple-value-bind-1.0.1 enhanced-multiple-value-bind.asd +envy http://beta.quicklisp.org/archive/envy/2019-08-13/envy-20190813-git.tgz 3558 1f82d7f3221043577e44772d27d44932 73a1c0d37dfd06abd6bd7a1368aa4735c52845b7 envy-20190813-git envy-test.asd envy.asd +eos http://beta.quicklisp.org/archive/eos/2015-06-08/eos-20150608-git.tgz 13161 94f6a72534171ff6adcc823c31e3d53f bbfeefe9f70dd744142060ef1e96f85092bfdef7 eos-20150608-git eos.asd +epigraph http://beta.quicklisp.org/archive/epigraph/2016-06-28/epigraph-20160628-git.tgz 17490 6666b31324773f5aa275660da4cdedcc 9b971c5aabbd4b3b3ec2753766c37114ccd634a8 epigraph-20160628-git epigraph.asd +equals http://beta.quicklisp.org/archive/equals/2014-08-26/equals-20140826-git.tgz 2963 5acfaaebd7e1a683b3a84f85b7413340 a3321de358488a827d8535e9b947a316b914f5f5 equals-20140826-git equals.asd +ernestine http://beta.quicklisp.org/archive/ernestine/2016-12-04/ernestine-20161204-git.tgz 305333 1f254cb1f061e846181360fe059ca20d 170f5f6b5622462afa2f8b5d266aaa1b61e7e083 ernestine-20161204-git ernestine-tests.asd ernestine.asd +erudite http://beta.quicklisp.org/archive/erudite/2019-10-07/erudite-20191007-git.tgz 376268 d6de2a638ed93f2f87647be695e7e85f 9cad42dc1203dab78f12799ec4bd3c9bc62c9801 erudite-20191007-git erudite-test.asd erudite.asd +escalator http://beta.quicklisp.org/archive/escalator/2019-03-07/escalator-20190307-hg.tgz 4906 fff63c0a1de90711325f5952ae344e2e 935dbda8a5a4539db23d7555ed47060b2e882204 escalator-20190307-hg escalator-bench.asd escalator.asd +esrap http://beta.quicklisp.org/archive/esrap/2019-12-27/esrap-20191227-git.tgz 69274 8dd58ffc605bba6eec614bdea573978b 7ab73af2e8a3346142280622dd4a6d09936a8159 esrap-20191227-git esrap.asd +esrap-liquid http://beta.quicklisp.org/archive/esrap-liquid/2016-10-31/esrap-liquid-20161031-git.tgz 35689 7bc12d040919cb5b5da641334a1f23a1 9c8b389cc2c147922bbbc9be7a21c31c06a1b888 esrap-liquid-20161031-git esrap-liquid.asd +esrap-peg http://beta.quicklisp.org/archive/esrap-peg/2019-10-07/esrap-peg-20191007-git.tgz 7824 48d87d3118febeefc23ca3a8dda36fc0 27a86bbcd4eb649ac379c6b9ba0093234f285ff0 esrap-peg-20191007-git esrap-peg.asd +event-emitter http://beta.quicklisp.org/archive/event-emitter/2018-12-10/event-emitter-20181210-git.tgz 3346 1b6cb3e12d074e35da563e7163b47a91 651ad4bc759d2a947fb8ecd72d1f67f4d19c2d08 event-emitter-20181210-git event-emitter-test.asd event-emitter.asd +event-glue http://beta.quicklisp.org/archive/event-glue/2015-06-08/event-glue-20150608-git.tgz 9282 1aa70e889ffd2a2d01e7ee740c057415 faedf03cac4300b60f270a365e11a4dba5a74789 event-glue-20150608-git event-glue-test.asd event-glue.asd +eventbus http://beta.quicklisp.org/archive/eventbus/2019-12-27/eventbus-20191227-git.tgz 15807 99b4ca9efc30825dd56e77ae6cd5afe3 85c30ca68cb565572b5a5595e5d5a34e8f5e16c4 eventbus-20191227-git eventbus.asd +eventfd http://beta.quicklisp.org/archive/eventfd/2017-11-30/eventfd-20171130-git.tgz 2518 6580eb40265070dc8292ed4c2a137ee8 8fdce2b98e2d7d6d437a73a5de85f882c0c60859 eventfd-20171130-git eventfd.asd +everblocking-stream http://beta.quicklisp.org/archive/everblocking-stream/2018-10-18/everblocking-stream-20181018-git.tgz 887 307e7b6ba7ecb8912492497d7025e1cd 5539bdd086bef5526c4487ce9634239ac7f204b9 everblocking-stream-20181018-git everblocking-stream.asd +evol http://beta.quicklisp.org/archive/evol/2010-10-06/evol-20101006-git.tgz 36040 063813e42d598be1073625c38cc0fc76 de2a0507ad9682b4f783d23d8e579859e5283763 evol-20101006-git evol-test.asd evol.asd +exit-hooks http://beta.quicklisp.org/archive/exit-hooks/2017-04-03/exit-hooks-20170403-git.tgz 3070 9a5c96e590462bd417f1940ce9d374d2 2d5fb7624a86f2efec0106def24306beece56d53 exit-hooks-20170403-git exit-hooks.asd +exponential-backoff http://beta.quicklisp.org/archive/exponential-backoff/2015-01-13/exponential-backoff-20150113-git.tgz 2397 d3e5d082518de0e1d03ad6a8dac63f07 06dea928582daa17b07682a2df406de61205c63e exponential-backoff-20150113-git exponential-backoff.asd +exscribe http://beta.quicklisp.org/archive/exscribe/2017-04-03/exscribe-20170403-git.tgz 30757 a7317b96ab623ce1795d0e01c070daff 628b19937fb8477a42792829202dbf9ae9f634b6 exscribe-20170403-git exscribe.asd +ext-blog http://beta.quicklisp.org/archive/ext-blog/2016-08-25/ext-blog-20160825-git.tgz 393481 74fbc8b459a0d074c6fd08bbbd644c31 de4620d23fe78be0a39d8768724c86e074365252 ext-blog-20160825-git ext-blog.asd +extended-reals http://beta.quicklisp.org/archive/extended-reals/2018-03-28/extended-reals-20180328-git.tgz 2979 191bca02ac2c4a55ccc98aa6eda82f66 7d1fba685087c2236a5dd24abdc070f1b2394c4b extended-reals-20180328-git extended-reals.asd +external-program http://beta.quicklisp.org/archive/external-program/2019-03-07/external-program-20190307-git.tgz 10408 b30fe104c34059506fd4c493fa79fe1a f04bc9e1b3a0eb5b4c017a8799b9483fc10ea0ff external-program-20190307-git external-program.asd +external-symbol-not-found http://beta.quicklisp.org/archive/external-symbol-not-found/2018-04-30/external-symbol-not-found-20180430-git.tgz 2882 20cc0679a0de51547810d9f75c04d350 1b7140c2efa0f4b342568c8a34079c478d3c94c7 external-symbol-not-found-20180430-git external-symbol-not-found.asd +f-underscore http://beta.quicklisp.org/archive/f-underscore/2010-10-06/f-underscore-20101006-darcs.tgz 982 45ef9c0ac1c92d9aba76b69b53cc7838 34c192987ab8b11f9b09ba40098fc696250506e6 f-underscore-20101006-darcs f-underscore.asd +f2cl http://beta.quicklisp.org/archive/f2cl/2019-01-07/f2cl-20190107-git.tgz 2132799 3e24767fe26aa1bc1c6da904b8027d68 7de3a8a885f825a233e7523ae97354801ed08fb9 f2cl-20190107-git f2cl-asdf.asd f2cl.asd packages/blas-complex.asd packages/blas-hompack.asd packages/blas-package.asd packages/blas-real.asd packages/blas.asd packages/colnew.asd packages/fishpack.asd packages/hompack.asd packages/lapack.asd packages/minpack.asd packages/odepack.asd packages/quadpack.asd packages/toms419.asd packages/toms715.asd packages/toms717.asd +fact-base http://beta.quicklisp.org/archive/fact-base/2018-03-28/fact-base-20180328-git.tgz 9491 86825a1ba98fe3aa2866ec7e3452a371 26a527bafcf2bd38221c9bd737ca15660d0bed9e fact-base-20180328-git fact-base.asd +fare-csv http://beta.quicklisp.org/archive/fare-csv/2017-12-27/fare-csv-20171227-git.tgz 7223 1d73aaac9fcd86cc5ddb72019722bc2a d7cdb3a2b3ca5b92953201cc8769998fd8ee65de fare-csv-20171227-git fare-csv.asd +fare-memoization http://beta.quicklisp.org/archive/fare-memoization/2018-04-30/fare-memoization-20180430-git.tgz 7571 7446aa643f0e461d960efb673a706dc1 ef47d67c6d76e8e0c829bbd654e27b69e08fef3b fare-memoization-20180430-git fare-memoization.asd +fare-mop http://beta.quicklisp.org/archive/fare-mop/2015-12-18/fare-mop-20151218-git.tgz 2728 4721ff62e2ac2c55079cdd4f2a0f6d4a cd1f7fcd2aa132432f271f43de9cf39aeef37c71 fare-mop-20151218-git fare-mop.asd +fare-quasiquote http://beta.quicklisp.org/archive/fare-quasiquote/2019-05-21/fare-quasiquote-20190521-git.tgz 16060 e08c24d35a485a74642bd0c7c06662d6 b441f6dadd12309bd7cf1cba64f41fc9ca7974d6 fare-quasiquote-20190521-git fare-quasiquote-extras.asd fare-quasiquote-optima.asd fare-quasiquote-readtable.asd fare-quasiquote-test.asd fare-quasiquote.asd +fare-scripts http://beta.quicklisp.org/archive/fare-scripts/2019-10-07/fare-scripts-20191007-git.tgz 41613 be86769065461713423ac98bef91b900 1f2ffe437dbb926c9e728227a9d7c0f6172ad349 fare-scripts-20191007-git fare-scripts.asd +fare-utils http://beta.quicklisp.org/archive/fare-utils/2017-01-24/fare-utils-20170124-git.tgz 32604 6752362d0c7c03df6576ab2dbe807ee2 e0b139600b7693a13eece65ff148464168ae890b fare-utils-20170124-git fare-utils.asd test/fare-utils-test.asd +fast-http http://beta.quicklisp.org/archive/fast-http/2019-10-07/fast-http-20191007-git.tgz 33540 fd43be4dd72fd9bda5a3ecce87104c97 419610a07b0ccf3117378b6fb9b5faa025037d0b fast-http-20191007-git fast-http-test.asd fast-http.asd +fast-io http://beta.quicklisp.org/archive/fast-io/2017-10-23/fast-io-20171023-git.tgz 8067 89105f8277f3bf3709fae1b789e3d5ad c1cb21c5c9100e067b405fece7ee5f22bcc36f9f fast-io-20171023-git fast-io-test.asd fast-io.asd +fast-websocket http://beta.quicklisp.org/archive/fast-websocket/2019-08-13/fast-websocket-20190813-git.tgz 9136 1bfc212b4e196049ab66598b9055c225 ec4ff9ece37aba5d6885cbbf7184ad2032663fa2 fast-websocket-20190813-git fast-websocket-test.asd fast-websocket.asd +femlisp http://beta.quicklisp.org/archive/femlisp/2019-12-27/femlisp-20191227-git.tgz 648961 5ce598c1a5073081ab7621a9fb2eba72 fa87977048b8494b5902a9a4c22b17aaee31b636 femlisp-20191227-git external/cl-cpu-affinity/cl-cpu-affinity.asd external/infix/infix.asd src/applications/courses/dealii-tutorial/dealii-tutorial.asd src/contrib/femlisp-picture.asd src/ddo/ddo.asd src/femlisp-ddo/net.scipolis.graphs.asd systems/femlisp-basic.asd systems/femlisp-dictionary.asd systems/femlisp-matlisp.asd systems/femlisp-parallel.asd systems/femlisp.asd +ffa http://beta.quicklisp.org/archive/ffa/2010-10-06/ffa-20101006-git.tgz 79415 5fe81065a6834b2095373667f5d58426 a3d137edc9af56e3ba853082a2b30f59f7bb79b4 ffa-20101006-git ffa.asd +fft http://beta.quicklisp.org/archive/fft/2018-07-11/fft-20180711-git.tgz 4806 06c2d33d8ddd43332dc25ac4ea7f20cc f77ba0a8d9ccf55d8daaebe31a7053e78a2c29c2 fft-20180711-git fft.asd pfft.asd +fiasco http://beta.quicklisp.org/archive/fiasco/2019-11-30/fiasco-20191130-git.tgz 18955 235809b661c89fed1c4ca4ba3e4f3606 71ac8b6cc0d93752c76872d329818cc692ed32a9 fiasco-20191130-git fiasco.asd +file-local-variable http://beta.quicklisp.org/archive/file-local-variable/2016-03-18/file-local-variable-20160318-git.tgz 3725 8c486b517f733978fa3224ae225a5829 ab4f69526c059b17f5262006217f43b17f217358 file-local-variable-20160318-git file-local-variable.asd file-local-variable.test.asd +file-select http://beta.quicklisp.org/archive/file-select/2019-12-27/file-select-20191227-git.tgz 16660 792889047c3f0713c4ecd014f592b380 7f59269e56af417095f4027f6c52adbc10bbb246 file-select-20191227-git file-select.asd +file-types http://beta.quicklisp.org/archive/file-types/2016-09-29/file-types-20160929-git.tgz 16146 4fd40465a8bde55c444c65bdcb238a95 ef2a666fadb709340caf6340043fc21c157b4ec6 file-types-20160929-git file-types.asd +filtered-functions http://beta.quicklisp.org/archive/filtered-functions/2016-03-18/filtered-functions-20160318-git.tgz 5624 1a30c0712c4750954a9b645bdc6362cc 76f362ebb3655223f646d4be53dcc85572b307a8 filtered-functions-20160318-git filtered-functions.asd +find-port http://beta.quicklisp.org/archive/find-port/2019-07-10/find-port-20190710-git.tgz 2053 50b5558caf3cc39cc6b55142b6630404 2f18aa155913ec653ae88804cab4422e0e05fb23 find-port-20190710-git find-port-test.asd find-port.asd +firephp http://beta.quicklisp.org/archive/firephp/2016-05-31/firephp-20160531-git.tgz 3101 776c31d2d1d29e0f8ddf916d66f57416 354083daca9bc6e502792af81300ebdaf7fbfd1a firephp-20160531-git firephp-tests.asd firephp.asd +first-time-value http://beta.quicklisp.org/archive/first-time-value/2018-12-10/first-time-value-1.0.1.tgz 4590 ad1d225958063396e5260d963ffbb6e3 20c732c8a5b0b32c80b5d23eb1f70e4c98614d0c first-time-value-1.0.1 first-time-value.asd tests/first-time-value_tests.asd +fiveam http://beta.quicklisp.org/archive/fiveam/2018-02-28/fiveam-v1.4.1.tgz 24014 7f182f8a4c12b98671e1707ae0f140b7 42e5b2e54ef6cda091ce116963d2eea30bb48f6b fiveam-v1.4.1 fiveam.asd +fiveam-asdf http://beta.quicklisp.org/archive/fiveam-asdf/2019-07-10/fiveam-asdf-20190710-git.tgz 3484 951689cab836f8cefafcf75dd324eb23 b870df02fbca25d3f4adf4aa843081324669e353 fiveam-asdf-20190710-git fiveam-asdf.asd +fixed http://beta.quicklisp.org/archive/fixed/2017-01-24/fixed-20170124-git.tgz 12070 738197e9e3f84c000df9f7c270f49401 58f9ec849945c966fa5f539fc7fd3d1ff8178d3d fixed-20170124-git fixed.asd +flac-metadata http://beta.quicklisp.org/archive/flac-metadata/2019-07-10/flac-metadata-20190710-git.tgz 6580 a3cef395abd5beae99ba60f394f8e7b6 d7d0d842ece10d903bfcbc9ecaccca84ecd7fcd8 flac-metadata-20190710-git flac-metadata.asd +flac-parser http://beta.quicklisp.org/archive/flac-parser/2019-07-10/flac-parser-20190710-git.tgz 11365 26b6e66cc7d2c0a886d615f7a581b0e9 c70a38376cb8d55eb03d53c546f39c52155d2697 flac-parser-20190710-git flac-parser.asd +flare http://beta.quicklisp.org/archive/flare/2019-07-10/flare-20190710-git.tgz 58017 a15c9be05e27bfc9c3986fca21fda893 82f93831b5a49164bd9646edfcfd05462deb7c37 flare-20190710-git flare.asd viewer/flare-viewer.asd +flexi-streams http://beta.quicklisp.org/archive/flexi-streams/2019-01-07/flexi-streams-20190107-git.tgz 132948 b59014f9f9f0d1b94f161e36e64a35c2 d3d3a0dcedf92fccce96fcfb47561487b5bdde73 flexi-streams-20190107-git flexi-streams.asd +flexichain http://beta.quicklisp.org/archive/flexichain/2010-10-06/flexichain_1.5.1.tgz 19919 e63247e4e3f61ec768c5ceff0a5e1293 7eb528e31fea545467c6b629094a335dadbebe3f flexichain_1.5.1 flexichain-doc.asd flexichain.asd +float-features http://beta.quicklisp.org/archive/float-features/2019-10-07/float-features-20191007-git.tgz 6721 21215bd53d6c23908b92a4afd47a2880 91d3fe44e93a2f430d83496fadce7f6b16981fce float-features-20191007-git float-features.asd +floating-point http://beta.quicklisp.org/archive/floating-point/2014-11-06/floating-point-20141106-git.tgz 473538 2ebe55f78c56d8ca5af9d1e0914b6402 b894b79a5fb145795d45488395056efa86277310 floating-point-20141106-git lisp/floating-point.asd test/floating-point-test.asd +floating-point-contractions http://beta.quicklisp.org/archive/floating-point-contractions/2016-06-28/floating-point-contractions-20160628-git.tgz 1925 0250c90f09a3b6970560da61a22c3f67 503f4aff7528ba6302a22b953a14af263ff8e020 floating-point-contractions-20160628-git floating-point-contractions.asd +flow http://beta.quicklisp.org/archive/flow/2019-08-13/flow-20190813-git.tgz 29847 b74593ef1f3bd9838693b8595ae5e5c0 642af5ba117c129373f3c7d4e95a78f937e9f9c8 flow-20190813-git flow.asd visualizer/flow-visualizer.asd +flute http://beta.quicklisp.org/archive/flute/2018-08-31/flute-20180831-git.tgz 13138 8c312b0e18c10e7f03b81fc19587b786 632821535927afe4fe360af6ffcd6e1f2f6780bc flute-20180831-git flute-test.asd flute.asd +fmt http://beta.quicklisp.org/archive/fmt/2016-03-18/fmt-20160318-git.tgz 15539 94092c9cff6b2b24cddd779a0e059b6e 844964ccdb739dc6b569cd7627779600a4269661 fmt-20160318-git fmt-test.asd fmt-time.asd fmt.asd +fn http://beta.quicklisp.org/archive/fn/2017-10-19/fn-20171019-git.tgz 6936 0e1cfe5f19ceec8966baa3037772d31e 64871b26712de944ff79e1f58b0e7f4952044810 fn-20171019-git fn.asd +focus http://beta.quicklisp.org/archive/focus/2017-04-03/focus-20170403-git.tgz 47354 2be0459474ffdf328f5139164531a46e 84ef144a2ae449c507a5eaa37ef7c4274b15c36d focus-20170403-git core/net.didierverna.focus.core.asd demos/quotation/net.didierverna.focus.demos.quotation.asd flv/net.didierverna.focus.flv.asd net.didierverna.focus.asd setup/net.didierverna.focus.setup.asd +folio http://beta.quicklisp.org/archive/folio/2013-01-28/folio-20130128-git.tgz 21241 6f675b7346e8fcd492d4fde527eaa5ac bf20129ce9e18991bb60d1e20dc6c489c9529819 folio-20130128-git as/folio.as.asd boxes/folio.boxes.asd collections/folio.collections.asd folio.asd functions/folio.functions.asd +folio2 http://beta.quicklisp.org/archive/folio2/2019-10-07/folio2-20191007-git.tgz 55271 df04ee7b930f3eec45293a26523c2f42 539dca8db49ca54e344e0f6ba902ea3301ecd745 folio2-20191007-git folio2-as-syntax.asd folio2-as-tests.asd folio2-as.asd folio2-boxes-tests.asd folio2-boxes.asd folio2-functions-syntax.asd folio2-functions-tests.asd folio2-functions.asd folio2-make-tests.asd folio2-make.asd folio2-maps-syntax.asd folio2-maps-tests.asd folio2-maps.asd folio2-pairs-tests.asd folio2-pairs.asd folio2-sequences-syntax.asd folio2-sequences-tests.asd folio2-sequences.asd folio2-series-tests.asd folio2-series.asd folio2-taps-tests.asd folio2-taps.asd folio2-tests.asd folio2.asd +fomus http://beta.quicklisp.org/archive/fomus/2012-09-09/fomus-20120909-svn.tgz 1142093 f23d94ff232efc377e331114e62c508f ca319a5373898758cccfa40c4a37feef523d2a1a fomus-20120909-svn fomus.asd +font-discovery http://beta.quicklisp.org/archive/font-discovery/2019-10-07/font-discovery-20191007-git.tgz 14711 625c16ab54bee0f441482fcd535f3cfa 5b9db7476c19d53c6863f09bc95297da27c891db font-discovery-20191007-git font-discovery.asd +for http://beta.quicklisp.org/archive/for/2019-07-10/for-20190710-git.tgz 37031 69b66819a3e64c77fa9832d9d4d188a1 cb94c7ab09f15d6a75e95013d620163c728a197a for-20190710-git for.asd +form-fiddle http://beta.quicklisp.org/archive/form-fiddle/2019-07-10/form-fiddle-20190710-git.tgz 5635 2576065de1e3c95751285fb155f5bcf6 a6a057c05e5512f2f8a0a05e336d422646d76b2c form-fiddle-20190710-git form-fiddle.asd +format-string-builder http://beta.quicklisp.org/archive/format-string-builder/2017-01-24/format-string-builder-20170124-git.tgz 5303 4997e60ed7af0f32d1c5b06f19247288 89a375a3ed8fb7c2cb8f1805403ebd1824594138 format-string-builder-20170124-git format-string-builder.asd +formlets http://beta.quicklisp.org/archive/formlets/2016-12-04/formlets-20161204-git.tgz 10598 b630d094fbbb2fe157f7e3a4bd93b648 a034c03549a46f751d65473b2312e55782ecb4d5 formlets-20161204-git formlets-test.asd formlets.asd +fred http://beta.quicklisp.org/archive/fred/2015-09-23/fred-20150923-git.tgz 34873 dbd3a53435f31cd78f4ddc3e74e9b33b 4abfe6150cb271db84a4094e4d7cef1c50a13472 fred-20150923-git fred.asd +freebsd-sysctl http://beta.quicklisp.org/archive/freebsd-sysctl/2018-07-11/freebsd-sysctl-20180711-git.tgz 3640 e8b12534d89d5c8bcd9a5f6e73907372 028b66742f9f1b0bbdf40c1857fa03afd86bb53b freebsd-sysctl-20180711-git freebsd-sysctl.asd +froute http://beta.quicklisp.org/archive/froute/2018-07-11/froute-20180711-git.tgz 6514 fc27a158d568985e863460c9ac816ecf a22f3a153e2c9314db0e08e625e75909687b0347 froute-20180711-git froute.asd +frpc http://beta.quicklisp.org/archive/frpc/2015-10-31/frpc-20151031-git.tgz 140181 c13346249483dd290b8cf22221df05f7 dafa923a87ffc6bc0b0cdbc4f9d81ee2fd140e48 frpc-20151031-git frpc.asd frpcgen.asd +fs-watcher http://beta.quicklisp.org/archive/fs-watcher/2017-11-30/fs-watcher-20171130-git.tgz 2293 98f697c99206be8e728e98414d56c28f fb546e596be903ecec976563d09982a5b3894885 fs-watcher-20171130-git fs-watcher.asd +fset http://beta.quicklisp.org/archive/fset/2017-10-19/fset-20171019-git.tgz 107932 dc8de5917c513302dd0e135e6c133978 d53c56499c817bce4d486b1fc9611fe32b2c2eb1 fset-20171019-git fset.asd +fsvd http://beta.quicklisp.org/archive/fsvd/2013-12-11/fsvd-20131211-git.tgz 8009 b6459ca9296f6e331cef49ab5580c766 392c65723a931eb2e8a4bd752d7abf95fc818b5a fsvd-20131211-git fsvd.asd +fucc http://beta.quicklisp.org/archive/fucc/2011-01-10/fucc_0.2.1.tgz 33293 b822259462e1cba9329845709c5f607e 245cc4e542d10eff1bffb70ecc552f2f0247a53a fucc_0.2.1 fucc-generator.asd fucc-parser.asd +function-cache http://beta.quicklisp.org/archive/function-cache/2018-12-10/function-cache-20181210-git.tgz 12754 c9ed7dd8f103273bd9daa06b5a720944 98e3470ccaccbd88c7dbfe5e77f19cc742446fc1 function-cache-20181210-git function-cache-clsql.asd function-cache.asd +fxml http://beta.quicklisp.org/archive/fxml/2019-12-27/fxml-20191227-git.tgz 840266 232e2106b230f05dac277a8e34a19a4c a95b680748d598c58f8b84ff1337bb6cc0d3c8d9 fxml-20191227-git fxml.asd +gamebox-dgen http://beta.quicklisp.org/archive/gamebox-dgen/2019-03-07/gamebox-dgen-20190307-git.tgz 9378 6f107b87923081e68a76a00ba1c81766 a57f60f17c8dd30731bce3eaac6879c095332a34 gamebox-dgen-20190307-git gamebox-dgen.asd +gamebox-ecs http://beta.quicklisp.org/archive/gamebox-ecs/2018-02-28/gamebox-ecs-20180228-git.tgz 7070 a4fef9181021f72168844ba1dfa57871 50080fc42ace635ad1f5b58c53023bcdcd0e5cf7 gamebox-ecs-20180228-git gamebox-ecs.asd +gamebox-frame-manager http://beta.quicklisp.org/archive/gamebox-frame-manager/2018-07-11/gamebox-frame-manager-20180711-git.tgz 3717 f8461ce7dbcfc0597df45375d43174ab 0e989400611cd95d5cb9f117631099ee8bf45b17 gamebox-frame-manager-20180711-git gamebox-frame-manager.asd +garbage-pools http://beta.quicklisp.org/archive/garbage-pools/2013-07-20/garbage-pools-20130720-git.tgz 44210 f691e2ddf6ba22b3451c24b61d4ee8b6 cd82cc2ecf1de06bc18bd4c578736448ad3c088a garbage-pools-20130720-git garbage-pools-test.asd garbage-pools.asd +gcm http://beta.quicklisp.org/archive/gcm/2014-12-17/gcm-20141217-git.tgz 2461 6836ca1144f86e181cc4684a4be58c10 fddbfbef63cfa8f9301405fc5d5ace4a495b6fe5 gcm-20141217-git gcm.asd +gendl http://beta.quicklisp.org/archive/gendl/2019-12-27/gendl-devo-b6bd4ce1-git.tgz 69422705 b56261c7b6d9b554e198380f70b25696 90542cb830e48d5dd8050a55fbc017d7f4838fea gendl-devo-b6bd4ce1-git apps/dom/dom.asd apps/gorg/gorg.asd apps/graphs/graphs.asd apps/ta2/ta2.asd apps/tasty/tasty.asd apps/timer/timer.asd apps/translators/translators.asd apps/tree/tree.asd apps/yadd/yadd.asd base/base.asd cl-lite/cl-lite.asd demos/bus/bus.asd demos/ledger/ledger.asd demos/robot/robot.asd demos/wire-world/wire-world.asd gendl-asdf.asd gendl.asd geom-base/geom-base.asd glisp/glisp.asd gwl-graphics/gwl-graphics.asd gwl/gwl.asd regression/regression.asd setup-cffi/setup-cffi.asd surf/surf.asd +generators http://beta.quicklisp.org/archive/generators/2013-06-15/generators-20130615-git.tgz 4999 e0de3d2f81b7d5802403186012bc37b6 f9df68f27c422f6dcce84f0635a42500ca2d6e39 generators-20130615-git generators.asd +generic-cl http://beta.quicklisp.org/archive/generic-cl/2019-11-30/generic-cl-20191130-git.tgz 66629 4993917d297113bf47002d2f5afa24b4 c307f7ee08d74fdd7417c30208b43b6de50fd127 generic-cl-20191130-git generic-cl.asd +generic-comparability http://beta.quicklisp.org/archive/generic-comparability/2018-01-31/generic-comparability-20180131-git.tgz 5622 9cc021f7f580a6e4951066f629bc56f3 7ef5b496c236d42f4fdf529ae257a2e99a9e4417 generic-comparability-20180131-git generic-comparability.asd +generic-sequences http://beta.quicklisp.org/archive/generic-sequences/2015-07-09/generic-sequences-20150709-git.tgz 106323 be208c2f1e6ea5ecd39355d24676312c 330178da719e73413c84f11e42170e76cf60b657 generic-sequences-20150709-git generic-sequences-cont.asd generic-sequences-iterate.asd generic-sequences-stream.asd generic-sequences-test.asd generic-sequences.asd +geneva http://beta.quicklisp.org/archive/geneva/2016-12-04/geneva-20161204-git.tgz 28218 6539a3fb3b4d8e6c2f4c8b1193ded5b3 80144517cb11bd17dd0c6e04470faa450855292e geneva-20161204-git geneva-cl.asd geneva-html.asd geneva-latex.asd geneva-mk2.asd geneva-plain-text.asd geneva-tex.asd geneva.asd open-geneva.asd +genhash http://beta.quicklisp.org/archive/genhash/2018-12-10/genhash-20181210-git.tgz 4210 373e52616aa9563899004e5f017cff6b 36a71477e3ddb2de935ff044dbb9bbe38cc48c76 genhash-20181210-git genhash.asd +genie http://beta.quicklisp.org/archive/genie/2019-03-07/genie-20190307-git.tgz 2991 a330d90823d8b14bf935f7a78bfb47f7 de9fff083c39e125cda4e3c0bf479d9484e4621f genie-20190307-git genie.asd +geowkt http://beta.quicklisp.org/archive/geowkt/2018-10-18/geowkt-20181018-git.tgz 127442 a3827d633b77241dbe0a18d7df672f6e a75474f5cec2bda247c423004147faa68e8d9492 geowkt-20181018-git geowkt-update.asd geowkt.asd +getopt http://beta.quicklisp.org/archive/getopt/2015-09-23/getopt-20150923-git.tgz 5108 adc97a0ae99d65edff231b35862d67dd 001d521ec954ddd8222f708316c04c6e522e2b16 getopt-20150923-git getopt.asd +gettext http://beta.quicklisp.org/archive/gettext/2017-11-30/gettext-20171130-git.tgz 23766 d162cb5310db5011c82ef6343fd280ed 896479742580c8abecf8f47b77c48d56988b3089 gettext-20171130-git gettext-example/gettext-example.asd gettext-tests/gettext-tests.asd gettext.asd +git-file-history http://beta.quicklisp.org/archive/git-file-history/2016-08-25/git-file-history-20160825-git.tgz 2640 a642d433a7fd6c73b1c81ad21ab5223e 7522386a8d66527f352d2b63c66feab5814769df git-file-history-20160825-git git-file-history-test.asd git-file-history.asd +glad-blob http://beta.quicklisp.org/archive/glad-blob/2018-02-28/glad-blob-stable-e6dd7fef-git.tgz 325980 fe67fc6d40b544b404b43879467cf054 226a4be77594fec3dc1ee8205b5e8d6c67c8576e glad-blob-stable-e6dd7fef-git glad-blob.asd +glass http://beta.quicklisp.org/archive/glass/2015-07-09/glass-20150709-git.tgz 70206 45acf599d8810960366575efe9e6dae4 49a0edeb8c25222add274d8ec7aebb8416fda42d glass-20150709-git glass.asd +glaw http://beta.quicklisp.org/archive/glaw/2018-02-28/glaw-20180228-git.tgz 1427712 aa341fdc184de0a4be21654af6b95d5a 361ba78fe7b6456b03bf8ab9c49d6330c2e3b52a glaw-20180228-git glaw-examples.asd glaw-imago.asd glaw-sdl.asd glaw.asd +glfw-blob http://beta.quicklisp.org/archive/glfw-blob/2018-02-28/glfw-blob-stable-5af92db3-git.tgz 488790 5567c3a03fa4b5cb6557f84e49c2240d 44905ce7d667322a522783c24bbe3cd6d36f4a37 glfw-blob-stable-5af92db3-git glfw-blob.asd +glisph http://beta.quicklisp.org/archive/glisph/2017-04-03/glisph-20170403-git.tgz 2341692 8fbfbd69a4b60b1cf7456b1a05332d37 9316f601eb05d9db8eebc61a3f0746227ccf1062 glisph-20170403-git glisph-test.asd glisph.asd +glkit http://beta.quicklisp.org/archive/glkit/2017-12-27/glkit-20171227-git.tgz 15068 96045c730e405bff1729f56ef79ac65b 87b6502dc08a45f997b942c088677bd32189ce20 glkit-20171227-git glkit-examples.asd glkit.asd +global-vars http://beta.quicklisp.org/archive/global-vars/2014-11-06/global-vars-20141106-git.tgz 3581 dd3153ee75c972a80450aa00644b2200 06ef315e35eaf447159303a16827e05cc28af887 global-vars-20141106-git global-vars-test.asd global-vars.asd +glop http://beta.quicklisp.org/archive/glop/2017-10-19/glop-20171019-git.tgz 85964 329610c0ffc7a862ce454d1901895bca 7d196144d503e8bba5a1ea8b4afe1a19927f8ac6 glop-20171019-git glop-test.asd glop.asd +glsl-packing http://beta.quicklisp.org/archive/glsl-packing/2018-01-31/glsl-packing-20180131-git.tgz 11241 32b129a2f045f76689c253d13aa8c8bc 3d93bc0affd8a6db19ed7397ed211e4499de0eae glsl-packing-20180131-git glsl-packing.asd +glsl-spec http://beta.quicklisp.org/archive/glsl-spec/2019-10-07/glsl-spec-release-quicklisp-f04476f7-git.tgz 133677 52760939a269acce6b2cba8dbde81ef7 4427cd544f8db5028d5acf54c85f55f398d8a8e7 glsl-spec-release-quicklisp-f04476f7-git glsl-docs.asd glsl-spec.asd glsl-symbols.asd +glsl-toolkit http://beta.quicklisp.org/archive/glsl-toolkit/2019-12-27/glsl-toolkit-20191227-git.tgz 35623 69c04729b2bf81cd399e3c71577849fa 676d61ea181160e6276afd2d571e872467dfd167 glsl-toolkit-20191227-git glsl-toolkit.asd +glu-tessellate http://beta.quicklisp.org/archive/glu-tessellate/2015-06-08/glu-tessellate-20150608-git.tgz 4736 bebb4d2d5c471ecd0c542ea01b7c48ab 38ef8ee019ff2e082ecb7b582ab86ba245fc9b74 glu-tessellate-20150608-git glu-tessellate.asd +glyphs http://beta.quicklisp.org/archive/glyphs/2018-07-11/glyphs-20180711-git.tgz 16354 1b7cd4d3cda79fa8a35148fedf991e11 a14199085a75163efefd17cfce15fb0a6f3bc9ee glyphs-20180711-git glyphs-test.asd glyphs.asd +golden-utils http://beta.quicklisp.org/archive/golden-utils/2019-08-13/golden-utils-20190813-git.tgz 8881 f66ce89ef840df51d4576964e1bdf393 9ece6b4ea846177cc830248f062b214b4309c75f golden-utils-20190813-git golden-utils.asd +gordon http://beta.quicklisp.org/archive/gordon/2014-07-13/gordon-20140713-git.tgz 91027 aeb5459e295855ce205af6f3fa15621a 4d3952782099079c6f6f3070ed6c964f997fb83a gordon-20140713-git gordon.asd +graph http://beta.quicklisp.org/archive/graph/2019-11-30/graph-20191130-git.tgz 40849 f2ccfbb47e4bcdf39f203dd4eab17524 99b642d96f96d882cf6cd4cd0cdd0a96752adeb1 graph-20191130-git graph.asd +graylex http://beta.quicklisp.org/archive/graylex/2011-05-22/graylex-20110522-git.tgz 26517 ebed20d32a2ed9bb763adac09a28ee7d be6cbbe39543e51eafbd0aa171353905db8f251a graylex-20110522-git graylex-m4-example.asd graylex.asd +green-threads http://beta.quicklisp.org/archive/green-threads/2014-12-17/green-threads-20141217-git.tgz 7895 6f2ac5dde894abb04e9dbb55c70ee658 61959b4f605a546d4fbe07a6c84f6754e54e9563 green-threads-20141217-git green-threads.asd +group-by http://beta.quicklisp.org/archive/group-by/2014-02-11/group-by-20140211-git.tgz 9071 25caa8291d230d98f66bca57a28ee7a5 9f600f78dc04fbfd4a1260427eb3079278ba2932 group-by-20140211-git group-by.asd +grovel-locally http://beta.quicklisp.org/archive/grovel-locally/2018-02-28/grovel-locally-20180228-git.tgz 5896 e99f1dece67838730a8845c7fbbf19c6 c419b568a3d45c9232a2ceae328c099b736472bc grovel-locally-20180228-git grovel-locally.asd +gsll http://beta.quicklisp.org/archive/gsll/2018-08-31/gsll-quicklisp-eeeda841-git.tgz 317981 4b21395e6c4531dc067d00ed10b580e1 de3edd6293d93620c33938c1ca6318ae13b6bdb4 gsll-quicklisp-eeeda841-git gsll.asd +gtk-tagged-streams http://beta.quicklisp.org/archive/gtk-tagged-streams/2018-02-28/gtk-tagged-streams-quicklisp-d1c2b827-git.tgz 73541 952070238f59cf17496556a98f04e8f6 7d4a0f5d5895e8eb0ab4f7d0d37547dc7eb211b3 gtk-tagged-streams-quicklisp-d1c2b827-git gtk-tagged-streams.asd +gtype http://beta.quicklisp.org/archive/gtype/2019-12-27/gtype-20191227-git.tgz 23144 f56dcd60fb6508203deb7cb033a61160 802686958b3d24e9d37c3e72aa0490a29ac594ab gtype-20191227-git gtype.asd gtype.test.asd +gzip-stream http://beta.quicklisp.org/archive/gzip-stream/2010-10-06/gzip-stream_0.2.8.tgz 12149 6f0c06fdf7ca0c3124593a2b99b69935 fbcd75fd3042c6fb7f33bcd4d7f065e2248a6a38 gzip-stream_0.2.8 gzip-stream.asd +halftone http://beta.quicklisp.org/archive/halftone/2019-07-10/halftone-20190710-git.tgz 5664 8b0e8a4411bd73acac297d124dd4d672 6b80181e4f8e8c2e564df62cf751f0c8d7d2667d halftone-20190710-git halftone.asd +harmony http://beta.quicklisp.org/archive/harmony/2019-07-10/harmony-20190710-git.tgz 70775 20addce2884c8206923ed8e02c59cc8a 8036fd327146c97dc9161160323b220df4feeba6 harmony-20190710-git drains/harmony-alsa.asd drains/harmony-coreaudio.asd drains/harmony-openal.asd drains/harmony-out123.asd drains/harmony-pulse.asd drains/harmony-wasapi.asd harmony.asd simple/harmony-simple.asd sources/harmony-flac.asd sources/harmony-mp3.asd sources/harmony-wav.asd +hash-set http://beta.quicklisp.org/archive/hash-set/2016-06-28/hash-set-20160628-git.tgz 6076 254fe9e8496265f078c4151ba3023f1b c1ddb19b474dfb9cc36ed6d5fc1858a15181d8ac hash-set-20160628-git hash-set-tests.asd hash-set.asd +hdf5-cffi http://beta.quicklisp.org/archive/hdf5-cffi/2018-02-28/hdf5-cffi-20180228-git.tgz 54363 dbe93f460641f2be9a9c1a910d4ef315 f6a7edd796abf4c379fe7e954690e6362d342600 hdf5-cffi-20180228-git hdf5-cffi.asd hdf5-cffi.examples.asd hdf5-cffi.test.asd +heap http://beta.quicklisp.org/archive/heap/2018-10-18/heap-20181018-git.tgz 2871 a2355ef9c113a3335919a45195083951 3c94679187d9a855a343647f8503812c0925f4f9 heap-20181018-git heap.asd +helambdap http://beta.quicklisp.org/archive/helambdap/2019-10-07/helambdap-20191007-git.tgz 101499 29f86c6e34ec5c7b09a7425e78c4bf17 76ea5c8f4026daa236e3f0b4af990e1450f83ffb helambdap-20191007-git helambdap.asd +hemlock http://beta.quicklisp.org/archive/hemlock/2016-12-08/hemlock-20161208-git.tgz 1283394 743d6fab15c5eed78c259f7afb5cd748 dd3196e78efee2f55be6e08adfe2d5dafc308d2f hemlock-20161208-git hemlock.base.asd hemlock.clx.asd hemlock.qt.asd hemlock.tty.asd +hermetic http://beta.quicklisp.org/archive/hermetic/2019-10-07/hermetic-20191007-git.tgz 4564 72d6a7322c98bf3040e88bb17b2f8b27 532f1f055d8e3a277a123d6c7304588457c712ec hermetic-20191007-git hermetic.asd +hh-aws http://beta.quicklisp.org/archive/hh-aws/2015-08-04/hh-aws-20150804-git.tgz 16762 3d1f15d366f2c0b161f5c8b7759f868a 91faf1b47a18eeb129f608a594a43f230a0c10b4 hh-aws-20150804-git hh-aws.asd +hh-redblack http://beta.quicklisp.org/archive/hh-redblack/2015-10-31/hh-redblack-20151031-git.tgz 13091 4c61afc0406a8eacffebc494a1230beb b4f520f58d13ba5fddb22f042944db2dc02cd960 hh-redblack-20151031-git hh-redblack.asd +hh-web http://beta.quicklisp.org/archive/hh-web/2014-11-06/hh-web-20141106-git.tgz 49100 f18080fa53654dac8d77e5ed5d9953ff d40315c8346f3d101c6c3acecb2e3ae24100484a hh-web-20141106-git hh-web.asd +hl7-client http://beta.quicklisp.org/archive/hl7-client/2015-04-07/hl7-client-20150407-git.tgz 3149 ee18a7ef718e2fb389ad27e6dd628d6d ab1915436f9377f698785eacbafbb8615441956e hl7-client-20150407-git hl7-client.asd +hl7-parser http://beta.quicklisp.org/archive/hl7-parser/2016-05-31/hl7-parser-20160531-git.tgz 5154 92fc8f793d674bb661b0363e1721b3d0 388f1e64bb4d2b76818ac0c02299fcab906b5538 hl7-parser-20160531-git hl7-parser.asd +horner http://beta.quicklisp.org/archive/horner/2019-11-30/horner-20191130-git.tgz 4644 8b4eabb5b0d56ba098ac4a21ae82ff60 aee72c11f78279ad81a01703e3110f1fc0b8aff7 horner-20191130-git horner.asd +horse-html http://beta.quicklisp.org/archive/horse-html/2019-10-07/horse-html-20191007-git.tgz 6518 c5ecbddc6a5e3c40d8329d13a2683763 e5ca014c5a7ca7db9e1f24e27d33c0ee016a53fb horse-html-20191007-git horse-html.asd +house http://beta.quicklisp.org/archive/house/2018-04-30/house-20180430-git.tgz 13014 6f39b6666d880b2be9cf8ed12222b626 17bc8a62f6cca820ed1b89ffbb2249b46b2c4a57 house-20180430-git house.asd +hspell http://beta.quicklisp.org/archive/hspell/2014-12-17/hspell-20141217-git.tgz 2205 a2bce23a0e37215f8302d1092c60c35e 19c8bb3f33d3f7df3a6fbec8a798c1c1f358ab38 hspell-20141217-git hspell.asd +ht-simple-ajax http://beta.quicklisp.org/archive/ht-simple-ajax/2013-04-21/ht-simple-ajax-20130421-git.tgz 10059 2787aebfc9c4d458206d50461f9443ab e1871d0755dbd48151d54c0c0e512f84798b3d4c ht-simple-ajax-20130421-git ht-simple-ajax.asd +html-encode http://beta.quicklisp.org/archive/html-encode/2010-10-06/html-encode-1.2.tgz 3132 67f22483fe6d270b8830f78f285a1016 ce347529dbb02f008c079427bcb1050372cc24e4 html-encode-1.2 html-encode.asd +html-entities http://beta.quicklisp.org/archive/html-entities/2017-10-19/html-entities-20171019-git.tgz 39697 7a71bcd138f1f367f26e26e9c8e3a390 95458f97469288061d505756bc1f1518b37462d7 html-entities-20171019-git html-entities.asd +html-template http://beta.quicklisp.org/archive/html-template/2017-12-27/html-template-20171227-git.tgz 32376 fb77c495914641f5e67e51a370b2d5a3 946ce5d402bb54c60f84acd6c6d7f6590ede40f1 html-template-20171227-git html-template.asd +http-body http://beta.quicklisp.org/archive/http-body/2019-08-13/http-body-20190813-git.tgz 15739 d46ac52643ae7dc148438f84a8107a79 1da29c1f6f6a06a5ab784acad8ebf702ba6c6216 http-body-20190813-git http-body-test.asd http-body.asd +http-get-cache http://beta.quicklisp.org/archive/http-get-cache/2018-02-28/http-get-cache-20180228-git.tgz 3610 807a9feefeed19159ff46c5733e13da6 2c4623119391c1403fd86f5c19e4865839e62e71 http-get-cache-20180228-git http-get-cache.asd +http-parse http://beta.quicklisp.org/archive/http-parse/2015-06-08/http-parse-20150608-git.tgz 30047 89b5449d33d1ad027606259f84b4c282 65a5aa04e2f6761fc87e6f2c7e7182462ebdaf3f http-parse-20150608-git http-parse-test.asd http-parse.asd +hu.dwim.asdf http://beta.quicklisp.org/archive/hu.dwim.asdf/2019-05-21/hu.dwim.asdf-20190521-darcs.tgz 6579 b359bf05f587196eba172803b5594318 435c3581852106065ba0d6978a23ac3e896d3a64 hu.dwim.asdf-20190521-darcs hu.dwim.asdf.asd hu.dwim.asdf.documentation.asd +hu.dwim.bluez http://beta.quicklisp.org/archive/hu.dwim.bluez/2016-09-29/hu.dwim.bluez-quicklisp-f3ebd960-git.tgz 126596 f751576de9d66818115f4db9f448644e 7ffaa82b75608d347efe799d50665b30b5dc07d0 hu.dwim.bluez-quicklisp-f3ebd960-git hu.dwim.bluez.asd +hu.dwim.common http://beta.quicklisp.org/archive/hu.dwim.common/2015-07-09/hu.dwim.common-20150709-darcs.tgz 3083 fff7f05c24e71a0270021909ca86a9ef 6ff0a62c94fee95b1440b59230f4a9c174d95093 hu.dwim.common-20150709-darcs hu.dwim.common.asd hu.dwim.common.documentation.asd +hu.dwim.common-lisp http://beta.quicklisp.org/archive/hu.dwim.common-lisp/2015-07-09/hu.dwim.common-lisp-20150709-darcs.tgz 2107 d3319cf3d963bff64ff90847af79251f b49f86c70a89ef52bb6b8da5b981d4ff51de48f9 hu.dwim.common-lisp-20150709-darcs hu.dwim.common-lisp.asd hu.dwim.common-lisp.documentation.asd +hu.dwim.computed-class http://beta.quicklisp.org/archive/hu.dwim.computed-class/2016-12-04/hu.dwim.computed-class-20161204-darcs.tgz 18769 f644ad7dd48737020a814319c934d23a ddb5126e5d2ff305ad5701106875710c8ac9c833 hu.dwim.computed-class-20161204-darcs hu.dwim.computed-class+hu.dwim.logger.asd hu.dwim.computed-class+swank.asd hu.dwim.computed-class.asd hu.dwim.computed-class.documentation.asd hu.dwim.computed-class.test.asd +hu.dwim.debug http://beta.quicklisp.org/archive/hu.dwim.debug/2019-01-07/hu.dwim.debug-20190107-darcs.tgz 6637 18d7d06110fdbd454e350d92cf5f17cc 3ba6fdf418010b6d7dc03d3dc95ec7c4171d6933 hu.dwim.debug-20190107-darcs hu.dwim.debug.asd hu.dwim.debug.documentation.asd hu.dwim.debug.test.asd +hu.dwim.def http://beta.quicklisp.org/archive/hu.dwim.def/2017-10-19/hu.dwim.def-20171019-darcs.tgz 19966 b0b6adc89b6aeb22fc6bb0caa9253712 c7f0abc95067fafa8764cea694dfe69a852dee61 hu.dwim.def-20171019-darcs hu.dwim.def+cl-l10n.asd hu.dwim.def+contextl.asd hu.dwim.def+hu.dwim.common.asd hu.dwim.def+hu.dwim.delico.asd hu.dwim.def+swank.asd hu.dwim.def.asd hu.dwim.def.documentation.asd hu.dwim.def.namespace.asd hu.dwim.def.test.asd +hu.dwim.defclass-star http://beta.quicklisp.org/archive/hu.dwim.defclass-star/2015-07-09/hu.dwim.defclass-star-20150709-darcs.tgz 7655 e37f386dca8f789fb2e303a1914f0415 ef556505bb91ff2d2f87bd327815e0f8bc4bde49 hu.dwim.defclass-star-20150709-darcs hu.dwim.defclass-star+contextl.asd hu.dwim.defclass-star+hu.dwim.def+contextl.asd hu.dwim.defclass-star+hu.dwim.def.asd hu.dwim.defclass-star+swank.asd hu.dwim.defclass-star.asd hu.dwim.defclass-star.documentation.asd hu.dwim.defclass-star.test.asd +hu.dwim.delico http://beta.quicklisp.org/archive/hu.dwim.delico/2018-04-30/hu.dwim.delico-20180430-darcs.tgz 19912 8fed0622f682d1de701d343159a43c7f adb94372a21da4e5c6d01908331fabd4a8cbeead hu.dwim.delico-20180430-darcs hu.dwim.delico.asd hu.dwim.delico.documentation.asd hu.dwim.delico.test.asd +hu.dwim.graphviz http://beta.quicklisp.org/archive/hu.dwim.graphviz/2017-08-30/hu.dwim.graphviz-20170830-darcs.tgz 11239 421c6dacc287bbc76443cc0e657ccaec 187e541dfe4add0b4ce0e9d111c15a5cd30070fd hu.dwim.graphviz-20170830-darcs hu.dwim.graphviz.asd hu.dwim.graphviz.documentation.asd hu.dwim.graphviz.test.asd +hu.dwim.logger http://beta.quicklisp.org/archive/hu.dwim.logger/2015-12-18/hu.dwim.logger-20151218-darcs.tgz 11456 4e180dbb379266d0cd29f5c238e1da5a 4e014f4993835235ac53a47fb900ea44b0652cc8 hu.dwim.logger-20151218-darcs hu.dwim.logger+iolib.asd hu.dwim.logger+swank.asd hu.dwim.logger.asd hu.dwim.logger.documentation.asd hu.dwim.logger.test.asd +hu.dwim.partial-eval http://beta.quicklisp.org/archive/hu.dwim.partial-eval/2017-11-30/hu.dwim.partial-eval-20171130-darcs.tgz 24393 78c498a3ba353e0a62e15df49a459078 9acbc3ab6c50c1104c94047ef747456a7cffd854 hu.dwim.partial-eval-20171130-darcs hu.dwim.partial-eval.asd hu.dwim.partial-eval.documentation.asd hu.dwim.partial-eval.test.asd +hu.dwim.perec http://beta.quicklisp.org/archive/hu.dwim.perec/2018-01-31/hu.dwim.perec-20180131-darcs.tgz 183286 d83b7b553244d10d7ce1dfc163a5d7ff 4eecec9468212801e4574db2c0cdcf4eb662575f hu.dwim.perec-20180131-darcs hu.dwim.perec+hu.dwim.quasi-quote.xml.asd hu.dwim.perec+iolib.asd hu.dwim.perec+swank.asd hu.dwim.perec.all.asd hu.dwim.perec.all.test.asd hu.dwim.perec.asd hu.dwim.perec.documentation.asd hu.dwim.perec.oracle.asd hu.dwim.perec.oracle.test.asd hu.dwim.perec.postgresql.asd hu.dwim.perec.postgresql.test.asd hu.dwim.perec.sqlite.asd hu.dwim.perec.sqlite.test.asd hu.dwim.perec.test.asd +hu.dwim.presentation http://beta.quicklisp.org/archive/hu.dwim.presentation/2017-10-19/hu.dwim.presentation-20171019-darcs.tgz 1729653 428ab20690f3513d974448d0097e6de1 66e02a2cf33ed07c918bc81c48237a3a268baca9 hu.dwim.presentation-20171019-darcs hu.dwim.presentation+cl-graph+cl-typesetting.asd hu.dwim.presentation+cl-typesetting.asd hu.dwim.presentation+hu.dwim.stefil.asd hu.dwim.presentation+hu.dwim.web-server.asd hu.dwim.presentation.asd +hu.dwim.quasi-quote http://beta.quicklisp.org/archive/hu.dwim.quasi-quote/2017-11-30/hu.dwim.quasi-quote-20171130-darcs.tgz 72072 314b7f577e7aec4e0ad0fafea22664b3 a6cfe34f6d330f543155a40b1324a70c94272fa5 hu.dwim.quasi-quote-20171130-darcs hu.dwim.quasi-quote.asd hu.dwim.quasi-quote.css.asd hu.dwim.quasi-quote.documentation.asd hu.dwim.quasi-quote.js.asd hu.dwim.quasi-quote.pdf.asd hu.dwim.quasi-quote.test.asd hu.dwim.quasi-quote.xml+cxml.asd hu.dwim.quasi-quote.xml+hu.dwim.quasi-quote.js.asd hu.dwim.quasi-quote.xml.asd +hu.dwim.rdbms http://beta.quicklisp.org/archive/hu.dwim.rdbms/2018-02-28/hu.dwim.rdbms-20180228-darcs.tgz 116724 719880aa6837228d1f87176ab3cd003b cea924b46169e492767618038ea8351d8459eecf hu.dwim.rdbms-20180228-darcs hu.dwim.rdbms.all.asd hu.dwim.rdbms.all.test.asd hu.dwim.rdbms.asd hu.dwim.rdbms.documentation.asd hu.dwim.rdbms.oracle.asd hu.dwim.rdbms.oracle.test.asd hu.dwim.rdbms.postgresql.asd hu.dwim.rdbms.postgresql.test.asd hu.dwim.rdbms.sqlite.asd hu.dwim.rdbms.sqlite.test.asd hu.dwim.rdbms.test.asd +hu.dwim.reiterate http://beta.quicklisp.org/archive/hu.dwim.reiterate/2017-10-19/hu.dwim.reiterate-20171019-darcs.tgz 21412 d6f0210e9e4aaef63dcbf24aeb564dd1 bad2b13f2aedeee69b767e6fc723fea2d40246b3 hu.dwim.reiterate-20171019-darcs hu.dwim.reiterate+hu.dwim.logger.asd hu.dwim.reiterate.asd +hu.dwim.sdl http://beta.quicklisp.org/archive/hu.dwim.sdl/2018-02-28/hu.dwim.sdl-quicklisp-aad47404-git.tgz 1787723 9474a5fda11b03a06706ea11a56b2822 8f030144d97d14ac58dc2b12f4b5cf60bbc360af hu.dwim.sdl-quicklisp-aad47404-git hu.dwim.sdl.asd +hu.dwim.serializer http://beta.quicklisp.org/archive/hu.dwim.serializer/2016-12-04/hu.dwim.serializer-20161204-darcs.tgz 12092 bb15ef778eca814e4f1caa5ae05fb7ad 197e6d4df639b4bbd976e819b3247d20a937bb5e hu.dwim.serializer-20161204-darcs hu.dwim.serializer.asd hu.dwim.serializer.documentation.asd hu.dwim.serializer.test.asd +hu.dwim.stefil http://beta.quicklisp.org/archive/hu.dwim.stefil/2017-04-03/hu.dwim.stefil-20170403-darcs.tgz 24074 ea8be76a360b1df297a8bbd50be0d8a1 d5a5ca36649838b14a270cea28743883672598e3 hu.dwim.stefil-20170403-darcs hu.dwim.stefil+hu.dwim.def+swank.asd hu.dwim.stefil+hu.dwim.def.asd hu.dwim.stefil+swank.asd hu.dwim.stefil.asd +hu.dwim.syntax-sugar http://beta.quicklisp.org/archive/hu.dwim.syntax-sugar/2016-12-04/hu.dwim.syntax-sugar-20161204-darcs.tgz 19274 c155225d3a2b9a329adfcb705b915a91 2f4c5e896d05181efcf0debf1741ac3e0e2fca06 hu.dwim.syntax-sugar-20161204-darcs hu.dwim.syntax-sugar.asd hu.dwim.syntax-sugar.documentation.asd hu.dwim.syntax-sugar.test.asd +hu.dwim.uri http://beta.quicklisp.org/archive/hu.dwim.uri/2018-02-28/hu.dwim.uri-20180228-darcs.tgz 8543 0e3408935a77c74a944f9a34dae3e728 f26121022ce365911e2ab03d8de2af07b8ec2a2d hu.dwim.uri-20180228-darcs hu.dwim.uri.asd hu.dwim.uri.test.asd +hu.dwim.util http://beta.quicklisp.org/archive/hu.dwim.util/2017-10-19/hu.dwim.util-20171019-darcs.tgz 51237 57a824c371c7fc393373218e4c1b543f e43f21213958998e39ab6e6d1c563a019f277ff7 hu.dwim.util-20171019-darcs hu.dwim.util+iolib.asd hu.dwim.util.asd hu.dwim.util.documentation.asd hu.dwim.util.test.asd +hu.dwim.walker http://beta.quicklisp.org/archive/hu.dwim.walker/2015-12-18/hu.dwim.walker-20151218-darcs.tgz 37982 39c1af6715dacb25329cddefac1be792 72b3e954bd87f3834b7b2f7f79509677b6e57b54 hu.dwim.walker-20151218-darcs hu.dwim.walker.asd hu.dwim.walker.documentation.asd hu.dwim.walker.test.asd +hu.dwim.web-server http://beta.quicklisp.org/archive/hu.dwim.web-server/2018-12-10/hu.dwim.web-server-20181210-darcs.tgz 511462 1bc99a6a26cb46ba7a8fa968034376ef c9b3001c740074b12f5d45a787dec1fb373bba28 hu.dwim.web-server-20181210-darcs hu.dwim.web-server+swank.asd hu.dwim.web-server.application+hu.dwim.perec.asd hu.dwim.web-server.application.asd hu.dwim.web-server.application.test.asd hu.dwim.web-server.asd hu.dwim.web-server.documentation.asd hu.dwim.web-server.test.asd hu.dwim.web-server.websocket.asd +hu.dwim.zlib http://beta.quicklisp.org/archive/hu.dwim.zlib/2017-08-30/hu.dwim.zlib-quicklisp-18b8e530-git.tgz 164424 b211be3638ce70b50c87af43e982f46f 39e7e7e389db0189e84d852fb59079b9380110ea hu.dwim.zlib-quicklisp-18b8e530-git hu.dwim.zlib.asd +huffman http://beta.quicklisp.org/archive/huffman/2018-10-18/huffman-20181018-git.tgz 2956 195c5722536473cadd283336008bab57 a458727ba8a5e188ecc18e64544836e83fab9b24 huffman-20181018-git huffman.asd +humbler http://beta.quicklisp.org/archive/humbler/2019-07-10/humbler-20190710-git.tgz 48317 a24a0968292724abb594d0a114e61e73 94ec67e5fe60b158d713497084db49be582d1b3d humbler-20190710-git humbler.asd +hunchensocket http://beta.quicklisp.org/archive/hunchensocket/2018-07-11/hunchensocket-20180711-git.tgz 12634 bf6cd52c13e3b1f464c8a45a8bac85b8 6a24827054f897a200220f416ba63db56ce24887 hunchensocket-20180711-git hunchensocket.asd +hunchentools http://beta.quicklisp.org/archive/hunchentools/2016-12-04/hunchentools-20161204-git.tgz 5310 3e4c00484a54fce107969941aa695e35 81c5f8bed80dd333cbc1be69da3bb2c752d7ebf9 hunchentools-20161204-git hunchentools.asd +hunchentoot http://beta.quicklisp.org/archive/hunchentoot/2017-12-27/hunchentoot-v1.2.38.tgz 218697 878a7833eb34a53231011b78e998e2fa 4fb0bf93d3cf3720e0bf0b222d01df8df1012857 hunchentoot-v1.2.38 hunchentoot.asd +hunchentoot-auth http://beta.quicklisp.org/archive/hunchentoot-auth/2014-01-13/hunchentoot-auth-20140113-git.tgz 5878 f6763dbbfd1f5421e46ff3e9648eeef6 fffbfd821814f8460262143be04c16db0d5f29f7 hunchentoot-auth-20140113-git hunchentoot-auth.asd +hunchentoot-cgi http://beta.quicklisp.org/archive/hunchentoot-cgi/2014-02-11/hunchentoot-cgi-20140211-git.tgz 4322 e300c5959f7100b7e032066239d82541 bf8b301b9f4a99a4ef2237581df81f2d848349a4 hunchentoot-cgi-20140211-git hunchentoot-cgi.asd +hunchentoot-multi-acceptor http://beta.quicklisp.org/archive/hunchentoot-multi-acceptor/2019-11-30/hunchentoot-multi-acceptor-20191130-git.tgz 6408 734aa1624d6d04f26664f4fcff10df9e 1889515bcd205853c813f4d0527330b2077e0d84 hunchentoot-multi-acceptor-20191130-git hunchentoot-multi-acceptor.asd +hunchentoot-single-signon http://beta.quicklisp.org/archive/hunchentoot-single-signon/2013-11-11/hunchentoot-single-signon-20131111-git.tgz 2279 52b6a4438e7c63209f674eadba35168c a67c2e3a07f00cf2738ac14400ebdc44868195dc hunchentoot-single-signon-20131111-git hunchentoot-single-signon.asd +hyperluminal-mem http://beta.quicklisp.org/archive/hyperluminal-mem/2016-12-04/hyperluminal-mem-20161204-git.tgz 88995 da358539317553cbdaef4c219d20b67a 762447423e1be7578ac777b8bc18abd82e258c16 hyperluminal-mem-20161204-git hyperluminal-mem.asd +hyperobject http://beta.quicklisp.org/archive/hyperobject/2013-04-20/hyperobject-20130420-git.tgz 41879 460a3c040b1ef40bdc9290eaa1a86249 da930ff34d7d234a1ae6e7c7596f0f5810106a3f hyperobject-20130420-git hyperobject-tests.asd hyperobject.asd +hyperspec http://beta.quicklisp.org/archive/hyperspec/2018-12-10/hyperspec-20181210-git.tgz 23892 742d80f89020e90234f1b8b6f00a3056 4bafc32c2cfd86b013525385e98ec7fa6a6a32c7 hyperspec-20181210-git hyperspec.asd +ia-hash-table http://beta.quicklisp.org/archive/ia-hash-table/2016-03-18/ia-hash-table-20160318-git.tgz 4491 59a825b5b809aabb5ac5db96728756b7 e23c512d4ab5c06fe31cda3fddad17e88981d2c5 ia-hash-table-20160318-git ia-hash-table.asd ia-hash-table.test.asd +iclendar http://beta.quicklisp.org/archive/iclendar/2019-07-10/iclendar-20190710-git.tgz 88066 4ce57c1359648e497fb25962ec2c0594 0bbc2d371b1f87d4077dff0e978f29dc9ebeca50 iclendar-20190710-git iclendar.asd +id3v2 http://beta.quicklisp.org/archive/id3v2/2016-02-08/id3v2-20160208-git.tgz 3963 427ec2cf9a5f8a8be20a663c336c2288 523e03187ec89b0ce2fe95c9bb9dd1376b6856e4 id3v2-20160208-git id3v2-test.asd id3v2.asd +idna http://beta.quicklisp.org/archive/idna/2012-01-07/idna-20120107-git.tgz 6242 85b91a66efe4381bf116cdb5d2b756b6 a32def3834b2130ace95c31af82c6c8b92365c53 idna-20120107-git idna.asd +ieee-floats http://beta.quicklisp.org/archive/ieee-floats/2017-08-30/ieee-floats-20170830-git.tgz 5325 3434b4d91224ca6a817ced9d83f14bb6 fa9e496f0fcf4ba05754fc32787f728ca6e2d674 ieee-floats-20170830-git ieee-floats.asd +illogical-pathnames http://beta.quicklisp.org/archive/illogical-pathnames/2016-08-25/illogical-pathnames-20160825-git.tgz 6071 386d2b1c0a4f280a52841f4a58ddfad2 dce6a9935768ed7323f4744e9d42752aa52af3d2 illogical-pathnames-20160825-git illogical-pathnames.asd +illusion http://beta.quicklisp.org/archive/illusion/2018-08-31/illusion-20180831-git.tgz 5591 e29adc45f1e630a68b7a2594ce8e1d38 b3edb224814b92f42bdc85f76cfda22fb4a61caf illusion-20180831-git illusion-test.asd illusion.asd +image http://beta.quicklisp.org/archive/image/2012-01-07/image-20120107-git.tgz 12334 f6e1bdabba64a9be1f31602ef87b993c f54562f11b8c6b005a480974bf6742c3dff33864 image-20120107-git image.asd +imago http://beta.quicklisp.org/archive/imago/2015-06-08/imago-20150608-git.tgz 17228 2aadfc8061203e178ef01d1169d70371 7914c440be279c14f7af25456ace26b7cd0a7cf6 imago-20150608-git imago.asd +immutable-struct http://beta.quicklisp.org/archive/immutable-struct/2015-07-09/immutable-struct-20150709-git.tgz 2413 dd68ea45a64bd739e733aa2bcf59955c cca9b233fdb9c441fd02a0015a91b982b34978be immutable-struct-20150709-git immutable-struct.asd +incf-cl http://beta.quicklisp.org/archive/incf-cl/2019-07-10/incf-cl-20190710-git.tgz 14029 d517885c08a3c9ab7ab0f56071660ed4 4c29c854fba0610eb9f8adc42b99a1e15bff8bfe incf-cl-20190710-git incf-cl.asd +incognito-keywords http://beta.quicklisp.org/archive/incognito-keywords/2013-01-28/incognito-keywords-1.1.tgz 3817 4759f96fbe4f7873f52d126cec3d5b51 d01f0962811264cea7a3ae1abcc510fd0b177d07 incognito-keywords-1.1 incognito-keywords.asd +incongruent-methods http://beta.quicklisp.org/archive/incongruent-methods/2013-03-12/incongruent-methods-20130312-git.tgz 7171 9e41e9a0a9f33e4f9a00b7d525d8d9c2 73424d66cec5c544ac1fd30729d4357ee2ede37a incongruent-methods-20130312-git incongruent-methods.asd +inferior-shell http://beta.quicklisp.org/archive/inferior-shell/2016-09-29/inferior-shell-20160929-git.tgz 11709 0a48be6575e42fa47a574cd60596d73f 8e1c0011055880ad74bbf128679977b06cb119cb inferior-shell-20160929-git inferior-shell.asd +infix-dollar-reader http://beta.quicklisp.org/archive/infix-dollar-reader/2012-10-13/infix-dollar-reader-20121013-git.tgz 2671 b94e744bb2cb69b22b8ca1b94711372c 76156fbe2d0f809d57a8fb74355b4cd9a25c1272 infix-dollar-reader-20121013-git infix-dollar-reader-test.asd infix-dollar-reader.asd +infix-math http://beta.quicklisp.org/archive/infix-math/2017-08-30/infix-math-20170830-git.tgz 7244 3a4e1c58636f6126b6ad2a00a1bf0918 ea2bdbb2e223090a3bfa40f4bb120ab4dab730f9 infix-math-20170830-git infix-math.asd +injection http://beta.quicklisp.org/archive/injection/2016-05-31/injection-20160531-git.tgz 16529 fd550866b59e2f852a7457318435cc54 3688d8be08eecc9140e2f6141e94490409227a54 injection-20160531-git injection-test.asd injection.asd +inkwell http://beta.quicklisp.org/archive/inkwell/2019-07-10/inkwell-20190710-git.tgz 19455 80965d4bd6e377146f684c9f55dcdb50 a0e229d7125c2995ae6c28b1e2ce600d59c506da inkwell-20190710-git inkwell.asd +inlined-generic-function http://beta.quicklisp.org/archive/inlined-generic-function/2019-05-21/inlined-generic-function-20190521-git.tgz 13775 e9336f83fe941d4188063d5b8a1daee2 ddb708a3730c99fe766c6f7412119a1c828bd1a3 inlined-generic-function-20190521-git inlined-generic-function.asd inlined-generic-function.test.asd +inner-conditional http://beta.quicklisp.org/archive/inner-conditional/2015-06-08/inner-conditional-20150608-git.tgz 14366 ddb07ddd8d96bff1ccad30a690e48b88 3a3bd7bbff2901db70f79023dff565be75ac1a85 inner-conditional-20150608-git inner-conditional-test.asd inner-conditional.asd +inotify http://beta.quicklisp.org/archive/inotify/2015-06-08/inotify-20150608-git.tgz 3569 185ac26e780c2d0426b261fbbccca12a fce1a600d8dfddb1193e9ee71b0df2d58a2fe288 inotify-20150608-git inotify.asd +inquisitor http://beta.quicklisp.org/archive/inquisitor/2019-05-21/inquisitor-20190521-git.tgz 938309 b3ccd374ca6d78db990605fa34ca9e6f d9c38ed218610dd382652062ca3ddb5787d82906 inquisitor-20190521-git inquisitor-flexi-test.asd inquisitor-flexi.asd inquisitor-test.asd inquisitor.asd +integral http://beta.quicklisp.org/archive/integral/2018-10-18/integral-20181018-git.tgz 24642 d8c8057d590cbc0104f1e8eaf6dbb168 9858da149eac66b6bf18bd2100068da5313c7989 integral-20181018-git integral-test.asd integral.asd +integral-rest http://beta.quicklisp.org/archive/integral-rest/2015-09-23/integral-rest-20150923-git.tgz 5803 335875a5465c16346cd29689873dc643 97379a1ff7b2b586b9f3bc8070f70be0009d7487 integral-rest-20150923-git integral-rest-test.asd integral-rest.asd +intel-hex http://beta.quicklisp.org/archive/intel-hex/2016-03-18/intel-hex-20160318-git.tgz 5977 0558406788710ac04f4493a66deb2ebe 43cece1a8cf9a6d2b3b574e95a94a9f6825f5ce0 intel-hex-20160318-git intel-hex-test.asd intel-hex.asd +intercom http://beta.quicklisp.org/archive/intercom/2013-06-15/intercom-20130615-git.tgz 32404 9188e4147f75529e5d5e24561d5c6c4e 953a7a49ab8700823c352a0a488486bc2a80f392 intercom-20130615-git lisp/intercom-examples.asd lisp/intercom.asd +interface http://beta.quicklisp.org/archive/interface/2019-03-07/interface-20190307-hg.tgz 8186 2171f1127f13b79c82c56302b629c18b cbe7051bcbdb6fda388369eb1b31717a38217751 interface-20190307-hg interface.asd +introspect-environment http://beta.quicklisp.org/archive/introspect-environment/2015-10-31/introspect-environment-20151031-git.tgz 9127 3c61088583f11791530edb2e18f5d6f0 599d21a1de88776bb340d0830e7f3774f061c269 introspect-environment-20151031-git introspect-environment-test.asd introspect-environment.asd +iolib http://beta.quicklisp.org/archive/iolib/2018-02-28/iolib-v0.8.3.tgz 255866 fc28d4cad6f8e43972df3baa6a8ac45c e84165ed45f8746baa282c0e6152460421cb9ed1 iolib-v0.8.3 iolib.asd iolib.asdf.asd iolib.base.asd iolib.common-lisp.asd iolib.conf.asd iolib.examples.asd iolib.grovel.asd iolib.tests.asd +ip-interfaces http://beta.quicklisp.org/archive/ip-interfaces/2018-12-10/ip-interfaces-0.2.1.tgz 14797 c85e479e1eb4139f8996b335e7d0e034 573b6f8413bdfe11863e649f8aa3ec990662c1b8 ip-interfaces-0.2.1 ip-interfaces-test.asd ip-interfaces.asd +irc-logger http://beta.quicklisp.org/archive/irc-logger/2015-09-23/irc-logger-20150923-git.tgz 10393 6d6b60c0d2ac53575ee5c644beb162c3 1b39d7fad92c3ef94747f9be086c567c1dd317bb irc-logger-20150923-git irc-logger.asd +ironclad http://beta.quicklisp.org/archive/ironclad/2019-10-07/ironclad-v0.47.tgz 1452945 b82d370b037422fcaf8953857f03b5f6 07ff0ad14258a81e0ee4ab21abd1a3726a58328d ironclad-v0.47 ironclad-text.asd ironclad.asd +iso-8601-date http://beta.quicklisp.org/archive/iso-8601-date/2019-01-07/iso-8601-date-20190107-git.tgz 4440 b1ab5921a442d86bb2727b4a2bc9e8e0 f927777c79967a5afa2a419b5ef222a8817b9af7 iso-8601-date-20190107-git eclecticse.iso-8601-date.asd +iterate http://beta.quicklisp.org/archive/iterate/2018-02-28/iterate-20180228-git.tgz 333795 ee3b198b0f9674c11e5283e56f57ed78 063f13e39a7a17f8813f1707cab2c17ff3b20dc6 iterate-20180228-git iterate.asd +iterate-clsql http://beta.quicklisp.org/archive/iterate-clsql/2013-03-12/iterate-clsql-20130312-http.tgz 2704 0950d7a9b29b8ddb9d16b45b9096bdae 8f74118d5f989b73db760bcb0a794e23fa185a0a iterate-clsql-20130312-http iterate-clsql.asd +its http://beta.quicklisp.org/archive/its/2018-12-10/its-1.0.tgz 10137 221358638db1a4eedde70b5ff4870eea 69b22964952a5a537646ac0e3877e47101f12cb2 its-1.0 its.asd tests/its_tests.asd +jenkins http://beta.quicklisp.org/archive/jenkins/2013-03-12/jenkins-20130312-git.tgz 15878 53049d3dd8dfe5ea36738005c786f8d0 f3a1fad4ff41d91901a8fe5484bbb2b5df746119 jenkins-20130312-git jenkins.api.asd +jonathan http://beta.quicklisp.org/archive/jonathan/2019-02-02/jonathan-20190202-git.tgz 160340 bf340574fc901706ba2dcdc57e1e78ad 0d332a8f852c735d817c0eb4173f25d9e88f8262 jonathan-20190202-git jonathan-test.asd jonathan.asd +jose http://beta.quicklisp.org/archive/jose/2018-07-11/jose-20180711-git.tgz 14142 92786104f9775ea657c37ae846526ab4 d90b3bc348676117c1639fbdc0553e805daa5861 jose-20180711-git jose.asd +jp-numeral http://beta.quicklisp.org/archive/jp-numeral/2019-05-21/jp-numeral-20190521-git.tgz 41673 1969e0dec2db5270d6e7517ed1d9001b d8d48074786dad5f54b8ef528f575d38c68be6af jp-numeral-20190521-git jp-numeral-test.asd jp-numeral.asd +jpl-queues http://beta.quicklisp.org/archive/jpl-queues/2010-10-06/jpl-queues-0.1.tgz 15113 7c3d14c955db0a5c8ece2b9409333ce0 39497c7cb7292433b5c5a83d7ceb7a6e09cac7b1 jpl-queues-0.1 jpl-queues.asd +js http://beta.quicklisp.org/archive/js/2018-01-31/js-20180131-git.tgz 64836 52f3ec4406ac27a84b65be99ebda51e0 85b589dc6d059502fb56c7b265121ff36712cf19 js-20180131-git cl-js.asd +js-parser http://beta.quicklisp.org/archive/js-parser/2015-04-07/js-parser-20150407-git.tgz 67870 4b86296f7eb3542447528822f7fa2612 4b2e27dfa07c730235c2014740b4d91540d0f656 js-parser-20150407-git js-parser-tests.asd js-parser.asd +json-mop http://beta.quicklisp.org/archive/json-mop/2018-02-28/json-mop-20180228-git.tgz 6214 82d6e487a8410e7f4f95e02fa2615fc7 fd825e88baa5e8e9d7dc100acb1c6a35c60e8d87 json-mop-20180228-git json-mop.asd tests/json-mop-tests.asd +json-responses http://beta.quicklisp.org/archive/json-responses/2019-03-07/json-responses-20190307-hg.tgz 4722 27b0c30fe8df35ecbaa2a7e860191dc1 393cfe5d2254c49fb28ad2ba24a95d3ee5d26c89 json-responses-20190307-hg json-responses.asd +json-streams http://beta.quicklisp.org/archive/json-streams/2017-10-19/json-streams-20171019-git.tgz 45679 b5ab07dce6bfa17782384ecd66bba4bc 8cc35c603b9fdef5e94b82da5dbb72f3551f5530 json-streams-20171019-git json-streams-tests.asd json-streams.asd +jsonrpc http://beta.quicklisp.org/archive/jsonrpc/2019-10-07/jsonrpc-20191007-git.tgz 11608 dbc1e444df10dea1681e8e1a5b4180e8 9ac2f791d611f0be146e50628eeb2e5212d18748 jsonrpc-20191007-git jsonrpc.asd +jsown http://beta.quicklisp.org/archive/jsown/2019-11-30/jsown-20191130-git.tgz 14948 2714529af34123c5d5ea5a6ec401230b 69fa55f69254913584f583ba1aa66fd5f3aad7d6 jsown-20191130-git jsown.asd tests/jsown-tests.asd +jwacs http://beta.quicklisp.org/archive/jwacs/2018-02-28/jwacs-20180228-git.tgz 202732 9f9d92d2e616fddc3ceac0e5be375f8d 4e367cb507f1095f53b90aa52dab4b5ac83451f7 jwacs-20180228-git jwacs-tests.asd jwacs.asd +kebab http://beta.quicklisp.org/archive/kebab/2015-06-08/kebab-20150608-git.tgz 3165 b7136a488e5f7f202fd74c59516cac8e 7ba2ed7c0f2ed1ebc31f7c9776563257a5c12bdb kebab-20150608-git kebab-test.asd kebab.asd +kenzo http://beta.quicklisp.org/archive/kenzo/2019-12-27/kenzo-20191227-git.tgz 5263930 03078b7d09f64f801c45d966ff8a0106 05a19917ca01828e8bd25ab4d8057124c7c7be57 kenzo-20191227-git kenzo-test.asd kenzo.asd +kl-verify http://beta.quicklisp.org/archive/kl-verify/2012-09-09/kl-verify-20120909-git.tgz 1728 fd742a26d44433617cf60ded1b4954ac 573e3cde43bc677f4a5da6e76dc7d53923319c1f kl-verify-20120909-git kl-verify.asd +km http://beta.quicklisp.org/archive/km/2011-05-22/km-2-5-33.tgz 328656 f4ba865c0342c5cf8ebcb507becc5e56 57b80fb82b4ea580882fae61c663c79ba3e864ee km-2-5-33 km.asd +kmrcl http://beta.quicklisp.org/archive/kmrcl/2015-09-23/kmrcl-20150923-git.tgz 57358 0cd15d3ed3e7d56528dd3243d1a5c9b1 4fa994e358e4b454880961a4e0156e29e32f63ba kmrcl-20150923-git kmrcl-tests.asd kmrcl.asd +l-math http://beta.quicklisp.org/archive/l-math/2019-03-07/l-math-20190307-git.tgz 46344 1d72a81ab46e4ebfda1c749ca67a0e90 a5a68998c4bfebdf452c4d4386fab465051c7eb4 l-math-20190307-git l-math.asd +l-system http://beta.quicklisp.org/archive/l-system/2018-02-28/l-system-20180228-git.tgz 13953 d42ca0e95be4d4cb4390e62119ac7934 89f30dbbdbc8a60a242abc5c63f1daf7851691c8 l-system-20180228-git l-system-examples.asd l-system.asd +laap http://beta.quicklisp.org/archive/laap/2017-08-30/laap-20170830-git.tgz 15178 5d86b49f328d314cdf22a5bda9565f1a 8e90156c16ad1a0ff95b9f29bc8828bee5123101 laap-20170830-git laap.asd +lack http://beta.quicklisp.org/archive/lack/2019-10-07/lack-20191007-git.tgz 178459 bce7a6b5aefb5bfd3fbeb782dda7748f 63c157526deff72db55ccea3a93781fe0eb54897 lack-20191007-git lack-component.asd lack-middleware-accesslog.asd lack-middleware-auth-basic.asd lack-middleware-backtrace.asd lack-middleware-csrf.asd lack-middleware-mount.asd lack-middleware-session.asd lack-middleware-static.asd lack-request.asd lack-response.asd lack-session-store-dbi.asd lack-session-store-redis.asd lack-test.asd lack-util-writer-stream.asd lack-util.asd lack.asd t-lack-component.asd t-lack-middleware-accesslog.asd t-lack-middleware-auth-basic.asd t-lack-middleware-backtrace.asd t-lack-middleware-csrf.asd t-lack-middleware-mount.asd t-lack-middleware-session.asd t-lack-middleware-static.asd t-lack-request.asd t-lack-session-store-dbi.asd t-lack-session-store-redis.asd t-lack-util.asd t-lack.asd +lake http://beta.quicklisp.org/archive/lake/2019-12-27/lake-20191227-git.tgz 21133 0d875fa4eeb0618f27c0238b29d8a6fa 0febcaf9d47b37c55d37eeeb21eab7f3f4e72247 lake-20191227-git lake-test.asd lake.asd +lambda-fiddle http://beta.quicklisp.org/archive/lambda-fiddle/2019-07-10/lambda-fiddle-20190710-git.tgz 6230 78f68f144ace9cb8f634ac14b3414e5e fd5c91ae6695e1531502458db52d0410c471fcee lambda-fiddle-20190710-git lambda-fiddle.asd +lambda-reader http://beta.quicklisp.org/archive/lambda-reader/2017-01-24/lambda-reader-20170124-git.tgz 3905 f2d0b70125707b31f1975a58b6c3523e e96b520a862982bb8bb801dca92c7ee744c8588a lambda-reader-20170124-git lambda-reader-8bit.asd lambda-reader.asd +lambdalite http://beta.quicklisp.org/archive/lambdalite/2014-12-17/lambdalite-20141217-git.tgz 6077 77d34562c5527b0b771d923704e74420 b1334d9c1402362a9c3aeb17f0c53f065bbec9bb lambdalite-20141217-git lambdalite.asd +language-codes http://beta.quicklisp.org/archive/language-codes/2019-07-10/language-codes-20190710-git.tgz 68776 9629d0b8fb89f350d00c4aeac316ccc2 be5e14344c850f6c00f7d789fdce5e2b250b3109 language-codes-20190710-git language-codes.asd +lass http://beta.quicklisp.org/archive/lass/2019-07-10/lass-20190710-git.tgz 23036 f2d65dc5aaf652444a3bff08559ec46e e87598a425f5b0687dfb5ccb99c0d590500711cb lass-20190710-git binary-lass.asd lass.asd +lass-flexbox http://beta.quicklisp.org/archive/lass-flexbox/2016-02-08/lass-flexbox-20160208-git.tgz 3151 7307dc8d1b5133e50ebb930d6a754edc a45b8c9e8663e6d99d48dc86a6799c4e50d78466 lass-flexbox-20160208-git lass-flexbox-test.asd lass-flexbox.asd +lassie http://beta.quicklisp.org/archive/lassie/2014-07-13/lassie-20140713-git.tgz 11181 3cd995df3ef888663c6a2237567cac27 f7398a93be3c19ae0e84a9b22d06638f56e6cf95 lassie-20140713-git lassie.asd +lastfm http://beta.quicklisp.org/archive/lastfm/2019-10-07/lastfm-20191007-git.tgz 7538 dc29a7688ade882f2c65396d2086f9b9 9a4b61c1bed6af4fbacbf4ab77207409dbc349b5 lastfm-20191007-git lastfm.asd +latex-table http://beta.quicklisp.org/archive/latex-table/2018-03-28/latex-table-20180328-git.tgz 44576 9f102a30b9f31cda67570fdf37c11401 b7f7e7b83296ca127278daa932dd6b9377393e76 latex-table-20180328-git latex-table.asd +lazy http://beta.quicklisp.org/archive/lazy/2018-10-18/lazy-20181018-git.tgz 1596 7dd62fc17c12846379f7d7be8963bbd6 a991ff232722e78080fcbeab1d3722a2d281b47f lazy-20181018-git lazy.asd +legion http://beta.quicklisp.org/archive/legion/2017-11-30/legion-20171130-git.tgz 6236 5ce607b3df2c82c88ba87681bdeb9acd 36929bd08eaadcc5f2619758409e265e406d27c8 legion-20171130-git legion-test.asd legion.asd +legit http://beta.quicklisp.org/archive/legit/2019-07-10/legit-20190710-git.tgz 28792 9b380fc23d4bab086df8a0e4a598457a 3d87520bbf8d1e153bec0330725572c63b1645c0 legit-20190710-git legit.asd +let-over-lambda http://beta.quicklisp.org/archive/let-over-lambda/2015-09-23/let-over-lambda-20150923-git.tgz 9277 d1089d8f6a1b65629b4a5b560ec09814 83a37659648cfb353a46a01e1e65aaf4743e6639 let-over-lambda-20150923-git let-over-lambda-test.asd let-over-lambda.asd +let-plus http://beta.quicklisp.org/archive/let-plus/2019-11-30/let-plus-20191130-git.tgz 11247 1b8d1660ed67852ea31cad44a6fc15d0 e5ff604e4809908974fafaaf2af49e2cc0f8bcca let-plus-20191130-git let-plus.asd +letrec http://beta.quicklisp.org/archive/letrec/2019-03-07/letrec-20190307-hg.tgz 1899 68eed8ac600a1c2f157a3f6921efdfec ad8fb4a17a629ca025b5d6a8fda50ec84f5c8a8e letrec-20190307-hg letrec.asd +lev http://beta.quicklisp.org/archive/lev/2015-05-05/lev-20150505-git.tgz 9520 10f340f7500beb98b5c0d4a9876131fb e01073c528dbdfdaae90486095172dffc2c5c748 lev-20150505-git lev.asd +leveldb http://beta.quicklisp.org/archive/leveldb/2016-05-31/leveldb-20160531-git.tgz 6169 fa515cf6ba4109ee89db4c23039bff7b 0dc56929759d6562246601b782dc6fd6c1dbadb1 leveldb-20160531-git leveldb.asd +levenshtein http://beta.quicklisp.org/archive/levenshtein/2010-10-06/levenshtein-1.0.tgz 761 6266196d57f78c0dc894af44ecb9d223 bd6dc7c06dcde4ed721d0513cab44ffde6568bea levenshtein-1.0 levenshtein.asd +lfarm http://beta.quicklisp.org/archive/lfarm/2015-06-08/lfarm-20150608-git.tgz 41956 4cc91df44a932b3175a1eabf73d6e42d d0020b44060e11ef149b366645d915fb1cecff06 lfarm-20150608-git lfarm-admin.asd lfarm-client.asd lfarm-common.asd lfarm-gss.asd lfarm-launcher.asd lfarm-server.asd lfarm-ssl.asd lfarm-test.asd +lhstats http://beta.quicklisp.org/archive/lhstats/2012-01-07/lhstats-20120107-git.tgz 42573 828738a13c638d9d090439e57aaaf0ef 655b38385e0cb69d344e58c1dd7331a7f314a0af lhstats-20120107-git lhstats.asd +liblmdb http://beta.quicklisp.org/archive/liblmdb/2017-08-30/liblmdb-20170830-git.tgz 4501 32fbfb193f327493ade3440f5bf9e989 2a355ed6a5a753f2a59c6584979056b5e5dc9bde liblmdb-20170830-git liblmdb.asd +lichat-ldap http://beta.quicklisp.org/archive/lichat-ldap/2019-07-10/lichat-ldap-20190710-git.tgz 3001 6ab1394eaf6d55b04d40e5d229b30a51 811b669faaec5248b59e91f74d85f3aa21aab9b5 lichat-ldap-20190710-git lichat-ldap.asd +lichat-protocol http://beta.quicklisp.org/archive/lichat-protocol/2019-11-30/lichat-protocol-20191130-git.tgz 40126 8371f0b44edd51bd6c590c4d68373c88 d7da75c915cab1c5573ada70a630660dc4c03140 lichat-protocol-20191130-git lichat-protocol.asd +lichat-serverlib http://beta.quicklisp.org/archive/lichat-serverlib/2019-07-10/lichat-serverlib-20190710-git.tgz 15969 f6e93ed83b7b66732646b1178abf8978 7f27418370e6770c537b861586d2854db476b385 lichat-serverlib-20190710-git lichat-serverlib.asd +lichat-tcp-client http://beta.quicklisp.org/archive/lichat-tcp-client/2019-07-10/lichat-tcp-client-20190710-git.tgz 7146 9c22da901c9df97f415797ad79350683 e35ef93ecf768d30bdd13d64e74b2ee184f49056 lichat-tcp-client-20190710-git lichat-tcp-client.asd +lichat-tcp-server http://beta.quicklisp.org/archive/lichat-tcp-server/2019-07-10/lichat-tcp-server-20190710-git.tgz 7684 fa46f205b911e51931ac3573472f2a09 4f3498018d1a44b63c85d2b8144479114c65dce5 lichat-tcp-server-20190710-git lichat-tcp-server.asd +lichat-ws-server http://beta.quicklisp.org/archive/lichat-ws-server/2019-07-10/lichat-ws-server-20190710-git.tgz 7059 e8fa5d952a7ef7744d83875cd08ac8de 960dca9954534c9fc62384787cf4d2a02f4303e0 lichat-ws-server-20190710-git lichat-ws-server.asd +lift http://beta.quicklisp.org/archive/lift/2019-05-21/lift-20190521-git.tgz 1132278 c03d3fa715792440c7b51a852ad581e3 5bf930dadf4900ee6a03066f6d5f2a51c041c19f lift-20190521-git lift-documentation.asd lift-test.asd lift.asd +lila http://beta.quicklisp.org/archive/lila/2019-10-07/lila-20191007-git.tgz 18320 d6b601d97d413abf9f401d5e6c5a0b48 2a13279fa64442360d5b88c2a2bbfda2addb8b3f lila-20191007-git lila.asd +lime http://beta.quicklisp.org/archive/lime/2015-12-18/lime-20151218-git.tgz 14590 1c43d6c9dbd8db49e0e25234477775d1 c60882af85f65f2e0e6cd4bea80112d862848c94 lime-20151218-git lime-example.asd lime-test.asd lime.asd +linear-programming http://beta.quicklisp.org/archive/linear-programming/2019-11-30/linear-programming-20191130-git.tgz 25969 9348b8da3d2dbcbb51cf006525d41f0a c349e18b823684d354541e10df5e7b816f9a5712 linear-programming-20191130-git linear-programming-test.asd linear-programming.asd +linedit http://beta.quicklisp.org/archive/linedit/2018-04-30/linedit-20180430-git.tgz 21140 a9f679411d01ec162eb1ba7c76e25d7a 82f1fab330a425fe3406a8a8a707575590cecf9f linedit-20180430-git linedit.asd +linewise-template http://beta.quicklisp.org/archive/linewise-template/2016-02-08/linewise-template-20160208-git.tgz 14893 396034dd6aab87bfe5db95b0064187b2 1cbddfa14e8620ad6eb87b8041bd5d3bf44abd4d linewise-template-20160208-git linewise-template.asd +lionchat http://beta.quicklisp.org/archive/lionchat/2019-07-10/lionchat-20190710-git.tgz 313345 9cbf24d2fb7f54960d1daa58cd853468 c947b14bf01e7b48cb1d99cecb404b40daaa535e lionchat-20190710-git lionchat.asd +lisa http://beta.quicklisp.org/archive/lisa/2012-04-07/lisa-20120407-git.tgz 165079 6d999f92e2d894a7c4785b044955a49f b8b3350d837c7ea807163213dece93d59db0c725 lisa-20120407-git lisa.asd +lisp-binary http://beta.quicklisp.org/archive/lisp-binary/2019-12-27/lisp-binary-20191227-git.tgz 928451 0e8dab0533d47746b56a16927e75238f ba1a40dff70a00e6cc07a045cb2315c3351047f7 lisp-binary-20191227-git lisp-binary.asd test/lisp-binary-test.asd +lisp-chat http://beta.quicklisp.org/archive/lisp-chat/2019-05-21/lisp-chat-20190521-git.tgz 99269 2e3e425dab2610b63038e6fcced3eed4 212518260f0a1bb4a33332bc867bf625dfec8dc3 lisp-chat-20190521-git lisp-chat.asd +lisp-critic http://beta.quicklisp.org/archive/lisp-critic/2019-05-21/lisp-critic-20190521-git.tgz 20286 998d8aee18cc0265ea7e8b5ca480fd40 aaaa72cc78f46fe5652e318ce1f38dd4c26547f2 lisp-critic-20190521-git ckr-tables.asd lisp-critic.asd +lisp-executable http://beta.quicklisp.org/archive/lisp-executable/2018-08-31/lisp-executable-20180831-git.tgz 23139 63ea5e1673e9b2d90df1a2bbe10fd7b5 ec9d633c4ac367fa2f756e9960a83eb3805d3f71 lisp-executable-20180831-git lisp-executable-example.asd lisp-executable-tests.asd lisp-executable.asd +lisp-gflags http://beta.quicklisp.org/archive/lisp-gflags/2015-10-31/lisp-gflags-20151031-git.tgz 8022 2e96622a1f5e11acf9871c6171bad635 ff6654e50a07142e916d6eaebf9b09b199f4dc52 lisp-gflags-20151031-git com.google.flag-test.asd com.google.flag.asd +lisp-interface-library http://beta.quicklisp.org/archive/lisp-interface-library/2018-04-30/lisp-interface-library-20180430-git.tgz 60414 1d71936f692f30bb000ffbbb69b098e7 e695c2d9e57f1770e5cb6acceb5da9505d29e90a lisp-interface-library-20180430-git lil.asd lisp-interface-library.asd +lisp-invocation http://beta.quicklisp.org/archive/lisp-invocation/2018-02-28/lisp-invocation-20180228-git.tgz 10863 3ed327ad1fc47f27cc1332d9a8b7e20e 49234e20c19ecb65fa0d743684c92965e8978160 lisp-invocation-20180228-git lisp-invocation.asd +lisp-namespace http://beta.quicklisp.org/archive/lisp-namespace/2017-11-30/lisp-namespace-20171130-git.tgz 9762 d3052a13db167c6a53487f31753b7467 e84b47c0b146849eeb5f624cc2c491e36f62be8a lisp-namespace-20171130-git lisp-namespace.asd lisp-namespace.test.asd +lisp-unit http://beta.quicklisp.org/archive/lisp-unit/2017-01-24/lisp-unit-20170124-git.tgz 18163 2c55342cb8af18b290bb6a28c75deac5 234203b4f9903cd82b1698f3a90439fb2bbc3f7e lisp-unit-20170124-git lisp-unit.asd +lisp-unit2 http://beta.quicklisp.org/archive/lisp-unit2/2018-01-31/lisp-unit2-20180131-git.tgz 34698 d061fa640837441a5d2eecbefd8b2e69 dd120bb9dd809fbd3bd0b8ef579e5328719be3d2 lisp-unit2-20180131-git lisp-unit2.asd +lisp-zmq http://beta.quicklisp.org/archive/lisp-zmq/2016-02-08/lisp-zmq-20160208-git.tgz 15281 b1aa6a105b82083f62bc8e149fe840d0 985b9003de4ea3c8d4b26a85d27d31a08cc23785 lisp-zmq-20160208-git zmq-examples.asd zmq-test.asd zmq.asd +lispbuilder http://beta.quicklisp.org/archive/lispbuilder/2019-05-21/lispbuilder-20190521-git.tgz 7509055 7fd1bd4e45d0e35c4ac33c677072cf2a b97ce2b733d247ef2d3cbd718e2b193c1832c6e4 lispbuilder-20190521-git lispbuilder-lexer/lispbuilder-lexer.asd lispbuilder-net/lispbuilder-net-cffi.asd lispbuilder-net/lispbuilder-net.asd lispbuilder-opengl/lispbuilder-opengl-1-1.asd lispbuilder-opengl/lispbuilder-opengl-examples.asd lispbuilder-regex/lispbuilder-regex.asd lispbuilder-sdl-gfx/lispbuilder-sdl-gfx-binaries.asd lispbuilder-sdl-gfx/lispbuilder-sdl-gfx-cffi.asd lispbuilder-sdl-gfx/lispbuilder-sdl-gfx-examples.asd lispbuilder-sdl-gfx/lispbuilder-sdl-gfx.asd lispbuilder-sdl-image/lispbuilder-sdl-image-binaries.asd lispbuilder-sdl-image/lispbuilder-sdl-image-cffi.asd lispbuilder-sdl-image/lispbuilder-sdl-image-examples.asd lispbuilder-sdl-image/lispbuilder-sdl-image.asd lispbuilder-sdl-mixer/lispbuilder-sdl-mixer-binaries.asd lispbuilder-sdl-mixer/lispbuilder-sdl-mixer-cffi.asd lispbuilder-sdl-mixer/lispbuilder-sdl-mixer-examples.asd lispbuilder-sdl-mixer/lispbuilder-sdl-mixer.asd lispbuilder-sdl-ttf/lispbuilder-sdl-ttf-binaries.asd lispbuilder-sdl-ttf/lispbuilder-sdl-ttf-cffi.asd lispbuilder-sdl-ttf/lispbuilder-sdl-ttf-examples.asd lispbuilder-sdl-ttf/lispbuilder-sdl-ttf.asd lispbuilder-sdl/cocoahelper.asd lispbuilder-sdl/lispbuilder-sdl-assets.asd lispbuilder-sdl/lispbuilder-sdl-base.asd lispbuilder-sdl/lispbuilder-sdl-binaries.asd lispbuilder-sdl/lispbuilder-sdl-cffi.asd lispbuilder-sdl/lispbuilder-sdl-cl-vectors-examples.asd lispbuilder-sdl/lispbuilder-sdl-cl-vectors.asd lispbuilder-sdl/lispbuilder-sdl-examples.asd lispbuilder-sdl/lispbuilder-sdl-vecto-examples.asd lispbuilder-sdl/lispbuilder-sdl-vecto.asd lispbuilder-sdl/lispbuilder-sdl.asd lispbuilder-windows/lispbuilder-windows.asd lispbuilder-yacc/lispbuilder-yacc.asd +lispqr http://beta.quicklisp.org/archive/lispqr/2019-12-27/lispqr-20191227-git.tgz 24946 1fb86ba44a041d1b4f22b2f61299c66b ff88cd4d8665c966f478f73b20f664bc1e9310d9 lispqr-20191227-git lispqr.asd +listoflist http://beta.quicklisp.org/archive/listoflist/2014-08-26/listoflist-20140826-git.tgz 12188 598138f6ddf5241eaa283d0adce7878d c4138b36e50717f3e826fbc0d77cd9c00d0c9612 listoflist-20140826-git listoflist.asd +listopia http://beta.quicklisp.org/archive/listopia/2019-07-10/listopia-20190710-git.tgz 10846 54bbe555ec64ec4c63a8ea83738dde17 ccfa999552b2d86a7786825faae0d61c79d98a65 listopia-20190710-git listopia-bench.asd listopia-test.asd listopia.asd +literate-lisp http://beta.quicklisp.org/archive/literate-lisp/2019-12-27/literate-lisp-20191227-git.tgz 145340 5134652204467310acf6379e3b095730 84c8de8f253af7ee2cd24c3e81bffb8d65ca2114 literate-lisp-20191227-git literate-demo.asd literate-lisp.asd +livesupport http://beta.quicklisp.org/archive/livesupport/2019-05-21/livesupport-release-quicklisp-71e6e412-git.tgz 2939 9eb376b26689ac54d2a51f5189587ec5 e2df3d1a994fad4f8149c2795dc5d7de5a10d5ce livesupport-release-quicklisp-71e6e412-git livesupport.asd +lla http://beta.quicklisp.org/archive/lla/2018-03-28/lla-20180328-git.tgz 38969 61d583603d5cacf9d81486a0cfcfaf6a 5c747b960f4ed782de3a11505eb02fef3b7b5d0a lla-20180328-git lla.asd +lmdb http://beta.quicklisp.org/archive/lmdb/2017-04-03/lmdb-20170403-git.tgz 7367 65a7e5f3ddfc9bd1d322ac9e6bf08f09 5178d796ab2eec1c1404e6505f97453c09e95dc7 lmdb-20170403-git lmdb-test.asd lmdb.asd +lml http://beta.quicklisp.org/archive/lml/2015-09-23/lml-20150923-git.tgz 16279 4250f2b2c4d110cc728645e8a1eba963 5e9d7018b7487783aeec69ff4ac283a56bccd1ef lml-20150923-git lml-tests.asd lml.asd +lml2 http://beta.quicklisp.org/archive/lml2/2015-09-23/lml2-20150923-git.tgz 31590 99d76c1971e4fceaa6496291c4ede90b b119542c292e0ff8ed86874cbe6ee64a6c16a9a0 lml2-20150923-git lml2-tests.asd lml2.asd +local-package-aliases http://beta.quicklisp.org/archive/local-package-aliases/2013-03-12/local-package-aliases-20130312-git.tgz 8525 a949c3a09612e3913c798bd4cc67eadf 002c40de319cb0d4cfe4071aa5375a2f5434895f local-package-aliases-20130312-git local-package-aliases.asd +local-time http://beta.quicklisp.org/archive/local-time/2019-07-10/local-time-20190710-git.tgz 282522 ff315f40d1f955210c78aa0804a117f2 77d2629935ebb6b66cebcd121f0b14ee3449b698 local-time-20190710-git cl-postgres+local-time.asd local-time.asd +local-time-duration http://beta.quicklisp.org/archive/local-time-duration/2018-04-30/local-time-duration-20180430-git.tgz 10333 8ad2f86ea33d4c7b3014e2152632b88c 0b443efd31c990ad022e9c16576bf68b2359de0b local-time-duration-20180430-git cl-postgres+local-time-duration.asd local-time-duration.asd +log4cl http://beta.quicklisp.org/archive/log4cl/2019-10-07/log4cl-20191007-git.tgz 917204 11cdcd9da0ede86092886a055b186861 06118f3a37d1038fe1188c621dca7b62886733d3 log4cl-20191007-git log4cl-examples.asd log4cl.asd log4slime.asd +log5 http://beta.quicklisp.org/archive/log5/2011-06-19/log5-20110619-git.tgz 29106 b05a585fbf58b25367c05ec8bb814e8c 07d72b5327c5e8795eac99d235cc1a483a4cbafd log5-20110619-git log5.asd +lorem-ipsum http://beta.quicklisp.org/archive/lorem-ipsum/2018-10-18/lorem-ipsum-20181018-git.tgz 3756 4a89cae2f82951c8cf76348b5f0600ee 6216e403bb0c4da378eb6b16e094926355c13549 lorem-ipsum-20181018-git lorem-ipsum.asd +lowlight http://beta.quicklisp.org/archive/lowlight/2013-12-11/lowlight-20131211-git.tgz 17517 83b71610e5b7de0979ffc9dcff43e129 d90ad3e313ce9d51984519b5512fd892ab513f77 lowlight-20131211-git doc/lowlight.doc.asd lowlight.asd old/lowlight.old.asd tests/lowlight.tests.asd +lparallel http://beta.quicklisp.org/archive/lparallel/2016-08-25/lparallel-20160825-git.tgz 78551 6393e8d0c0cc9ed1c88b6e7cca8de5df 1514c95041efd503f335e2cd96ba5ef1537415cc lparallel-20160825-git lparallel-bench.asd lparallel-test.asd lparallel.asd +lquery http://beta.quicklisp.org/archive/lquery/2019-07-10/lquery-20190710-git.tgz 38615 987e9e505ff230c7bfc425bdf58fb717 e5fa7b08ffc8725db9180f41d1346312927f3bf6 lquery-20190710-git lquery-test.asd lquery.asd +lredis http://beta.quicklisp.org/archive/lredis/2014-11-06/lredis-20141106-git.tgz 8338 c3696a2d2665fd8c31002c3e9e22f6b6 49824a4b3d2730746a19c94536f68971cbb48ea1 lredis-20141106-git lredis.asd +lsx http://beta.quicklisp.org/archive/lsx/2019-10-07/lsx-20191007-git.tgz 6813 6eabb871226e5211632451e4286fdb0c b2d38cfc9642a0136dcb297545e66e6419f3db0b lsx-20191007-git cl-syntax-lsx.asd lsx.asd +ltk http://beta.quicklisp.org/archive/ltk/2019-02-02/ltk-20190202-git.tgz 62309 2560e392031180561698b49386b10c45 7d54dc61d474e2133bfbb0a0aa95484e48b0c4eb ltk-20190202-git ltk/ltk-mw.asd ltk/ltk-remote.asd ltk/ltk.asd +lucerne http://beta.quicklisp.org/archive/lucerne/2019-08-13/lucerne-20190813-git.tgz 155497 2355e311b1adeb91e9cb4582c236bc09 e785246a23c25a148e249cb43a97ba88558f967c lucerne-20190813-git lucerne-auth.asd lucerne-hello-world.asd lucerne-test.asd lucerne-utweet.asd lucerne.asd +lw-compat http://beta.quicklisp.org/archive/lw-compat/2016-03-18/lw-compat-20160318-git.tgz 2165 024b8e63d13fb12dbcccaf18cf4f8dfa 92259792af7830d80a868c5f06b2510ead325110 lw-compat-20160318-git lw-compat.asd +lyrics http://beta.quicklisp.org/archive/lyrics/2019-11-30/lyrics-20191130-git.tgz 4427 a0cd616233120323860aa65d112ba07c 8790d576f491d665894861e61394e5f8136a450d lyrics-20191130-git lyrics.asd +m2cl http://beta.quicklisp.org/archive/m2cl/2013-01-28/m2cl-20130128-git.tgz 47489 4d26b8e7cd1108db4c46070c2211c796 f69330a9442ec7192a433b51921d2a2c650291f8 m2cl-20130128-git m2cl-examples.asd m2cl-test.asd m2cl.asd +macro-html http://beta.quicklisp.org/archive/macro-html/2015-12-18/macro-html-20151218-git.tgz 18865 4c73847f830a8ccacd87e5ea76d44bb3 3b03c5253738adea7d0f7b8a67617356a293c7cc macro-html-20151218-git macro-html.asd +macro-level http://beta.quicklisp.org/archive/macro-level/2012-10-13/macro-level-1.0.1.tgz 1907 486ad598536a7b719f04c0f756d9017f 355a1254441193c1698f2641e84f3dfc356f8591 macro-level-1.0.1 macro-level.asd +macrodynamics http://beta.quicklisp.org/archive/macrodynamics/2018-02-28/macrodynamics-20180228-git.tgz 7668 8f226b02f6442d439edc80da09bd8a72 dcffeeebbb8b5084fd1517cab04abb515fb9a4a6 macrodynamics-20180228-git macrodynamics.asd +macroexpand-dammit http://beta.quicklisp.org/archive/macroexpand-dammit/2013-11-11/macroexpand-dammit-20131111-http.tgz 3604 6290fa304f986ea05e084c6342dd0c0f e0b77f879b8fd5a85120cae0b2a90ae17c93fc9d macroexpand-dammit-20131111-http macroexpand-dammit.asd +madeira-port http://beta.quicklisp.org/archive/madeira-port/2015-07-09/madeira-port-20150709-git.tgz 4844 f3d5a6aea61ecb83c56fb123d6a1ecf8 841f3bac6df3588220adc49c5caccaf495800c03 madeira-port-20150709-git madeira-port.asd +magicl http://beta.quicklisp.org/archive/magicl/2019-11-30/magicl-v0.6.5.tgz 510348 a7ffdb8d8e0911565de5c01cf0a6dc92 9b4acfd93471e917c26eef4e7bb1104fdd08acd4 magicl-v0.6.5 magicl-examples.asd magicl-gen.asd magicl-tests.asd magicl-transcendental.asd magicl.asd +maiden http://beta.quicklisp.org/archive/maiden/2019-12-27/maiden-20191227-git.tgz 234821 a24c727285b2693e197ce86231e9c5ab 538c7fadb21f7d8996b331882fc1a1a002f1e02f maiden-20191227-git agents/accounts/maiden-accounts.asd agents/activatable/maiden-activatable.asd agents/blocker/maiden-blocker.asd agents/chatlog/maiden-chatlog.asd agents/commands/maiden-commands.asd agents/core-manager/maiden-core-manager.asd agents/counter/maiden-counter.asd agents/crimes/maiden-crimes.asd agents/dictionary/maiden-dictionary.asd agents/emoticon/maiden-emoticon.asd agents/help/maiden-help.asd agents/lastfm/maiden-lastfm.asd agents/location/maiden-location.asd agents/lookup/maiden-lookup.asd agents/markov/maiden-markov.asd agents/medals/maiden-medals.asd agents/notify/maiden-notify.asd agents/permissions/maiden-permissions.asd agents/silly/maiden-silly.asd agents/talk/maiden-talk.asd agents/throttle/maiden-throttle.asd agents/time/maiden-time.asd agents/trivia/maiden-trivia.asd agents/urlinfo/maiden-urlinfo.asd agents/vote/maiden-vote.asd agents/weather/maiden-weather.asd clients/irc/maiden-irc.asd clients/lichat/maiden-lichat.asd clients/relay/maiden-relay.asd clients/twitter/maiden-twitter.asd maiden.asd modules/api-access/maiden-api-access.asd modules/client-entities/maiden-client-entities.asd modules/networking/maiden-networking.asd modules/serialize/maiden-serialize.asd modules/storage/maiden-storage.asd +mailbox http://beta.quicklisp.org/archive/mailbox/2013-10-03/mailbox-20131003-git.tgz 1907 fd52c2dc8d80c87013a6418b04c4c737 ee9f30c005b768a945c98fc466ec276a662b2b0b mailbox-20131003-git mailbox.asd +make-hash http://beta.quicklisp.org/archive/make-hash/2013-06-15/make-hash-20130615-git.tgz 361160 4f612ef068411284c88e0381fa4a0c7f a0f2260867e32967ef02f316b8d42d9d168c140f make-hash-20130615-git make-hash-tests.asd make-hash.asd +manifest http://beta.quicklisp.org/archive/manifest/2012-02-08/manifest-20120208-git.tgz 98532 16b500a79f0cd4a8f95760cb634cd617 13441aaf0b11a1275a8f72d0ec31908f60307556 manifest-20120208-git manifest.asd +map-bind http://beta.quicklisp.org/archive/map-bind/2012-08-11/map-bind-20120811-git.tgz 2092 a24c5c012e41b87f836b6d8ef318e7cd 047b3ccf3f9d433eb2104bd9da89de7f8e81a2a4 map-bind-20120811-git map-bind.asd +map-set http://beta.quicklisp.org/archive/map-set/2019-03-07/map-set-20190307-hg.tgz 2389 866dba36cdf060c943267cb79ccc0532 9b7c74de8b801583539807e28c676c5ed630bec3 map-set-20190307-hg map-set.asd +marching-cubes http://beta.quicklisp.org/archive/marching-cubes/2015-07-09/marching-cubes-20150709-git.tgz 97306 a44282b741e9dc43d40cb1979a6c7afe b8002c6a01dc8579d3f109c6ecd36dce88e9075f marching-cubes-20150709-git marching-cubes-example.asd marching-cubes-test.asd marching-cubes.asd +markdown.cl http://beta.quicklisp.org/archive/markdown.cl/2019-05-21/markdown.cl-20190521-git.tgz 21656 7de74021c21229dc5e8c94ff2d935b39 72d7124ff85b0ffcca09242f30dcb5837724ac0f markdown.cl-20190521-git markdown.cl-test.asd markdown.cl.asd +markup http://beta.quicklisp.org/archive/markup/2019-11-30/markup-20191130-git.tgz 12091 25727e4bc516291ea9265ef53c0a2629 53e8cbd2bf32b50b464ab9e84f784f0fa7679b60 markup-20191130-git markup.asd markup.test.asd +marshal http://beta.quicklisp.org/archive/marshal/2013-07-20/marshal-20130720-git.tgz 2921 7b2f8d0cb6c95f2418eca133a2e299b6 2c3d9e2c3b04cb581eb8f1f0dc94055176328029 marshal-20130720-git fmarshal-test.asd fmarshal.asd +mathkit http://beta.quicklisp.org/archive/mathkit/2016-02-08/mathkit-20160208-git.tgz 5451 f00124bdf2eea4d18154a4497bf414f7 f5323f595ca08be75b394d1baa82380982dd2f4e mathkit-20160208-git mathkit.asd +maxpc http://beta.quicklisp.org/archive/maxpc/2017-11-30/maxpc-20171130-git.tgz 26151 db7288e066a31f7080e1c7a71531a4d3 5d5aff90fe687119100e149abd22d4c8b19b6d56 maxpc-20171130-git maxpc-test.asd maxpc.asd +mcclim http://beta.quicklisp.org/archive/mcclim/2019-12-27/mcclim-20191227-git.tgz 2331764 7ebf5e9590689c238446b908fd78af49 5c3ea30aa513d6a22548ab0b00ca33d80f992e44 mcclim-20191227-git Apps/Clouseau/clouseau.asd Apps/Debugger/clim-debugger.asd Apps/Functional-Geometry/functional-geometry.asd Apps/Listener/clim-listener.asd Apps/Scigraph/scigraph.asd Backends/CLX-fb/mcclim-clx-fb.asd Backends/CLX/mcclim-clx.asd Backends/Null/mcclim-null.asd Backends/PDF/clim-pdf.asd Backends/PostScript/clim-postscript-font.asd Backends/PostScript/clim-postscript.asd Backends/RasterImage/mcclim-raster-image.asd Backends/common/mcclim-backend-common.asd Core/clim-basic/clim-basic.asd Core/clim-core/clim-core.asd Core/clim/clim.asd Examples/clim-examples.asd Experimental/tree-with-cross-edges/mcclim-tree-with-cross-edges.asd Extensions/Franz/mcclim-franz.asd Extensions/bezier/mcclim-bezier.asd Extensions/bitmap-formats/mcclim-bitmaps.asd Extensions/conditional-commands/conditional-commands.asd Extensions/fonts/mcclim-fonts.asd Extensions/image/mcclim-image.asd Extensions/layouts/mcclim-layouts.asd Extensions/render/mcclim-render.asd Libraries/Drei/Persistent/persistent.asd Libraries/Drei/cl-automaton/automaton.asd Libraries/Drei/drei-mcclim.asd Libraries/ESA/esa-mcclim.asd Libraries/Slim/slim.asd clim-lisp.asd mcclim.asd +md5 http://beta.quicklisp.org/archive/md5/2018-02-28/md5-20180228-git.tgz 15847 7f250f8a2487e4e0aac1ed9c50b79b4d 6539b395ec2b9513464f03e66f396a4c9c8b6da2 md5-20180228-git md5.asd +media-types http://beta.quicklisp.org/archive/media-types/2018-07-11/media-types-20180711-git.tgz 20767 ed16ed33fc38f0279e943d547377f3d6 e1b2d2564e260e9c78ce4eef58006a95a612259f media-types-20180711-git media-types.asd +mel-base http://beta.quicklisp.org/archive/mel-base/2018-02-28/mel-base-20180228-git.tgz 67969 17931e0cbfec8fafb7b825a0af0c897d 447445ec593bc3191d06233e505c9a55247f8be0 mel-base-20180228-git mel-base.asd +memoize http://beta.quicklisp.org/archive/memoize/2014-08-26/memoize-20140826-http.tgz 3547 bdf9cf51fb95293e42553045b7faea2f 1c29c09b7f60686ac929688b842db4c6bcb8f021 memoize-20140826-http memoize.asd +message-oo http://beta.quicklisp.org/archive/message-oo/2013-06-15/message-oo-20130615-git.tgz 2426 44631ce806432e2a55fdfdca7de414ac 95d35b35cfb93d1a19760a6291e5f756e05be25e message-oo-20130615-git message-oo.asd +meta http://beta.quicklisp.org/archive/meta/2015-06-08/meta-20150608-git.tgz 3371 3322d6d54783269122e087b1349e3171 1dfa5cc33d7d1840bfc0d5626758e3bce3e57914 meta-20150608-git meta.asd +meta-sexp http://beta.quicklisp.org/archive/meta-sexp/2010-10-06/meta-sexp-0.1.6.tgz 155693 1d8b6e9b6431340af88269fbd6bdaab3 c427e3744000b6b3275ce3c061e3b23241ba8d3b meta-sexp-0.1.6 meta-sexp.asd +metabang-bind http://beta.quicklisp.org/archive/metabang-bind/2019-11-30/metabang-bind-20191130-git.tgz 22549 b0845abb1eadb83e33e91c8d4ad88d2f 7e1cc7f04728acd7d6e9d322d5665bd9f2533171 metabang-bind-20191130-git metabang-bind-test.asd metabang-bind.asd +metacopy http://beta.quicklisp.org/archive/metacopy/2017-04-03/metacopy-20170403-darcs.tgz 9186 caa5ac0a1f5e3741e7f789589ff537fe 559f0201e9fe8708b9211ef856ed35eefd0167f9 metacopy-20170403-darcs metacopy-with-contextl.asd metacopy.asd +metap http://beta.quicklisp.org/archive/metap/2015-05-05/metap-20150505-git.tgz 3176 1de5d80b35b75fa3c8f668adb2fb891e bc6cb669fe93462ad434fd620eeeac1b17b59aa5 metap-20150505-git metap-test.asd metap.asd +metatilities http://beta.quicklisp.org/archive/metatilities/2018-02-28/metatilities-20180228-git.tgz 194405 bb75a7979528d08ec9c27ee154b9317e 531048725a416caea22d5996edd570f7cd25947a metatilities-20180228-git metatilities-test.asd metatilities.asd +metatilities-base http://beta.quicklisp.org/archive/metatilities-base/2019-12-27/metatilities-base-20191227-git.tgz 70648 7968829ca353c4a42784a151317029f1 e2abddb20c1a29455fc761c4c7716d9fdbebf0e9 metatilities-base-20191227-git metatilities-base-test.asd metatilities-base.asd +metering http://beta.quicklisp.org/archive/metering/2016-12-08/metering-20161208-git.tgz 17248 45dea763d90e5c9ddbdc31a8ccc5b6d7 e916a69c0148ea0ac6cbbab30f1e737b12b067cd metering-20161208-git metering.asd +method-combination-utilities http://beta.quicklisp.org/archive/method-combination-utilities/2014-11-06/method-combination-utilities-20141106-git.tgz 7311 881048d7bed117b8d7b4547a5111812d cb5a6ab010f6981e27c83f2ba22d33649a4db46a method-combination-utilities-20141106-git method-combination-utilities.asd +method-hooks http://beta.quicklisp.org/archive/method-hooks/2019-12-27/method-hooks-20191227-git.tgz 14332 f12af466f0dce69c3c50c8f5bd1ce61f 66ced022506a2eefbd65286cf7dd2af235bca45b method-hooks-20191227-git method-hooks-test.asd method-hooks.asd +method-versions http://beta.quicklisp.org/archive/method-versions/2011-05-22/method-versions_0.1.2011.05.18.tgz 4709 3e64215eeae18b8c830653e4ca22fe26 96476b31ff0c747c58477b2dc6227e1bfff611c8 method-versions_0.1.2011.05.18 method-versions.asd +mexpr http://beta.quicklisp.org/archive/mexpr/2015-07-09/mexpr-20150709-git.tgz 5385 7660c46156c0f98adc208451f64ff62f 9f9be5508184cc8dd23ed2e04812e1b71fdd1b5e mexpr-20150709-git mexpr-tests.asd mexpr.asd +mgl-pax http://beta.quicklisp.org/archive/mgl-pax/2018-01-31/mgl-pax-20180131-git.tgz 175872 05d6a95c330a661d0fe4ea8861dc86ea 07608475421ae501bf2a4857d31ac4b70a079233 mgl-pax-20180131-git mgl-pax-test.asd mgl-pax.asd +micmac http://beta.quicklisp.org/archive/micmac/2015-06-08/micmac-20150608-git.tgz 24509 fbe086e1ee3b4f4cb65a34872b6942b0 1dd7fb7a9c35a0f00f3a988ab35022a2db568c09 micmac-20150608-git micmac-test.asd micmac.asd +midi http://beta.quicklisp.org/archive/midi/2010-10-06/midi-20070618.tgz 6886 78d494c8d2fbc9a6af1b2d3e1b3c25d7 73a273cd33bccfa2bcd8ff93b38de5b1523e9993 midi-20070618 midi.asd +minheap http://beta.quicklisp.org/archive/minheap/2016-06-28/minheap-20160628-git.tgz 17015 27a57cdd27e91eb767f1377fcbfe2af3 0fe362afcf54c58c43ac9c36d8384d0be4782e02 minheap-20160628-git minheap-tests.asd minheap.asd +mini-cas http://beta.quicklisp.org/archive/mini-cas/2015-09-23/mini-cas-20150923-git.tgz 7018 5b29524320ea446c59ee913d6787faf0 7361170e6ebafe271aaf8b32962214bb2e860b5f mini-cas-20150923-git mini-cas.asd +misc-extensions http://beta.quicklisp.org/archive/misc-extensions/2015-06-08/misc-extensions-20150608-git.tgz 25456 ef8a05dd4382bb9d1e3960aeb77e332e 3f22977672a040f72b46d49fa680757deeff6a12 misc-extensions-20150608-git misc-extensions.asd +mito http://beta.quicklisp.org/archive/mito/2019-10-07/mito-20191007-git.tgz 38773 970032b767f3181967c179c7bc9bd0d3 07a8b4a3f24744dddeab1f7a6da068879c21998a mito-20191007-git lack-middleware-mito.asd mito-core.asd mito-migration.asd mito-test.asd mito.asd +mito-attachment http://beta.quicklisp.org/archive/mito-attachment/2019-05-21/mito-attachment-20190521-git.tgz 5159 00ff19e5e15a7bf9b2f159102d7b9f59 9e9d3a40b0ccc1b701ca9c76b1225a3bf909923e mito-attachment-20190521-git mito-attachment.asd +mito-auth http://beta.quicklisp.org/archive/mito-auth/2017-10-19/mito-auth-20171019-git.tgz 2014 f2ef144e4012a1ecac9420a64ac6ab16 f5c7ed9c9a43f739d1afddfb3616322b58b33746 mito-auth-20171019-git mito-auth.asd +mixalot http://beta.quicklisp.org/archive/mixalot/2015-12-18/mixalot-20151218-git.tgz 49886 c2132e94690a03a39343fff3a12cff1f 22856864b7a35fb44f52547cc6387e31f4db42e1 mixalot-20151218-git flac.asd mixalot-flac.asd mixalot-mp3.asd mixalot-vorbis.asd mixalot.asd mpg123-ffi.asd vorbisfile-ffi.asd +mk-string-metrics http://beta.quicklisp.org/archive/mk-string-metrics/2018-01-31/mk-string-metrics-20180131-git.tgz 5395 40f23794a7d841cb178f5951d3992886 e869de7baf6a85580ae92dd30e2ddffd9ce35400 mk-string-metrics-20180131-git mk-string-metrics-tests.asd mk-string-metrics.asd +mmap http://beta.quicklisp.org/archive/mmap/2019-11-30/mmap-20191130-git.tgz 13222 c465c1ec1dbbb17a227bc3c17d40bed4 983e80b42600cf539f8298716bfa9a0259ec309b mmap-20191130-git mmap-test.asd mmap.asd +mockingbird http://beta.quicklisp.org/archive/mockingbird/2017-11-30/mockingbird-20171130-git.tgz 8277 b5a2f5d401ba6ca7e2fab668bfa22cad 90ce36a82f42bf47eb9c87fd8f4694e4753673f5 mockingbird-20171130-git mockingbird-test.asd mockingbird.asd +modest-config http://beta.quicklisp.org/archive/modest-config/2018-02-28/modest-config-20180228-git.tgz 4144 25b0ea7d813ee8b806fd8ac434252ffd b899245e88298eb9bc042cd07237a6f1e6925af0 modest-config-20180228-git modest-config-test.asd modest-config.asd +modf http://beta.quicklisp.org/archive/modf/2019-05-21/modf-20190521-git.tgz 14168 42d31418ef8529e5e6be5c73c06eecb2 0e97b61de29d7ddd6d57d42627a385222e6fdc11 modf-20190521-git modf-test.asd modf.asd +modf-fset http://beta.quicklisp.org/archive/modf-fset/2015-06-08/modf-fset-20150608-git.tgz 2115 aec2b57d064522f5065597cd6619f851 0fb42b40b822fc95b98dacf7dcc86a0781f581cd modf-fset-20150608-git modf-fset-test.asd modf-fset.asd +modularize http://beta.quicklisp.org/archive/modularize/2019-07-10/modularize-20190710-git.tgz 10984 8a161c237e330eacdaae78a61b98bbdc 24d32656523252a1d0c367ba581ca98063b9ed50 modularize-20190710-git modularize-test-module.asd modularize.asd +modularize-hooks http://beta.quicklisp.org/archive/modularize-hooks/2019-07-10/modularize-hooks-20190710-git.tgz 6119 86d8ed59bb2e6231b3c651372920128a 164b8063183939b2b42aa744e4280bca1a626f35 modularize-hooks-20190710-git modularize-hooks.asd +modularize-interfaces http://beta.quicklisp.org/archive/modularize-interfaces/2019-07-10/modularize-interfaces-20190710-git.tgz 11193 c9730aafa93b237ffe0a5415a45e4c73 e37e1f7754385f011a46a0b0f7112f8ac3c10dc4 modularize-interfaces-20190710-git interfaces-test-implementation.asd modularize-interfaces.asd +moira http://beta.quicklisp.org/archive/moira/2017-11-30/moira-20171130-git.tgz 2823 a1cfcd5ab13cc5dda524d0f5e26e90ce 6e26e71c89b4ecdef7218d572ebcf342a26052bb moira-20171130-git moira.asd +monkeylib-binary-data http://beta.quicklisp.org/archive/monkeylib-binary-data/2011-12-03/monkeylib-binary-data-20111203-git.tgz 4927 ef6b8e9c30e6b8efa915ca35ed962cf3 77232f96c8600789af74f006a7af9eb1fc6e698d monkeylib-binary-data-20111203-git com.gigamonkeys.binary-data.asd +monkeylib-html http://beta.quicklisp.org/archive/monkeylib-html/2018-02-28/monkeylib-html-20180228-git.tgz 7951 2b2b680f1eb02d4392135cebc33825fe 464b87c31dcfde60e5e350c7f2b5bab63bd3eb32 monkeylib-html-20180228-git monkeylib-html.asd +monkeylib-json http://beta.quicklisp.org/archive/monkeylib-json/2018-02-28/monkeylib-json-20180228-git.tgz 4329 253e4e5aa8fd634fc76c97e8b9be0862 56e485b956487256210d5eb76a3031f95d54335d monkeylib-json-20180228-git com.gigamonkeys.json.asd +monkeylib-macro-utilities http://beta.quicklisp.org/archive/monkeylib-macro-utilities/2011-12-03/monkeylib-macro-utilities-20111203-git.tgz 1968 b03c3644ff328ded7e7e0a39741a69ba 4bc771174bdb9bb52952356408d7a617e6b4ce2c monkeylib-macro-utilities-20111203-git com.gigamonkeys.macro-utilities.asd +monkeylib-markup http://beta.quicklisp.org/archive/monkeylib-markup/2012-09-09/monkeylib-markup-20120909-git.tgz 51056 e2f052930d4ed6cbd97b802b20a83646 fcf29d2e6a193626a8c5eb3d2498caf192735479 monkeylib-markup-20120909-git com.gigamonkeys.markup.asd +monkeylib-markup-html http://beta.quicklisp.org/archive/monkeylib-markup-html/2012-02-08/monkeylib-markup-html-20120208-git.tgz 4582 f70d4f0c511f36d6fc4a10a6912b51e0 d1fb1db716fdb7fe0fa845e223d0da5e76629b69 monkeylib-markup-html-20120208-git monkeylib-markup-html.asd +monkeylib-parser http://beta.quicklisp.org/archive/monkeylib-parser/2012-02-08/monkeylib-parser-20120208-git.tgz 22347 3e4327f25a31e78f93fd50de71b41065 48d5b2a1b8072d27c7601124a166fbadb2bc1bb4 monkeylib-parser-20120208-git com.gigamonkeys.parser.asd +monkeylib-pathnames http://beta.quicklisp.org/archive/monkeylib-pathnames/2012-02-08/monkeylib-pathnames-20120208-git.tgz 3689 9f7c261f5a6f3e594c8b63f3a81fd87e 8d3750393675bcd26b42b59cf20ca4e9127d55f2 monkeylib-pathnames-20120208-git com.gigamonkeys.pathnames.asd +monkeylib-prose-diff http://beta.quicklisp.org/archive/monkeylib-prose-diff/2014-07-13/monkeylib-prose-diff-20140713-git.tgz 68305 6c656fe2d6bcb7eaba029b23da783a53 d70a0717980660fb19691b8f40c02fb430187a67 monkeylib-prose-diff-20140713-git com.gigamonkeys.prose-diff.asd +monkeylib-test-framework http://beta.quicklisp.org/archive/monkeylib-test-framework/2010-12-07/monkeylib-test-framework-20101207-git.tgz 7237 cebe94d4ac359f39cf0eef63cf0e8de5 52d736e23f6a71c8ea987186c1f4c1b460c5a356 monkeylib-test-framework-20101207-git com.gigamonkeys.test-framework.asd +monkeylib-text-languages http://beta.quicklisp.org/archive/monkeylib-text-languages/2011-12-03/monkeylib-text-languages-20111203-git.tgz 5234 a5ff209ee992b4fe4685cabd3616bc49 9e02022e60dfbcfa4e2c7399dec3d4e579721383 monkeylib-text-languages-20111203-git monkeylib-text-languages.asd +monkeylib-text-output http://beta.quicklisp.org/archive/monkeylib-text-output/2011-12-03/monkeylib-text-output-20111203-git.tgz 3919 1d0623eadd80d9b0bbfa71b5a6d08d31 12de87a35e9dd6169d0201c3d17f07ab7d9bcd16 monkeylib-text-output-20111203-git monkeylib-text-output.asd +monkeylib-utilities http://beta.quicklisp.org/archive/monkeylib-utilities/2017-04-03/monkeylib-utilities-20170403-git.tgz 12151 323d5400fe092b0aff4be8d39c8bef33 9c55b7c6192c126ff49da725fdadeaf4e90a5d3c monkeylib-utilities-20170403-git com.gigamonkeys.utilities.asd +montezuma http://beta.quicklisp.org/archive/montezuma/2018-02-28/montezuma-20180228-git.tgz 1264435 db964cddda9b92877259d7db67c2aac3 37dd0718f7823760da2d72d050b39a38c56b4758 montezuma-20180228-git contrib/montezuma-indexfiles/montezuma-indexfiles.asd lucene-in-action/lucene-in-action-tests.asd montezuma.asd +mop-utils http://beta.quicklisp.org/archive/mop-utils/2012-08-11/mop-utils-20120811-http.tgz 5309 f320b8601e9d921305b1fd5b405479b6 7ba77dc06ef07c5ff2ef756552a6016d4ba48071 mop-utils-20120811-http mop-utils.asd +moptilities http://beta.quicklisp.org/archive/moptilities/2017-04-03/moptilities-20170403-git.tgz 15618 b118397be325e60a772ea3631c4f19a4 a2b4eb6acad43773290ed22ee7698367476b01f5 moptilities-20170403-git moptilities-test.asd moptilities.asd +more-conditions http://beta.quicklisp.org/archive/more-conditions/2018-08-31/more-conditions-20180831-git.tgz 20791 c4797bd3c6c50fba02a6e8164ddafe28 d81093734a1f68b0ce022eaa1577334d22987390 more-conditions-20180831-git more-conditions.asd +mp3-duration http://beta.quicklisp.org/archive/mp3-duration/2016-02-08/mp3-duration-20160208-git.tgz 2763 fe74eb23d4016d798f4c7ab39fae1991 edeab1547d760345c92b49dbb707adf69c4e16a8 mp3-duration-20160208-git mp3-duration-test.asd mp3-duration.asd +mpc http://beta.quicklisp.org/archive/mpc/2016-09-29/mpc-20160929-git.tgz 22507 7a4be8c7f3c1a896d2fa06c6aff4accf fc09c11b6e330eee4d0435e1fe5a9d09c3d1c803 mpc-20160929-git mpc.asd +mra-wavelet-plot http://beta.quicklisp.org/archive/mra-wavelet-plot/2018-12-10/mra-wavelet-plot-20181210-git.tgz 2672 6e58c7f058b996710f89095bd7d55140 4824e4d538ea298a76d6c69f6df99782ce5e0b41 mra-wavelet-plot-20181210-git mra-wavelet-plot.asd +mt19937 http://beta.quicklisp.org/archive/mt19937/2011-02-19/mt19937-1.1.1.tgz 5551 54c63977b6d77abd66ebe0227b77c143 268d9a0d1dc870bd409bf9a85f80ff39840efd49 mt19937-1.1.1 mt19937.asd +mtif http://beta.quicklisp.org/archive/mtif/2017-11-30/mtif-20171130-git.tgz 36178 a713b90c4790464371cdc469d44a441f 8ee07bbf0c5b5fbfd618054945055ab638c7db57 mtif-20171130-git mtif.asd +mtlisp http://beta.quicklisp.org/archive/mtlisp/2013-06-15/mtlisp-20130615-git.tgz 41092 651cd99d4c77b0d533c1ee94e515b6b7 4d9ce6610ce99f89ddbfaea4d40a4369f8e1c8f8 mtlisp-20130615-git mtlisp.asd +multilang-documentation http://beta.quicklisp.org/archive/multilang-documentation/2019-07-10/multilang-documentation-20190710-git.tgz 7361 ba61cdd7a06d398143c4f18614c2b3a7 fa7caa1284353367149f88f1606465fa4357f49a multilang-documentation-20190710-git multilang-documentation.asd +multiple-value-variants http://beta.quicklisp.org/archive/multiple-value-variants/2014-08-26/multiple-value-variants-1.0.1.tgz 6991 b5676f66549832298262156277a79a52 b149d999e846c682677d7bbfbd3791c1baf73480 multiple-value-variants-1.0.1 multiple-value-variants.asd +multiposter http://beta.quicklisp.org/archive/multiposter/2019-07-10/multiposter-20190710-git.tgz 19032 38c12d3d08ad2b045f1b11e846eb2388 c49a54fb5fe7e314cbcc721677f0162e8b6a295e multiposter-20190710-git multiposter-git.asd multiposter-mastodon.asd multiposter-studio.asd multiposter-tumblr.asd multiposter-twitter.asd multiposter.asd +multival-plist http://beta.quicklisp.org/archive/multival-plist/2012-03-05/multival-plist-20120305-git.tgz 2263 db7767930bc07a150b697a6b63c369db eb4c2b023fccebd18549008ad67aa1ce6d4ace09 multival-plist-20120305-git multival-plist-test.asd multival-plist.asd +mw-equiv http://beta.quicklisp.org/archive/mw-equiv/2010-10-06/mw-equiv-0.1.3.tgz 6115 671497babfd44f6d9c5f0c02bddb457c 4a79edf2ca9f5e65daff7f37323da4f1055d914c mw-equiv-0.1.3 mw-equiv.asd +mystic http://beta.quicklisp.org/archive/mystic/2016-02-08/mystic-20160208-git.tgz 7566 c76b5583defbbc0a921332f496fee7c5 a0ddfaea0aea12b7ce41e05d446626cf02a5d99f mystic-20160208-git mystic-file-mixin.asd mystic-fiveam-mixin.asd mystic-gitignore-mixin.asd mystic-library-template.asd mystic-readme-mixin.asd mystic-test.asd mystic-travis-mixin.asd mystic.asd +myway http://beta.quicklisp.org/archive/myway/2018-10-18/myway-20181018-git.tgz 5345 88adecdaec89ceb262559d443512e545 59f2da1260d448da0d9fc41e6ae2ddde26d5f5bc myway-20181018-git myway-test.asd myway.asd +myweb http://beta.quicklisp.org/archive/myweb/2015-06-08/myweb-20150608-git.tgz 29572 bc91336495ca1421dac79bf14c5e6881 9e6e03663659d582aca58d1bfb7606952e9a7fcf myweb-20150608-git myweb.asd +named-read-macros http://beta.quicklisp.org/archive/named-read-macros/2018-02-28/named-read-macros-20180228-git.tgz 7508 d0d68f2a17654219f1b1aebd16978003 dbe6462ca342c5620b1438265f93785053df5d3a named-read-macros-20180228-git named-read-macros.asd test/named-read-macros-test.asd +named-readtables http://beta.quicklisp.org/archive/named-readtables/2018-01-31/named-readtables-20180131-git.tgz 32869 46db18ba947dc0aba14c76471604448d 6a6509d4c21a89df82098635fe655eb1d156dbbf named-readtables-20180131-git named-readtables.asd +nanovg-blob http://beta.quicklisp.org/archive/nanovg-blob/2018-02-28/nanovg-blob-stable-c9ef601c-git.tgz 805423 1efaa411fe9fcde20207682ec4e965a8 633c8e7c3059eb7269dfed86758b258de3994d05 nanovg-blob-stable-c9ef601c-git nanovg-blob.asd +napa-fft3 http://beta.quicklisp.org/archive/napa-fft3/2015-12-18/napa-fft3-20151218-git.tgz 31959 4930569d5c4092ab11f76d8886779e6e 61afdce14dfe27431acbbd063c9840786b5e5d11 napa-fft3-20151218-git napa-fft3.asd +narrowed-types http://beta.quicklisp.org/archive/narrowed-types/2018-02-28/narrowed-types-20180228-git.tgz 2510 a149f985d2032c17210a3f75a9eca101 130b28978940159ed19df76eed1945738cfd1b05 narrowed-types-20180228-git narrowed-types-test.asd narrowed-types.asd +neo4cl http://beta.quicklisp.org/archive/neo4cl/2018-08-31/neo4cl-20180831-git.tgz 10076 bc94c945ddee04e872ffb3958c1a2577 93efd8fbc1df222b66a3c401344c036b4b83ade6 neo4cl-20180831-git src/neo4cl.asd test/neo4cl-test.asd +net-telent-date http://beta.quicklisp.org/archive/net-telent-date/2010-10-06/net-telent-date_0.42.tgz 12575 6fedf40113b2462f7bd273d07950066b 2a0efdd496136ba7d0d1d7b701ff57f9f0a0929f net-telent-date_0.42 net-telent-date.asd +network-addresses http://beta.quicklisp.org/archive/network-addresses/2016-06-28/network-addresses-20160628-git.tgz 4504 6b48746dc7beff85ed4b81edc4d31732 aa2e821a7e184fa885827db8b111896d641d3f6b network-addresses-20160628-git network-addresses-test.asd network-addresses.asd +new-op http://beta.quicklisp.org/archive/new-op/2019-01-07/new-op-20190107-git.tgz 22260 6c2743ca9eaac48b619d911008f44795 6fb4b2b881e489757f4e4de9604b9f59f10dd8a7 new-op-20190107-git new-op.asd +nibbles http://beta.quicklisp.org/archive/nibbles/2018-08-31/nibbles-20180831-git.tgz 17647 4badf1f066a59c3c270d40be1116ecd5 8aa99c491fb71a18bf8da843556b1df0da368152 nibbles-20180831-git nibbles.asd +nineveh http://beta.quicklisp.org/archive/nineveh/2019-10-07/nineveh-release-quicklisp-0a10a846-git.tgz 47692 c7c3fe5e3a5a3bb9e8e7de3086cf95bb 43962ced034bf55962f61fe06ba75c2dd85a47a6 nineveh-release-quicklisp-0a10a846-git nineveh.asd +ningle http://beta.quicklisp.org/archive/ningle/2019-10-07/ningle-20191007-git.tgz 7069 13c890c05123b77d1d4c0f811490bfb2 f4677ddadcb493627fba8f96b6dd4142694afe57 ningle-20191007-git ningle-test.asd ningle.asd +nodgui http://beta.quicklisp.org/archive/nodgui/2019-12-27/nodgui-20191227-git.tgz 119723 8aefa966cc15e060128411810b3e1776 44069f8dfd09491695d398e8b8da762b6dc97dce nodgui-20191227-git nodgui.asd +north http://beta.quicklisp.org/archive/north/2019-07-10/north-20190710-git.tgz 53727 911fa6dff0ba34301ab3b7ed26194a69 0e36470bba12f4bc9e533a8efab20f452f42d793 north-20190710-git example/north-example.asd north-core.asd north-dexador.asd north-drakma.asd north.asd +nsort http://beta.quicklisp.org/archive/nsort/2015-05-05/nsort-20150505-git.tgz 1785 71e01656a21f61447e0298f89d3af456 912766fd5765889a4ce4a6a0b64fc2d14d29f63a nsort-20150505-git nsort.asd +nst http://beta.quicklisp.org/archive/nst/2016-03-18/nst-4.1.0.tgz 635557 4fedd2bed9ead1c50901087ff8b14ef6 037e7bb17db08f52a0286b5d4f2d7388792ede38 nst-4.1.0 asdf-nst.asd nst.asd test/direct/nst-simple-tests.asd test/lisp/comp-set/comp-set.asd test/manual/nst-manual-tests.asd test/meta/mnst-relay.asd test/meta/nst-meta-tests.asd test/nst-test-jenkins.asd test/nst-test.asd test/util/nst-selftest-utils.asd utils/mop/nst-mop-utils.asd +nuclblog http://beta.quicklisp.org/archive/nuclblog/2014-08-26/nuclblog-20140826-git.tgz 20053 fb80583640212d0bfc452f9156917eac ffded3e808a703fdda65f3b3ab7c677c9be60946 nuclblog-20140826-git nuclblog.asd +nuklear-blob http://beta.quicklisp.org/archive/nuklear-blob/2018-02-28/nuklear-blob-stable-6c297dc2-git.tgz 1144021 ff3ca427d01ca1b40a4793aae8ff5669 3aa2e0c8484bead4269be706f87593cf9c8b30d0 nuklear-blob-stable-6c297dc2-git nuklear-blob.asd +num-utils http://beta.quicklisp.org/archive/num-utils/2019-11-30/num-utils-20191130-git.tgz 69549 d48ab213d48378c1ed16506d43472c63 3c8458aea70de41f285c5bd93ee84eab036d39af num-utils-20191130-git num-utils.asd +numcl http://beta.quicklisp.org/archive/numcl/2019-12-27/numcl-20191227-git.tgz 252024 8832fb53f6839b4713d39972d8c01849 99f19f64e445e3e8b517c3ff7f5a9ed01fcbcd1f numcl-20191227-git numcl.asd numcl.test.asd +numpy-file-format http://beta.quicklisp.org/archive/numpy-file-format/2019-07-10/numpy-file-format-20190710-git.tgz 4675 06d473abeb72c1ff6d8905dfe2fc19ef 1c134c560b2e98b3f39f6ded3c0b4a37b8e2383b numpy-file-format-20190710-git code/numpy-file-format.asd +oclcl http://beta.quicklisp.org/archive/oclcl/2019-05-21/oclcl-20190521-git.tgz 171806 3e1768e4d9c1412aabd19fc23457ca8f 2f49a21ab843dc52b012a82c286142994c122e95 oclcl-20190521-git oclcl-examples.asd oclcl-test.asd oclcl.asd +ode-blob http://beta.quicklisp.org/archive/ode-blob/2018-02-28/ode-blob-stable-bf2a5e4e-git.tgz 3757262 0aab7098d5e984763feb298da1c041fb cd711fe77374c6065f16821af4e86eac156dab9a ode-blob-stable-bf2a5e4e-git ode-blob.asd +oe-encode http://beta.quicklisp.org/archive/oe-encode/2015-08-04/oe-encode-20150804-git.tgz 49756 317e7cb5295306a3b64a7b5cfe673093 1d2ad0214c58b88ddff8c2f66e8ef1d89b6de0ba oe-encode-20150804-git oe-encode.asd +omer-count http://beta.quicklisp.org/archive/omer-count/2019-01-07/omer-count-20190107-git.tgz 15545 286a7a336643883ab687d59e45411fd0 87d0a5cf584feec73ae0d49f0450d4281358562f omer-count-20190107-git eclecticse.omer.asd +oneliner http://beta.quicklisp.org/archive/oneliner/2013-10-03/oneliner-20131003-git.tgz 3129 8709f2596797542709d9fc02e557d8c2 b2c7d3ee581dc13e43cf14a85b1f3e0bca093625 oneliner-20131003-git cl-oneliner.asd +ook http://beta.quicklisp.org/archive/ook/2019-01-07/ook-20190107-git.tgz 12018 2d97c0df14bbeb217c3f040debad16c8 ee5b43757da4eec24f07ed7ae92af92823633603 ook-20190107-git ook.asd +oook http://beta.quicklisp.org/archive/oook/2017-11-30/oook-20171130-git.tgz 12023 eb6ee68a5f48b3720d7285fae7336485 b368840c0547253cb2c82e9ef9c48ffd27fed565 oook-20171130-git oook.asd +open-location-code http://beta.quicklisp.org/archive/open-location-code/2019-05-21/open-location-code-20190521-git.tgz 16291 b4284a6d6e2cc69ed83c55cda0b12e42 3026ae7a678f5cee8ee82cad27c742d604605ff7 open-location-code-20190521-git open-location-code.asd +open-vrp http://beta.quicklisp.org/archive/open-vrp/2014-09-14/open-vrp-20140914-git.tgz 925579 718ad8132bb06eb5a66b1c1a814b7e66 066d3adb2be495e1a76dadf9e55ec2e66519715c open-vrp-20140914-git open-vrp-lib.asd open-vrp.asd +openal-blob http://beta.quicklisp.org/archive/openal-blob/2018-02-28/openal-blob-stable-d414fc89-git.tgz 2266861 d372c27834a955621f3c8e1a3f853908 8a962e86b10de8af75d6b6b9c1f126d3dec759e9 openal-blob-stable-d414fc89-git openal-blob.asd +openid-key http://beta.quicklisp.org/archive/openid-key/2018-12-10/openid-key-20181210-git.tgz 3284 cbe196eef93ee9eec7ef117557c440b2 4cdb875b541259e7bb9bbf8d26244f3dba1078b2 openid-key-20181210-git openid-key-test.asd openid-key.asd +opticl http://beta.quicklisp.org/archive/opticl/2018-12-10/opticl-20181210-git.tgz 193833 4d33d1faff5db29a1ffe65df37555f4f 16a4b01d3a336929a0389211e349e1ea2122d143 opticl-20181210-git opticl-doc.asd opticl.asd +opticl-core http://beta.quicklisp.org/archive/opticl-core/2017-10-19/opticl-core-20171019-git.tgz 4502 612766d24e14244a87d0bf41a789ed5a 90fe1cccff0248626018b5634abdf717f5e8c445 opticl-core-20171019-git opticl-core.asd +optima http://beta.quicklisp.org/archive/optima/2015-07-09/optima-20150709-git.tgz 20345 20523dc3dfc04bb2526008dff0842caa aec56f162a6b34024d0b419ed9dfb35ef9e75be6 optima-20150709-git optima.asd optima.ppcre.asd optima.test.asd +org-davep-dict http://beta.quicklisp.org/archive/org-davep-dict/2019-05-21/org-davep-dict-20190521-git.tgz 6731 a5c307e394ddaf3dc23fd415fb025e04 84ce779221666927b4e07aaa47fcd26fb24f7bf0 org-davep-dict-20190521-git org-davep-dict.asd +org-davep-dictrepl http://beta.quicklisp.org/archive/org-davep-dictrepl/2019-05-21/org-davep-dictrepl-20190521-git.tgz 2983 311107f58978970b214e575690815a62 89eb453c83abfd72dd4c6a821a5b9704794e2fab org-davep-dictrepl-20190521-git org-davep-dictrepl.asd +org-sampler http://beta.quicklisp.org/archive/org-sampler/2016-03-18/org-sampler-0.2.0.tgz 61604 1d367f79a5cb325abce3e1640ce6bc91 e7e572deb75c9bb2f55bdca3a5915bf1fb4440da org-sampler-0.2.0 org-sampler.asd +origin http://beta.quicklisp.org/archive/origin/2019-12-27/origin-20191227-git.tgz 32925 6a1916f3d76c940967dd204be8f9ea1c 6daccc964991755c6dafaaaf40e18ebef136d7f4 origin-20191227-git origin.asd origin.test.asd +orizuru-orm http://beta.quicklisp.org/archive/orizuru-orm/2019-10-07/orizuru-orm-20191007-git.tgz 49639 3ea3d1379b9051835ff209074a67655b 71ccbac81c4d6cdc4c868be10a97d8d76e8b4960 orizuru-orm-20191007-git orizuru-orm.asd +osc http://beta.quicklisp.org/archive/osc/2019-05-21/osc-20190521-git.tgz 17189 3de093d1f99a34544e8555d3e51c7f6e 34689d25a01a1ef71f27de6f3bc4179a0b732e3e osc-20190521-git osc.asd +osicat http://beta.quicklisp.org/archive/osicat/2019-07-10/osicat-20190710-git.tgz 54723 9a062b84fce8979686c17d676ff0c0e5 49bbb5830916a90b306460aa396b6b3cee7db912 osicat-20190710-git osicat-tests.asd osicat.asd +osmpbf http://beta.quicklisp.org/archive/osmpbf/2019-12-27/osmpbf-20191227-git.tgz 18603 444df002a3e438b778531aa2fb8656b1 29c085b73c5dc84a3c14ae2c7d934b81d605e3d4 osmpbf-20191227-git osmpbf.asd +overlord http://beta.quicklisp.org/archive/overlord/2019-11-30/overlord-20191130-git.tgz 59572 1bc805d3c001a1a1416663edd488af1f d647d87e17a8c42e806162b10a2c6c6f13f8146f overlord-20191130-git overlord.asd +oxenfurt http://beta.quicklisp.org/archive/oxenfurt/2019-07-10/oxenfurt-20190710-git.tgz 23362 d3399266edf13969b0031f972a15477f 146d6718296832a33ebd25076d743677b4a74a95 oxenfurt-20190710-git oxenfurt-core.asd oxenfurt-dexador.asd oxenfurt-drakma.asd oxenfurt.asd +pack http://beta.quicklisp.org/archive/pack/2011-06-19/pack-20110619-git.tgz 3684 f769fa83d8487575facf6fe5adf9b245 e33f75deac5ab3a1facc24fc378c9184b6be6d04 pack-20110619-git pack.asd +package-renaming http://beta.quicklisp.org/archive/package-renaming/2012-04-07/package-renaming-20120407-git.tgz 4522 b9d7b446196fba632edd088bf9ad23ae bcba6923289ab9cf2f539dec333853ff7d9e0a65 package-renaming-20120407-git package-renaming-test.asd package-renaming.asd +packet http://beta.quicklisp.org/archive/packet/2015-03-02/packet-20150302-git.tgz 10533 71312a40fa6abb7027b94c8a57a90d00 5c459eb3feebdfed53359a7b021cba522ae6df71 packet-20150302-git packet.asd +paiprolog http://beta.quicklisp.org/archive/paiprolog/2018-02-28/paiprolog-20180228-git.tgz 172150 1f04f011c9f09d7fe854b98e845d21bd e5505fd5ff9fb77bf6e3374ab0d5e9e37cc7186a paiprolog-20180228-git paiprolog.asd unifgram.asd +pal http://beta.quicklisp.org/archive/pal/2015-06-08/pal-20150608-git.tgz 3707918 ce7afd79040188475efc67ae87287949 795d4e4f69cb4132ee35b641e564ee01ab6365d9 pal-20150608-git examples/bermuda/bermuda.asd pal.asd +pandocl http://beta.quicklisp.org/archive/pandocl/2015-09-23/pandocl-20150923-git.tgz 2581 ee9450a491206f3c606c05bb63268c08 613046a725fc6925372f484d1771c6acf4b74b0d pandocl-20150923-git pandocl.asd +pango-markup http://beta.quicklisp.org/archive/pango-markup/2019-07-10/pango-markup-20190710-git.tgz 9296 811d7fb0d9d3744030c5ff63873d9a8c 67ac0851ed2b9f01ca5a59c18c3a9c95e4f122c8 pango-markup-20190710-git pango-markup.asd +papyrus http://beta.quicklisp.org/archive/papyrus/2018-01-31/papyrus-20180131-git.tgz 75141 21f9ff35cb1dc7e0b908747c99bbfa63 6720de69bc909d07e0f4b9818b751361a1e16925 papyrus-20180131-git papyrus.asd +parachute http://beta.quicklisp.org/archive/parachute/2019-11-30/parachute-20191130-git.tgz 52496 ab5ee5589a6db1dbe0d6dbc1671022c6 3e30731da18f6ebf73c2e4ad5ea7ad3fe629917f parachute-20191130-git compat/parachute-fiveam.asd compat/parachute-lisp-unit.asd compat/parachute-prove.asd parachute.asd +parameterized-function http://beta.quicklisp.org/archive/parameterized-function/2019-03-07/parameterized-function-20190307-hg.tgz 3178 13de98b8381cd84c9cad3dde122e919a d0ee504ad9a10a393ff6326f1885ebfd16981149 parameterized-function-20190307-hg parameterized-function.asd +paren-files http://beta.quicklisp.org/archive/paren-files/2011-04-18/paren-files-20110418-git.tgz 11665 cf10bbcfa01d65e1487b2764d3967aeb 136c1ec5faace0cb6642fde48c9c8c317e0a3b91 paren-files-20110418-git paren-files.asd +paren-test http://beta.quicklisp.org/archive/paren-test/2017-08-30/paren-test-20170830-git.tgz 2796 1699edb46292e81cc416a717d42eb13a 8337b21fd440117d26c77f1ce1c6c3d81ec49265 paren-test-20170830-git examples/arith.asd paren-test.asd +paren-util http://beta.quicklisp.org/archive/paren-util/2011-04-18/paren-util-20110418-git.tgz 9583 ce8212375a6586235774baa4f7cfc4c5 1928ce6c595d307357e01e49fd47c32993b8562e paren-util-20110418-git paren-util.asd +paren6 http://beta.quicklisp.org/archive/paren6/2019-11-30/paren6-20191130-git.tgz 11611 0a7af3a318e176871cd0f5f54f701329 1fe467be360247f27cb410c5f19989cb9a002d00 paren6-20191130-git paren6.asd test-paren6.asd +parenml http://beta.quicklisp.org/archive/parenml/2015-09-23/parenml-20150923-git.tgz 2084 e02a5cb32d6ceda30744c90589b854cb 87db838f002b09178393e5162ebf681b43d23be6 parenml-20150923-git parenml-test.asd parenml.asd +parenscript http://beta.quicklisp.org/archive/parenscript/2018-12-10/Parenscript-2.7.1.tgz 103952 047c9a72bd36f1b4a5ec67af9453a0b9 2532046ecb26bcbc808bf8ed2d14d140a9a33fba Parenscript-2.7.1 parenscript.asd parenscript.tests.asd +parenscript-classic http://beta.quicklisp.org/archive/parenscript-classic/2011-12-03/parenscript-classic-20111203-darcs.tgz 185472 9d355c65babf238bdce498ff628e187b 3ea1563d8e21583c48b31677797e99b74fd31492 parenscript-classic-20111203-darcs parenscript-classic.asd +parse http://beta.quicklisp.org/archive/parse/2019-10-07/parse-20191007-git.tgz 7392 9b12a61e279f5cf969b45feff6946efa ab4b3da76e74abf9f5ca8a76c877c9d303caf79d parse-20191007-git parse.asd +parse-declarations http://beta.quicklisp.org/archive/parse-declarations/2010-10-06/parse-declarations-20101006-darcs.tgz 36664 e49222003e5b59c5c2a0cf58b86cfdcd f2ed7dbb076058e4aef57553469759b13a0a618c parse-declarations-20101006-darcs parse-declarations-1.0.asd +parse-float http://beta.quicklisp.org/archive/parse-float/2017-10-19/parse-float-20171019-git.tgz 4696 182135a8478013dbd52b87a9f378adc0 c280e2e4f7fd153d0ddec5de03f56b0891f33e24 parse-float-20171019-git parse-float.asd +parse-front-matter http://beta.quicklisp.org/archive/parse-front-matter/2016-08-25/parse-front-matter-20160825-git.tgz 1378 478c27505370135f5d8859fe5c755431 2da48a358580ac203b5762acdce7eb3e6516f39b parse-front-matter-20160825-git parse-front-matter-test.asd parse-front-matter.asd +parse-js http://beta.quicklisp.org/archive/parse-js/2016-04-21/parse-js-20160421-git.tgz 10664 14049fdc5f55bf48d7e3d54a9549a97e c6baef888b9383b2d437d31426f231de8a31b064 parse-js-20160421-git parse-js.asd +parse-number http://beta.quicklisp.org/archive/parse-number/2018-02-28/parse-number-v1.7.tgz 5715 b9ec925018b8f10193d73403873dde8f 472816dd6ad673d3be65ae33495c5378ba6b6588 parse-number-v1.7 parse-number.asd +parse-number-range http://beta.quicklisp.org/archive/parse-number-range/2012-11-25/parse-number-range-1.0.tgz 5733 a1a173bffeafcdca9320473f14103f80 c79d229ba4d3a0c5267b21b3560026b78a8c2300 parse-number-range-1.0 parse-number-range.asd +parseltongue http://beta.quicklisp.org/archive/parseltongue/2013-03-12/parseltongue-20130312-git.tgz 27941 4519905cf797085c6063c33bf0107b9c 3f9099ad7ee505fe0b8abaaca1e32d03bf6892b0 parseltongue-20130312-git parseltongue.asd +parseq http://beta.quicklisp.org/archive/parseq/2018-07-11/parseq-20180711-git.tgz 40220 850be8911e7bda4c0fa70da9891ab348 2e6f48a219623b5221774a3bc8f11fe999aafe75 parseq-20180711-git parseq.asd +parser.common-rules http://beta.quicklisp.org/archive/parser.common-rules/2019-08-13/parser.common-rules-20190813-git.tgz 18693 ac4b894c728378c016a4ab71eb00503f b768c951247e8f9596abcd52b67a9869d8c9e98e parser.common-rules-20190813-git parser.common-rules.asd parser.common-rules.operators.asd +parser.ini http://beta.quicklisp.org/archive/parser.ini/2018-10-18/parser.ini-20181018-git.tgz 11142 83943b433684f7bef2ad113adef8e4fd 60010609b62b382abbdda31e8824ab3026a42ffe parser.ini-20181018-git parser.ini.asd +parsley http://beta.quicklisp.org/archive/parsley/2019-07-10/parsley-20190710-git.tgz 2598 5e7ad4fb112607379dd20e2ad52ee766 d32698da74e3fadf88145220be4cd0c2d828addc parsley-20190710-git parsley.asd +patchwork http://beta.quicklisp.org/archive/patchwork/2019-10-08/patchwork-20191008-git.tgz 5446 0b6ec00c7d0cd7b60ee98bfc71fc9acc 2f96d153b0439cfbcf0b121771f6a11275ec2cac patchwork-20191008-git patchwork.asd +path-parse http://beta.quicklisp.org/archive/path-parse/2016-04-21/path-parse-20160421-git.tgz 2115 83ace94d06e0759f717bf11be698602e 331bfeef1557fa4133220cac48bf4afb4f62a8da path-parse-20160421-git path-parse-test.asd path-parse.asd +path-string http://beta.quicklisp.org/archive/path-string/2016-08-25/path-string-20160825-git.tgz 4983 bc3d1e818a793d955eb6877f67bd4d52 833c85edc0fffcfcef2a9b5cfd111910c648293a path-string-20160825-git path-string-test.asd path-string.asd +pathname-utils http://beta.quicklisp.org/archive/pathname-utils/2019-07-10/pathname-utils-20190710-git.tgz 11927 b9a4eca84ddaa0e4daa6f2a66f788d3e 1f11bb91ee40ef38fc9de2a3f1af40a58b135e81 pathname-utils-20190710-git pathname-utils-test.asd pathname-utils.asd +patron http://beta.quicklisp.org/archive/patron/2013-04-20/patron-20130420-git.tgz 12195 dd08fa2247852002f9884ccc842aeae4 6d2f8130f0ab4eab47b9aba79e3cc060ef6da096 patron-20130420-git patron.asd +pcall http://beta.quicklisp.org/archive/pcall/2010-10-06/pcall-0.3.tgz 14561 019d85dfd1d5d0ee8d4ee475411caf6b 65626582e38d7a8b3180382a694a96290fde4b2c pcall-0.3 pcall-queue.asd pcall.asd +percent-encoding http://beta.quicklisp.org/archive/percent-encoding/2012-10-13/percent-encoding-20121013-git.tgz 5240 de4b28564907c12b598630d27135d80f c945ddb56afaf0244019242f77e396edfe870e1f percent-encoding-20121013-git percent-encoding.asd +periodic-table http://beta.quicklisp.org/archive/periodic-table/2011-10-01/periodic-table-1.0.tgz 5100 1fe8e203b8b622857fe1af4ade13e7ce 1f118c131789908e9108b84e72c2e1325f1ee22e periodic-table-1.0 periodic-table.asd +periods http://beta.quicklisp.org/archive/periods/2019-03-07/periods-20190307-git.tgz 32775 2c6e7fb7b1bd2ce68fa8b4a465bbf1b8 8d5404ba512157b680285dbe51a8c5f0ed8d445e periods-20190307-git periods-series.asd periods.asd +perlre http://beta.quicklisp.org/archive/perlre/2018-10-18/perlre-20181018-git.tgz 7321 48d78039676ff6d2373bf194132e87d1 84d7222acf11fb1ef2cbe59a7a911e16a761913e perlre-20181018-git perlre.asd +persistent-tables http://beta.quicklisp.org/archive/persistent-tables/2012-02-08/persistent-tables-20120208-git.tgz 2585 08f6feb0c4716102d9f4c0ebe817a7be d53ebc25f643ca4ff4f4dda34421ddd1f6a2137c persistent-tables-20120208-git persistent-tables.asd +persistent-variables http://beta.quicklisp.org/archive/persistent-variables/2013-03-12/persistent-variables-20130312-git.tgz 117127 ba06997b04bdbeee85fc8861e0cdf687 ac9009d2637c21140d015c84b88200659808a7e1 persistent-variables-20130312-git persistent-variables.asd +petalisp http://beta.quicklisp.org/archive/petalisp/2019-12-27/petalisp-20191227-git.tgz 110026 e386843163c9b7be44df67aa3f1f4024 b158a44b6bb9dc21a985488f8c654f809aeecd48 petalisp-20191227-git code/api/petalisp.api.asd code/core/petalisp.core.asd code/graphviz/petalisp.graphviz.asd code/ir-backend/petalisp.ir-backend.asd code/ir/petalisp.ir.asd code/native-backend/petalisp.native-backend.asd code/native-compiler/petalisp.blueprint-compiler.asd code/petalisp.asd code/reference-backend/petalisp.reference-backend.asd code/scheduler/petalisp.scheduler.asd code/test-suite/petalisp.test-suite.asd code/type-inference/petalisp.type-inference.asd code/utilities/petalisp.utilities.asd examples/petalisp.examples.asd +petit.package-utils http://beta.quicklisp.org/archive/petit.package-utils/2014-08-26/petit.package-utils-20140826-git.tgz 2290 58e6dceab797eec3cea779e5fb366486 f8a4735180f1d47481349ed8801433a4a6a5a8df petit.package-utils-20140826-git petit.package-utils.asd +petit.string-utils http://beta.quicklisp.org/archive/petit.string-utils/2014-11-06/petit.string-utils-20141106-git.tgz 4262 dea2dea0ac8045a1930a81231a1ac39b 8169426736e26e55f30171560c3b0e17c0175eea petit.string-utils-20141106-git petit.string-utils-test.asd petit.string-utils.asd +petri http://beta.quicklisp.org/archive/petri/2019-02-02/petri-20190202-git.tgz 139161 9de1c080844a2430c69b41b9be625c3c 14be4e87ea4efea0e254459ec1ca3c094c9fe038 petri-20190202-git petri.asd +pettomato-deque http://beta.quicklisp.org/archive/pettomato-deque/2012-01-07/pettomato-deque-20120107-git.tgz 5573 f4aebae99019f5ca7c82fec60540bbd9 7f132a9c5c15aac2d555bc1c19570973d32eb5c3 pettomato-deque-20120107-git pettomato-deque-tests.asd pettomato-deque.asd +pettomato-indexed-priority-queue http://beta.quicklisp.org/archive/pettomato-indexed-priority-queue/2012-09-09/pettomato-indexed-priority-queue-20120909-git.tgz 7555 f734b68ce8cdb911562cdd62eed1d5aa fdeebe7c9c560e4c559c18ba9ee833310685a1eb pettomato-indexed-priority-queue-20120909-git pettomato-indexed-priority-queue-tests.asd pettomato-indexed-priority-queue.asd +pg http://beta.quicklisp.org/archive/pg/2015-06-08/pg-20150608-git.tgz 48921 11a6ddac157a7443155158e255a2452b 6e5a808a1b08d0049450724574058280cf3a8a2d pg-20150608-git pg.asd +pgloader http://beta.quicklisp.org/archive/pgloader/2019-02-02/pgloader-v3.6.1.tgz 3677520 9cba0e3afa1706a20cfdeced7ad1fce2 ca692deb0d4adecad7d351beb8180c775f09b78b pgloader-v3.6.1 pgloader.asd +phoe-toolbox http://beta.quicklisp.org/archive/phoe-toolbox/2019-11-30/phoe-toolbox-20191130-git.tgz 9300 051096aa7c921ca6179ae76e7d85675c 2f7e572ede4b16fc572518980bed8d2b74cb9b4f phoe-toolbox-20191130-git phoe-toolbox.asd +physical-quantities http://beta.quicklisp.org/archive/physical-quantities/2018-07-11/physical-quantities-20180711-git.tgz 30191 3e8e842b0e68b2ca2d446bead7ca0a1d 3ff468dd80a6f49475c13eff113eb3ab7b87cb9e physical-quantities-20180711-git physical-quantities.asd +piggyback-parameters http://beta.quicklisp.org/archive/piggyback-parameters/2019-10-07/piggyback-parameters-20191007-git.tgz 6763 65d36af31df9beeec878cc4d7ce0ba85 50544fdcb667c6a092e2a48dabcc3c44a5f6fcf1 piggyback-parameters-20191007-git piggyback-parameters.asd +pileup http://beta.quicklisp.org/archive/pileup/2015-07-09/pileup-20150709-git.tgz 20217 230aeb8bbb0993c5fecd4ef47052623f 045fe18800b0e56283617fa5b032c483f38be280 pileup-20150709-git pileup.asd +pipes http://beta.quicklisp.org/archive/pipes/2015-09-23/pipes-20150923-git.tgz 5603 77717361af87e7a83d38e84d08ad29f5 e7ce78dc510136ebd0b8b6a7495fac662233a363 pipes-20150923-git pipes.asd +piping http://beta.quicklisp.org/archive/piping/2019-07-10/piping-20190710-git.tgz 8533 852246a0c773a047dfb023638198387a 0f0fd020438d640c211736f0e572d11e4388edeb piping-20190710-git piping.asd +pithy-xml http://beta.quicklisp.org/archive/pithy-xml/2010-10-06/pithy-xml-20101006-git.tgz 10188 5401547ac31ab9c502d3409a9200a0dc 9445d371b1e0801e3e75ff112f8ba551bb372276 pithy-xml-20101006-git pithy-xml.asd +pjlink http://beta.quicklisp.org/archive/pjlink/2019-10-07/pjlink-20191007-git.tgz 14963 6d48f93695a792dbc2fb5c702596642a 04bcc61e1d3cdd6f11dfae46759542e906168159 pjlink-20191007-git src/pjlink.asd +place-modifiers http://beta.quicklisp.org/archive/place-modifiers/2012-11-25/place-modifiers-2.1.tgz 10202 8c209e6ee7e376b20b447a4e75fb12e3 3a15cc3cd06e587cb81222057b99efa0a27a1545 place-modifiers-2.1 place-modifiers.asd +place-utils http://beta.quicklisp.org/archive/place-utils/2018-10-18/place-utils-0.2.tgz 14315 5462562949ab3a8b5a9f40e9e6d2a628 164c95f8afeab6e8ddf256f1f845108665035fa0 place-utils-0.2 place-utils.asd +plain-odbc http://beta.quicklisp.org/archive/plain-odbc/2019-11-30/plain-odbc-20191130-git.tgz 60040 cfa0da32a083a406344e6f6504d962de 9a7a0ce75ac9e1ef7c2fddc0705a1b2429196400 plain-odbc-20191130-git plain-odbc.asd +planks http://beta.quicklisp.org/archive/planks/2011-05-22/planks-20110522-git.tgz 13152 b0881e48b242ea36e95a815ba6118950 6fd7b423ace8306647696ae42d465683bec59e1a planks-20110522-git planks.asd +plexippus-xpath http://beta.quicklisp.org/archive/plexippus-xpath/2019-05-21/plexippus-xpath-20190521-git.tgz 56479 eb9a4c39a7c37aa0338c401713b3f944 6acb71007298138bb494e04abe39a79fff54af86 plexippus-xpath-20190521-git xpath.asd +plokami http://beta.quicklisp.org/archive/plokami/2019-07-10/plokami-20190710-git.tgz 20055 2ec548790adf34ae9d0ffa3b3ba2549c 5b5c0dc3f9bbe2570e54aa4400b221a20cef9232 plokami-20190710-git plokami.asd +pludeck http://beta.quicklisp.org/archive/pludeck/2018-08-31/pludeck-20180831-git.tgz 5125 7cc744ed744245026604347abf01a539 3bed71c98b172d330579aaa8833575f9f7b5b7f3 pludeck-20180831-git pludeck.asd +plump http://beta.quicklisp.org/archive/plump/2019-07-10/plump-20190710-git.tgz 50917 e3276779e368758274156c9477f0b22a a2d8f464c4303e047d5b1bb982311ab11e82f09d plump-20190710-git plump-dom.asd plump-lexer.asd plump-parser.asd plump.asd +plump-bundle http://beta.quicklisp.org/archive/plump-bundle/2019-07-10/plump-bundle-20190710-git.tgz 7705 a89ccc2557c1657fa080302d5c929a6d 7a4b27d045b483bfc99ecfd43e5084bc6b985e60 plump-bundle-20190710-git plump-bundle.asd +plump-sexp http://beta.quicklisp.org/archive/plump-sexp/2019-07-10/plump-sexp-20190710-git.tgz 6669 d5dd63dd63cff2095b5f38211f684fd4 0dcbf5533db0fa9212ba9169bdcb14513885ae45 plump-sexp-20190710-git plump-sexp.asd +plump-tex http://beta.quicklisp.org/archive/plump-tex/2019-07-10/plump-tex-20190710-git.tgz 6490 ecef24ab6111712b5d0da63cc5e86a92 7badffb575c1b39a1f25886990f9b9ec48b848fe plump-tex-20190710-git plump-tex-test.asd plump-tex.asd +png-read http://beta.quicklisp.org/archive/png-read/2017-08-30/png-read-20170830-git.tgz 8677 40354aa5f3f3321a4d42629c15c6f9f7 d36071bb47abcda177284afddd83cf518d579b19 png-read-20170830-git png-read.asd +pngload http://beta.quicklisp.org/archive/pngload/2019-10-07/pngload-20191007-git.tgz 94912 3f2e9dbc56cefbc480cac2faaa97b49a 0b79824eebdb1644283ab767b2387f9824b00ae9 pngload-20191007-git pngload.asd pngload.test.asd +pngload-fast http://beta.quicklisp.org/archive/pngload-fast/2019-10-07/pngload-fast-20191007-git.tgz 94919 8f9f1aaeabea83e8b3c75f348a123606 1009b43c9e4cd2428e00518e843dfebd1db771d0 pngload-fast-20191007-git pngload-fast.asd pngload-fast.test.asd +poler http://beta.quicklisp.org/archive/poler/2018-12-10/poler-20181210-git.tgz 6505 9f7588fcb283ff5c56bab084304fc4a3 fbf7235432d08b6d488bd1282ba19dddd9e0db36 poler-20181210-git poler-test.asd poler.asd +policy-cond http://beta.quicklisp.org/archive/policy-cond/2019-03-07/policy-cond-20190307-hg.tgz 6132 1773f5aa332484e6742adf38e9fd4b15 51f227d249080950afa1d16fa3fefaa4e0967fab policy-cond-20190307-hg policy-cond.asd +polisher http://beta.quicklisp.org/archive/polisher/2019-12-27/polisher-20191227-git.tgz 6538 b6d069250705e6a07378beeaab5eb002 c7e88975635c889520c274d44a6a2d2d6b8e72dc polisher-20191227-git polisher.asd polisher.test.asd +pooler http://beta.quicklisp.org/archive/pooler/2015-06-08/pooler-20150608-git.tgz 4985 75efc3d397c6962954ec3c37b0f45c5f b118bb296d55bcd7d783a4b52b293a970b46728c pooler-20150608-git pooler.asd +portable-threads http://beta.quicklisp.org/archive/portable-threads/2019-03-07/portable-threads-20190307-git.tgz 31127 f5f5baa0847cce4910b0394e4157797a 0c062c9c6213d2566b7ebbdf9b09a6cd1448b473 portable-threads-20190307-git portable-threads.asd +portableaserve http://beta.quicklisp.org/archive/portableaserve/2019-08-13/portableaserve-20190813-git.tgz 586259 4cd7af3fbd45693800a823aff55fa442 dfd074e79bfd1d98385f2066a82dacf8b3f98bea portableaserve-20190813-git acl-compat/acl-compat.asd aserve/aserve.asd aserve/htmlgen/htmlgen.asd aserve/webactions/webactions.asd +positional-lambda http://beta.quicklisp.org/archive/positional-lambda/2012-10-13/positional-lambda-2.0.tgz 7250 1099a5457455b7c570132556073aa21f 7433ee7798c5bdbd6c2edd9869f5173d93178727 positional-lambda-2.0 positional-lambda.asd +postmodern http://beta.quicklisp.org/archive/postmodern/2019-12-27/postmodern-20191227-git.tgz 313862 67b909de432e6414e7832eed18f9ad18 6e54d9d2661bc600ff83abe2ea4ca8023bbbd6b5 postmodern-20191227-git cl-postgres.asd postmodern.asd s-sql.asd simple-date.asd +postmodernity http://beta.quicklisp.org/archive/postmodernity/2017-01-24/postmodernity-20170124-git.tgz 3251 9109aace9c9a906732eb0259a15274e0 380ce87aaceedd6aa00a2d94da9b4dfaa16ddd6a postmodernity-20170124-git postmodernity.asd +postoffice http://beta.quicklisp.org/archive/postoffice/2012-09-09/postoffice-20120909-git.tgz 36931 d09dd023aac099aba49bd3a485179a26 0e6aa7efb53da555f44a8b7caefff3dce1e7eaf3 postoffice-20120909-git postoffice.asd +pounds http://beta.quicklisp.org/archive/pounds/2016-02-08/pounds-20160208-git.tgz 22888 7690a4a5aaca79a60bbb5c49ac9ef1b2 b60ec9318d7017a982e95eae42a2a5c6844da2b7 pounds-20160208-git pounds.asd +pp-toml http://beta.quicklisp.org/archive/pp-toml/2018-02-28/pp-toml-20180228-git.tgz 10851 28f316d8f8309b0a56372e49dc0e7022 ea6b34bacc0556f7a67416f22b6bb9751461d16c pp-toml-20180228-git pp-toml-tests.asd pp-toml.asd +ppath http://beta.quicklisp.org/archive/ppath/2018-07-11/ppath-20180711-git.tgz 26911 bcfdda2ff1161721b98c2c1233434429 b93079de943fb4f9cf8ef0a3c2517ce4292b8cdc ppath-20180711-git ppath-test.asd ppath.asd +practical-cl http://beta.quicklisp.org/archive/practical-cl/2018-04-30/practical-cl-20180430-git.tgz 241556 6d0d20024a11897b190d9680fb067d79 462ef8018d44d307ae58197ff03d049ad9a0eff1 practical-cl-20180430-git practicals/Chapter03/pcl-simple-database.asd practicals/Chapter08/pcl-macro-utilities.asd practicals/Chapter09/pcl-test-framework.asd practicals/Chapter15/pcl-pathnames.asd practicals/Chapter23/pcl-spam.asd practicals/Chapter24/pcl-binary-data.asd practicals/Chapter25/pcl-id3v2.asd practicals/Chapter26/pcl-url-function.asd practicals/Chapter27/pcl-mp3-database.asd practicals/Chapter28/pcl-shoutcast.asd practicals/Chapter29/pcl-mp3-browser.asd practicals/Chapter31/pcl-html.asd practicals/practical-cl.asd +prbs http://beta.quicklisp.org/archive/prbs/2018-02-28/prbs-20180228-git.tgz 16327 6baec1bb244961320d1a034a30fdb89a c09a9e8fe05cea4dcc3b4573b33c5f517e4c566b prbs-20180228-git doc/prbs-docs.asd prbs.asd +prepl http://beta.quicklisp.org/archive/prepl/2018-10-18/prepl-20181018-git.tgz 24716 1da918018645e9ea8c291d66f55b9907 47ca4168a7d798f8369c037012bcc88befa094df prepl-20181018-git prepl.asd +pretty-function http://beta.quicklisp.org/archive/pretty-function/2013-06-15/pretty-function-20130615-git.tgz 6248 7b6ad93307bc8c8ec585a8199e5e9cb6 3eaf9baa4d31922b3adf8b04005393e7d054b4aa pretty-function-20130615-git pretty-function.asd +print-html http://beta.quicklisp.org/archive/print-html/2018-10-18/print-html-20181018-git.tgz 2917 c9f8962deb792e5dd82c3971bfdf3daa ec23887721f684f8cd6170676d7141df9c3b381b print-html-20181018-git print-html.asd +print-licenses http://beta.quicklisp.org/archive/print-licenses/2018-10-18/print-licenses-20181018-git.tgz 3079 fc2c8770ec8bc28f154f31fc247d47cd 8f76b7b3c94c29d916a1b31e07cc90f70c4a3737 print-licenses-20181018-git print-licenses.asd +printv http://beta.quicklisp.org/archive/printv/2014-07-14/printv-20140714-git.tgz 16113 049108fb64993d704fba006a1b7ce300 36b5b3188f22a39dafaa030219ccaa21c3b35e41 printv-20140714-git printv.asd +priority-queue http://beta.quicklisp.org/archive/priority-queue/2015-07-09/priority-queue-20150709-git.tgz 2535 5196d0b355b72215228de49eeb0df745 65644f0e3eb8bd23af1ffe64f856bbd9c4d1ac15 priority-queue-20150709-git priority-queue.asd +proc-parse http://beta.quicklisp.org/archive/proc-parse/2019-08-13/proc-parse-20190813-git.tgz 8695 99bdce79943071267c6a877d8de246c5 18fff39d2a228aeb60547154bb09745d2a8769e1 proc-parse-20190813-git proc-parse-test.asd proc-parse.asd +projectured http://beta.quicklisp.org/archive/projectured/2017-12-27/projectured-quicklisp-c3a60e76-git.tgz 3573436 501022101c0211a267b608c4615fdce0 3e002e0bc323ffa8a6495bdd42883027516f69c6 projectured-quicklisp-c3a60e76-git projectured.document.asd projectured.editor.asd projectured.executable.asd projectured.projection.asd projectured.sdl.asd projectured.sdl.test.asd projectured.swank.asd projectured.test.asd +prometheus.cl http://beta.quicklisp.org/archive/prometheus.cl/2019-10-07/prometheus.cl-20191007-git.tgz 26087 29af5bcaefc2787441403352a99f560c deba5912ebde30c75ba9bf35a0d8a3f808a3bda5 prometheus.cl-20191007-git prometheus.asd prometheus.collectors.process.asd prometheus.collectors.process.test.asd prometheus.collectors.sbcl.asd prometheus.collectors.sbcl.test.asd prometheus.examples.asd prometheus.exposers.hunchentoot.asd prometheus.exposers.hunchentoot.test.asd prometheus.formats.text.asd prometheus.formats.text.test.asd prometheus.pushgateway.asd prometheus.pushgateway.test.asd prometheus.test.all.asd prometheus.test.asd prometheus.test.support.asd +protest http://beta.quicklisp.org/archive/protest/2019-05-21/protest-20190521-git.tgz 68083 5ec1333564b4e27e54ea26efe2ed24f5 79619cbaac2f4dd3001536f5a32568718ad8b86e protest-20190521-git protest.asd +protobuf http://beta.quicklisp.org/archive/protobuf/2018-12-10/protobuf-20181210-git.tgz 64058 cdb5d92efc02b32f45febe83a1406490 db202763305822fc9736c145bcf869501b942520 protobuf-20181210-git protobuf.asd varint/varint-test.asd varint/varint.asd +prove http://beta.quicklisp.org/archive/prove/2017-11-30/prove-20171130-git.tgz 878875 630df4367537f799570be40242f8ed52 67eba1cb93bce0eb45d6ff02396eec04a3f439a6 prove-20171130-git cl-test-more.asd prove-asdf.asd prove-test.asd prove.asd +pseudonyms http://beta.quicklisp.org/archive/pseudonyms/2016-08-25/pseudonyms-20160825-git.tgz 4072 bbbea2ee21987734173b3ccf9db62015 3e255b706b3ae8d812a1d245eebfbae97d3c0a1e pseudonyms-20160825-git pseudonyms.asd +psgraph http://beta.quicklisp.org/archive/psgraph/2010-10-06/psgraph-1.2.tgz 8448 df735b2f6c45e14ea18c16650ad8e90d 1cb75fe9886dd39bc7dbdd92c5e4a0b7e229218a psgraph-1.2 psgraph.asd +psychiq http://beta.quicklisp.org/archive/psychiq/2018-02-28/psychiq-20180228-git.tgz 17573 d07eb5632c0c15ddeff1fde9ae860fa8 40d40d7d1c06fc1c5add607cf4d12af0e89e54a6 psychiq-20180228-git psychiq-test.asd psychiq.asd +ptester http://beta.quicklisp.org/archive/ptester/2016-09-29/ptester-20160929-git.tgz 12713 938a4366b6608ae5c4a0be9da11a61d4 c32afa4c3f143967eddf4ace14f3e15429610f7f ptester-20160929-git ptester.asd +puri http://beta.quicklisp.org/archive/puri/2018-02-28/puri-20180228-git.tgz 30002 0c43ad5d862ed0d18ef84d8e2a42f67f 79053c86ebabe7ec8aab7ef175e13c9f3a9f0960 puri-20180228-git puri.asd +purl http://beta.quicklisp.org/archive/purl/2016-09-29/purl-20160929-git.tgz 32297 ab5d05fcdd2b09d143ebc4e332b4058b 7ce1d37badf30b8386747f26d330b0432d2be4a1 purl-20160929-git purl.asd +py-configparser http://beta.quicklisp.org/archive/py-configparser/2017-08-30/py-configparser-20170830-svn.tgz 8452 b6a9fc2a9c70760d6683cafe656f9e90 256cf7e56d08aa7021f8c0739f0f6a2912780c1c py-configparser-20170830-svn py-configparser.asd +py4cl http://beta.quicklisp.org/archive/py4cl/2019-11-30/py4cl-20191130-git.tgz 615487 9d06ef58a7c9dc8ea406f57cdc07fb57 e2d470b9e7b80f447aa298550d99e68da16bed8d py4cl-20191130-git py4cl.asd +pythonic-string-reader http://beta.quicklisp.org/archive/pythonic-string-reader/2018-07-11/pythonic-string-reader-20180711-git.tgz 3594 8156636895b1148fad6e7bcedeb6b556 084f20b11e986f7f186f5f8744ce0e77c2065129 pythonic-string-reader-20180711-git pythonic-string-reader.asd +pzmq http://beta.quicklisp.org/archive/pzmq/2019-07-10/pzmq-20190710-git.tgz 20467 89e152691e331d660cd8861f8fee643d d617f4420e5c3f81c388786fbc4253cf10a9c8cd pzmq-20190710-git pzmq.asd +qbase64 http://beta.quicklisp.org/archive/qbase64/2019-11-30/qbase64-20191130-git.tgz 15721 32b03aa1b3c5ca4c49f586b4028cae5e 310210d449dd016d0b141a2f36ee68fa4c3d3979 qbase64-20191130-git qbase64.asd +qbook http://beta.quicklisp.org/archive/qbook/2013-03-12/qbook-20130312-darcs.tgz 12971 6e1cc023c21340d4884da27ce1a1df39 872d11a845287195e88e3fd1d3045a0c471e5698 qbook-20130312-darcs qbook.asd +ql-checkout http://beta.quicklisp.org/archive/ql-checkout/2019-05-21/ql-checkout-20190521-git.tgz 4290 e2b0b29b3829a67a6f88aab932b68e5f c3cf51de9f3c2a6155d838e5645363be4c596dd4 ql-checkout-20190521-git ql-checkout.asd +qlot http://beta.quicklisp.org/archive/qlot/2019-12-27/qlot-20191227-git.tgz 32386 20e2f6505eae2ccf98fc80f8624828e5 dbf0702831311a6ccb28975e1b64bba820e9e06b qlot-20191227-git qlot.asd +qmynd http://beta.quicklisp.org/archive/qmynd/2019-07-10/qmynd-20190710-git.tgz 48872 c4a230ca44c5c037664979dfd48985a9 2a43db7117073bc830ad419da96a5e60cb1d2a89 qmynd-20190710-git qmynd.asd tests/qmynd-test.asd +qt-libs http://beta.quicklisp.org/archive/qt-libs/2019-11-30/qt-libs-20191130-git.tgz 52709 8f92957d0b15b9a594924e3900c83c84 5dd81781a20ddf0ec0420308a2a8739def91ab62 qt-libs-20191130-git qt-lib-generator.asd qt-libs.asd systems/commonqt.asd systems/phonon.asd systems/qimageblitz.asd systems/qsci.asd systems/qt3support.asd systems/qtcore.asd systems/qtdbus.asd systems/qtdeclarative.asd systems/qtgui.asd systems/qthelp.asd systems/qtnetwork.asd systems/qtopengl.asd systems/qtscript.asd systems/qtsql.asd systems/qtsvg.asd systems/qttest.asd systems/qtuitools.asd systems/qtwebkit.asd systems/qtxml.asd systems/qtxmlpatterns.asd systems/qwt.asd systems/smokebase.asd +qtools http://beta.quicklisp.org/archive/qtools/2019-11-30/qtools-20191130-git.tgz 196923 450ea3932742e538d88583e51183d4f3 3bfae2c01582df632f6c3698af7f7ceeae27c0bf qtools-20191130-git examples/evaluator/qtools-evaluator.asd examples/game/qtools-game.asd examples/helloworld/qtools-helloworld.asd examples/melody/qtools-melody.asd examples/opengl/qtools-opengl.asd examples/titter/qtools-titter.asd q+.asd qtools.asd +qtools-ui http://beta.quicklisp.org/archive/qtools-ui/2019-07-10/qtools-ui-20190710-git.tgz 65416 e01a0e6a18e80b5fdd7ce862021f39c7 051d22af68720a01751d34a65caf6f12b5a30bf8 qtools-ui-20190710-git qtools-ui-base.asd qtools-ui-bytearray.asd qtools-ui-cell.asd qtools-ui-color-history.asd qtools-ui-color-picker.asd qtools-ui-color-sliders.asd qtools-ui-color-triangle.asd qtools-ui-compass.asd qtools-ui-container.asd qtools-ui-debugger.asd qtools-ui-dialog.asd qtools-ui-dictionary.asd qtools-ui-drag-and-drop.asd qtools-ui-executable.asd qtools-ui-fixed-qtextedit.asd qtools-ui-flow-layout.asd qtools-ui-helpers.asd qtools-ui-imagetools.asd qtools-ui-keychord-editor.asd qtools-ui-layout.asd qtools-ui-listing.asd qtools-ui-notification.asd qtools-ui-options.asd qtools-ui-panels.asd qtools-ui-placeholder-text-edit.asd qtools-ui-plot.asd qtools-ui-progress-bar.asd qtools-ui-repl.asd qtools-ui-slider.asd qtools-ui-spellchecked-text-edit.asd qtools-ui-splitter.asd qtools-ui-svgtools.asd qtools-ui.asd +quadtree http://beta.quicklisp.org/archive/quadtree/2015-07-09/quadtree-20150709-git.tgz 3869 50ff5dc28ea35f3073946739537f039d 7961bb58a4a4e50008d5398fbb1ae71380e36248 quadtree-20150709-git quadtree-test.asd quadtree.asd +quantile-estimator.cl http://beta.quicklisp.org/archive/quantile-estimator.cl/2016-08-25/quantile-estimator.cl-20160825-git.tgz 3510 3a28f05e4466c714f712d31cc190992c 30796c8194de9b436e022a35aa5973db986fbd05 quantile-estimator.cl-20160825-git quantile-estimator.asd quantile-estimator.test.asd +quasiquote-2.0 http://beta.quicklisp.org/archive/quasiquote-2.0/2015-05-05/quasiquote-2.0-20150505-git.tgz 8956 7c557e0c10cf7608afa5a20e4a83c778 5f61d74c96a9a863f38ab56c08b5287187bd9ef7 quasiquote-2.0-20150505-git quasiquote-2.0.asd +queen.lisp http://beta.quicklisp.org/archive/queen.lisp/2016-09-29/queen.lisp-20160929-git.tgz 22553 2e7c68441e99d826cfb2c7cb9aa83766 f7988f650dfc560c49226e848de326b9d69da068 queen.lisp-20160929-git queen.asd +query-fs http://beta.quicklisp.org/archive/query-fs/2019-05-21/query-fs-20190521-git.tgz 270327 1108c91b69007c6ab35b42d70d4dd7a2 97649ef86497ee0f029b8e5522769937f86b75fe query-fs-20190521-git query-fs.asd +queues http://beta.quicklisp.org/archive/queues/2017-01-24/queues-20170124-git.tgz 8748 9b291db09b7385e12515697f1f918e27 3835c55c8a7010b35d4b2ef2e9ce54845ca564bc queues-20170124-git queues.asd queues.priority-cqueue.asd queues.priority-queue.asd queues.simple-cqueue.asd queues.simple-queue.asd +quickapp http://beta.quicklisp.org/archive/quickapp/2016-08-25/quickapp-20160825-git.tgz 7116 f7c00d1217d7b58f6f1f023668580891 2f4eff6c45eca224463eb0a32eacfd5e34513f0f quickapp-20160825-git quickapp.asd +quicklisp-slime-helper http://beta.quicklisp.org/archive/quicklisp-slime-helper/2015-07-09/quicklisp-slime-helper-20150709-git.tgz 2211 08a86772cfee1a9dc7b1d4a9bb7d371e 6abe815efe3a1b03cb485d4d95329188b1100fe5 quicklisp-slime-helper-20150709-git quicklisp-slime-helper.asd +quickproject http://beta.quicklisp.org/archive/quickproject/2019-12-27/quickproject-1.4.1.tgz 6777 1d582d9dc066e0904f716166e448ccb7 eefaabe524fb4113b7b785f623899e417bed7d72 quickproject-1.4.1 quickproject.asd +quicksearch http://beta.quicklisp.org/archive/quicksearch/2017-10-19/quicksearch-20171019-git.tgz 13482 b64e3f756d4edafe270499058b087c26 8984719946dc05f5ad03063265e1fbc1e9986516 quicksearch-20171019-git quicksearch.asd +quickutil http://beta.quicklisp.org/archive/quickutil/2019-07-10/quickutil-20190710-git.tgz 1508394 fe9b44ce90e259c90c346f4005c1d9da 34629c942ff3f21b3746c0e6573077538bc0884f quickutil-20190710-git quickutil-client/quickutil-client-management.asd quickutil-client/quickutil-client.asd quickutil-client/quickutil.asd quickutil-server/quickutil-server.asd quickutil-utilities/quickutil-utilities-test.asd quickutil-utilities/quickutil-utilities.asd +quilc http://beta.quicklisp.org/archive/quilc/2019-12-27/quilc-v1.15.2.tgz 1184464 0ed9400a58a1c6b489a16f0269977311 7df7aa30ceb984a9d40807fb9e90d4271b327f78 quilc-v1.15.2 boondoggle/boondoggle-tests.asd boondoggle/boondoggle.asd cl-quil-benchmarking.asd cl-quil-tests.asd cl-quil.asd quilc-tests.asd quilc.asd +quri http://beta.quicklisp.org/archive/quri/2019-11-30/quri-20191130-git.tgz 69725 4a3e8d2ebe459ea731738650c2c5bf56 58c4d571f700fceb9a67ea6dc52ae739a26aaacd quri-20191130-git quri-test.asd quri.asd +quux-hunchentoot http://beta.quicklisp.org/archive/quux-hunchentoot/2018-04-30/quux-hunchentoot-20180430-git.tgz 4627 e767f34d08e5da1a98cf99ce6cacc99a 852c396d028964a975034ecf372454edb86a7f7d quux-hunchentoot-20180430-git quux-hunchentoot.asd +quux-time http://beta.quicklisp.org/archive/quux-time/2015-04-07/quux-time-20150407-git.tgz 34282 f89bd972e19dd2fd5abae2a9e8b143e2 51b24561e194e32110bbb5a6e6be5d98c6daac8c quux-time-20150407-git quux-time.asd +qvm http://beta.quicklisp.org/archive/qvm/2019-12-27/qvm-v1.15.2.tgz 355327 3dba4c207c58efd91b2d4662f1b7500a d24bb7ab705921df3b81f9f15c5f93addeac9fab qvm-v1.15.2 qvm-app-ng-tests.asd qvm-app-ng.asd qvm-app-tests.asd qvm-app.asd qvm-benchmarks.asd qvm-examples.asd qvm-tests.asd qvm.asd +racer http://beta.quicklisp.org/archive/racer/2019-07-10/racer-20190710-git.tgz 28462787 ecc163e4033836e93aaeb3990052fe3a f27637cb6f310019ad45377016535f15b1cbffdf racer-20190710-git clients/lracer/lracer.asd racer.asd +random http://beta.quicklisp.org/archive/random/2019-10-07/random-20191007-git.tgz 4620 13a609118dd74e217fafd018875b8366 9c3214946a660c5edc558c2f592ff70994c3df65 random-20191007-git acm-random-test.asd acm-random.asd random-test.asd random.asd +random-access-lists http://beta.quicklisp.org/archive/random-access-lists/2012-02-08/random-access-lists-20120208-git.tgz 4903 36e5b00c2556ffda4cc2d6297471d053 7f2fe5a0f6497a98b538bfed7fa0dea7c3c3d8cc random-access-lists-20120208-git random-access-lists.asd +random-sample http://beta.quicklisp.org/archive/random-sample/2018-07-11/random-sample-20180711-git.tgz 3416 c849823d61c7dc3c8ef9d4cea595391c 177806586fbe0d70144af9ee41144dc63ee687cf random-sample-20180711-git random-sample.asd +random-state http://beta.quicklisp.org/archive/random-state/2019-07-10/random-state-20190710-git.tgz 10759 c958cd6015c6ed0b3cd44283ed68dc08 cadf3310ad0f61167972ccb5b5ce71020a278e5d random-state-20190710-git random-state-viewer.asd random-state.asd +rate-monotonic http://beta.quicklisp.org/archive/rate-monotonic/2017-01-24/rate-monotonic-20170124-git.tgz 16931 40d28ad246c2fa1d84a1fe68fac0c74b c6198a314738cd44a2b9fdcf62037591b6d86d87 rate-monotonic-20170124-git rate-monotonic.asd rate-monotonic.examples.asd +ratify http://beta.quicklisp.org/archive/ratify/2019-10-07/ratify-20191007-git.tgz 30103 bb3371f343c1cfd75b6cc4ea6f2e7cc1 c4e33d368e883efdb66356afd4cffc0c6593bedf ratify-20191007-git ratify.asd +rcl http://beta.quicklisp.org/archive/rcl/2016-08-25/rcl-20160825-http.tgz 32780 c270ce4a4b2dcc12ac7c793c26a583d1 5e7494f2d3ddd826afc6f3211228e8acadecf123 rcl-20160825-http rcl.asd +re http://beta.quicklisp.org/archive/re/2019-10-07/re-20191007-git.tgz 8683 2dd52d733bdbcd7df45350dc0b9b143e babd0e0648cbeeb36f9d956f5fee45af694b9813 re-20191007-git re.asd +read-csv http://beta.quicklisp.org/archive/read-csv/2018-10-18/read-csv-20181018-git.tgz 4924 ef21abc13722ff1ede9f72951bd725af ac27005e51ff658b0b28665fefc260b812032802 read-csv-20181018-git read-csv.asd +read-number http://beta.quicklisp.org/archive/read-number/2019-05-21/read-number-20190521-git.tgz 7986 928e06ed46fb67f216f7299c8c1dfdf5 962d8a2d2f14748ab3e8d28cbd4131c2bcfdaf1d read-number-20190521-git read-number.asd +reader http://beta.quicklisp.org/archive/reader/2019-12-27/reader-20191227-git.tgz 5859 a1317a75a040760375d7ba7b2ab30a90 7335959482977c87f70843a4bd6e65a657299d32 reader-20191227-git reader-test.asd reader.asd +reader-interception http://beta.quicklisp.org/archive/reader-interception/2015-06-08/reader-interception-20150608-git.tgz 5162 8bb17a9cb708c842cb9cac112bd2d7b7 b8319c2a038be121cf1cc5ac493e876880d52ea2 reader-interception-20150608-git reader-interception-test.asd reader-interception.asd +rectangle-packing http://beta.quicklisp.org/archive/rectangle-packing/2013-06-15/rectangle-packing-20130615-git.tgz 16507 98a4a3e3a1daf65b56475e1f850ca0a7 08ed9778cc20bb058a54e1db28fbbdeb75c929ba rectangle-packing-20130615-git rectangle-packing.asd +recur http://beta.quicklisp.org/archive/recur/2019-03-07/recur-20190307-hg.tgz 1485 c29fa990323309c17e98cc7eadd2b31d edc298a910d5c737937aed72f66f7d484a55485a recur-20190307-hg recur.asd +recursive-regex http://beta.quicklisp.org/archive/recursive-regex/2012-04-07/recursive-regex-20120407-git.tgz 11763 fefa07fe68a4a99338900a7be78129b3 4a09f21c6e6daf510dc1570431ed4ddd40716815 recursive-regex-20120407-git recursive-regex.asd +recursive-restart http://beta.quicklisp.org/archive/recursive-restart/2016-10-31/recursive-restart-20161031-git.tgz 3054 39d5c3ca334229dd5f5111a6f993d8a0 cf91a8a01feb4efbf8ce3d7cd74e34b224a90faf recursive-restart-20161031-git recursive-restart.asd +redirect-stream http://beta.quicklisp.org/archive/redirect-stream/2019-07-10/redirect-stream-20190710-git.tgz 3914 3dbcdaad096f9ba1e308a351fce12744 14dcc7ff3bd776e2b391fa7f74a17b089b975c17 redirect-stream-20190710-git redirect-stream.asd +regex http://beta.quicklisp.org/archive/regex/2012-09-09/regex-20120909-git.tgz 30204 545d10011ea7d33cea0dfcb238acf94b 9ab918df7063e4aac22c3cb0a4776529747cf080 regex-20120909-git regex.asd +regular-type-expression http://beta.quicklisp.org/archive/regular-type-expression/2019-07-10/regular-type-expression-export-to-quicklisp-6a781b1f-git.tgz 2650721 c8f2228509c4b6f33df8a528759963a0 1eda28066cf0b186c1dd282376169b833a1e258b regular-type-expression-export-to-quicklisp-6a781b1f-git 2d-array/2d-array-test.asd 2d-array/2d-array.asd adjuvant/adjuvant-test.asd adjuvant/adjuvant.asd cl-robdd/cl-robdd-analysis-test.asd cl-robdd/cl-robdd-analysis.asd cl-robdd/cl-robdd-test.asd cl-robdd/cl-robdd.asd dispatch/dispatch-test.asd dispatch/dispatch.asd lisp-types/lisp-types-analysis.asd lisp-types/lisp-types-test.asd lisp-types/lisp-types.asd ndfa/ndfa-test.asd ndfa/ndfa.asd research.asd rte-regexp/rte-regexp-test.asd rte-regexp/rte-regexp.asd rte/rte-test.asd rte/rte.asd scrutiny/scrutiny-test.asd scrutiny/scrutiny.asd +remote-js http://beta.quicklisp.org/archive/remote-js/2019-07-10/remote-js-20190710-git.tgz 4434 fcc3b2e4201c1ad11ec8575a98bce39e 0a623b75ed970fe8e5f9d5572c4bf1bccbcf3ec5 remote-js-20190710-git remote-js-test.asd remote-js.asd +repl-utilities http://beta.quicklisp.org/archive/repl-utilities/2015-06-08/repl-utilities-20150608-git.tgz 11278 2299800cecc045af21fd3ac692138972 7a3098268b3a68781d537beba29d8cea39b56c9c repl-utilities-20150608-git repl-utilities.asd +replic http://beta.quicklisp.org/archive/replic/2019-11-30/replic-20191130-git.tgz 18002 da5c97326b1ccf7fce0704d2d29093f7 a8a44bea8976745fb2903a1e6deaf933495fdd41 replic-20191130-git replic-test.asd replic.asd +restas http://beta.quicklisp.org/archive/restas/2019-10-08/restas-20191008-git.tgz 182787 ceec9a0482460e2ad32446d43623480b cec4ae81730d0f741cdf3a436750a564de2c9d31 restas-20191008-git docs/restas-doc.asd restas.asd +restas-directory-publisher http://beta.quicklisp.org/archive/restas-directory-publisher/2013-01-28/restas-directory-publisher-20130128-git.tgz 13313 ac714dd7b907eebaa428fc411fce7434 112f0d8f6aa05b4e4a3fbae8131c1dd20f05a1cf restas-directory-publisher-20130128-git restas-directory-publisher.asd +restas.file-publisher http://beta.quicklisp.org/archive/restas.file-publisher/2012-01-07/restas.file-publisher-20120107-git.tgz 1176 74b3636315653b08c83747b8a45796d5 48bd0eb451bc218675ba47a64240d261a8cd5d4f restas.file-publisher-20120107-git restas.file-publisher.asd +restful http://beta.quicklisp.org/archive/restful/2015-06-08/restful-20150608-git.tgz 12311 fb8e34eba9a82fcd8351eb16dd908176 aebeed541ff77427483632265e4f0dda44c62669 restful-20150608-git restful-test.asd restful.asd +restricted-functions http://beta.quicklisp.org/archive/restricted-functions/2019-05-21/restricted-functions-20190521-git.tgz 6700 0ae3b25b8fa92ea9d625cae324ec445f 7e47bc6d54ff68ec0d0e65f34c635a3b6f9d9d10 restricted-functions-20190521-git code/restricted-functions.asd +retrospectiff http://beta.quicklisp.org/archive/retrospectiff/2017-10-19/retrospectiff-20171019-git.tgz 1460413 44c765984cd9dd0ecbb1bec8c78a3301 c9dce8ca0e8f0b738508d592b3c73d75e7ee4558 retrospectiff-20171019-git retrospectiff.asd +reversi http://beta.quicklisp.org/archive/reversi/2015-09-23/reversi-20150923-git.tgz 99958 b67728e66d479acb1a77983793092508 d6e3723c7a48943f49cff79f129812c76304da66 reversi-20150923-git reversi.asd +rfc2109 http://beta.quicklisp.org/archive/rfc2109/2015-12-18/rfc2109-20151218-darcs.tgz 29102 ca039ac430baaed87f08a1a01e4cfe91 8cfa85913f22053a81c691d8eb8309aa6e9eeeb6 rfc2109-20151218-darcs rfc2109.asd +rfc2388 http://beta.quicklisp.org/archive/rfc2388/2018-08-31/rfc2388-20180831-git.tgz 12522 f57e3c588e5e08210516260e67d69226 b9fce4ee84e60426fc9ef11f1847235b13dd256e rfc2388-20180831-git rfc2388.asd +rfc2388-binary http://beta.quicklisp.org/archive/rfc2388-binary/2017-01-24/rfc2388-binary-20170124-darcs.tgz 98374 0f0e4796ce5b4c0d30aee6f87ecf13d5 4ea6b34d653445314332dce88e4792b8332004f0 rfc2388-binary-20170124-darcs rfc2388-binary.asd +rfc3339-timestamp http://beta.quicklisp.org/archive/rfc3339-timestamp/2015-06-08/rfc3339-timestamp-20150608-git.tgz 5146 91a8159c603749a20e58847d0e4e78b2 57056b5fc5efb1d046f18e23eebf52d3b85fc1f0 rfc3339-timestamp-20150608-git rfc3339-timestamp-test.asd rfc3339-timestamp.asd +rlc http://beta.quicklisp.org/archive/rlc/2015-09-23/rlc-20150923-git.tgz 3997 b26fd533287f1033a7a2885a780c2318 e9d56b4078c5672498325308ae2898ab9dd9b797 rlc-20150923-git rlc.asd +roan http://beta.quicklisp.org/archive/roan/2019-11-30/roan-20191130-git.tgz 1135925 83b94f712f002f551ea85247bc11c71f b4f7339ccb26e26b3bea9bbc05634933131b2772 roan-20191130-git roan.asd +rock http://beta.quicklisp.org/archive/rock/2015-06-08/rock-20150608-git.tgz 9855 e54b64ba4d201d559355eb6bdb8e9d34 fcbcdd37d9cf8de9ae4c8b392ab7de632f58bdd9 rock-20150608-git rock-test.asd rock-web.asd rock.asd +romreader http://beta.quicklisp.org/archive/romreader/2014-07-13/romreader-20140713-git.tgz 6533 1e7c5f085d2495bd7a131b479b85ca8b 4133137ffba648f72739f0faa56b79b8bb48ec3a romreader-20140713-git romreader.asd +rove http://beta.quicklisp.org/archive/rove/2019-10-07/rove-20191007-git.tgz 14893 7ce5d3b0b423f8b68665bbcc51cf18a1 543f9a7bbc581ed2403309a944ee3b3fc28a2e1d rove-20191007-git rove.asd +rpc4cl http://beta.quicklisp.org/archive/rpc4cl/2015-06-08/rpc4cl-20150608-git.tgz 13071 75c4f8ed74f2688decbc26eb3c5094c8 a56e162d114af1ee168b08db47fe208db5fc7603 rpc4cl-20150608-git rpc4cl-test.asd rpc4cl.asd +rpcq http://beta.quicklisp.org/archive/rpcq/2019-12-27/rpcq-v3.0.0.tgz 79254 7e7cd7ebfe29c600984b967ad255fdba 1e59f7652c2a6edf42e087784c3577745dce910c rpcq-v3.0.0 rpcq-tests.asd rpcq.asd +rpm http://beta.quicklisp.org/archive/rpm/2016-04-21/rpm-20160421-git.tgz 4835 3c60f17576cb2c22554fff9b0eec2796 15eb5b24e92715d7e25605acd314702178122486 rpm-20160421-git rpm.asd +rt http://beta.quicklisp.org/archive/rt/2010-10-06/rt-20101006-git.tgz 10676 94a56c473399572ca835ac91c77c04e5 80643f045a1ff7313d55db64a3f6787236f68eff rt-20101006-git rt.asd +rt-events http://beta.quicklisp.org/archive/rt-events/2016-03-18/rt-events-20160318-git.tgz 5518 c9c0de2cafffd8319bc6f8a9ee9c4908 86aabf4057d784d88d938890ca0273ff1dba31f6 rt-events-20160318-git rt-events.asd rt-events.examples.asd +rtg-math http://beta.quicklisp.org/archive/rtg-math/2019-10-07/rtg-math-release-quicklisp-29fc5b3d-git.tgz 94423 fefa73c6923964666ecc8a8c382df718 2ce1482195edd95a831dd09c37f959277cb1a2e5 rtg-math-release-quicklisp-29fc5b3d-git rtg-math.asd rtg-math.vari.asd +rucksack http://beta.quicklisp.org/archive/rucksack/2015-06-08/rucksack-20150608-git.tgz 111832 e968c9e90632cbba892dae1e2833efe3 3e3ec1762970a3ad7df8d87afdae2bd80ab27af0 rucksack-20150608-git rucksack.asd tests/rucksack-test.asd +rutils http://beta.quicklisp.org/archive/rutils/2019-11-30/rutils-20191130-git.tgz 170325 11551d0709dbeeee44c4aa377e6471f2 3ce11df6da71853198327e4a0c524d56f8bdea54 rutils-20191130-git rutils-test.asd rutils.asd rutilsx.asd +ryeboy http://beta.quicklisp.org/archive/ryeboy/2015-03-02/ryeboy-20150302-git.tgz 9381 509436a25df82c2408d68db308650957 49bf72d638ae2a5485294e753cae73eadc9a1323 ryeboy-20150302-git ryeboy.asd +s-base64 http://beta.quicklisp.org/archive/s-base64/2013-01-28/s-base64-20130128-git.tgz 7033 9c4220053ea4b18fca7a49f29aae0ee1 70c7fc4ed0762db40bc6e0e71f36f358a2c6cb9a s-base64-20130128-git s-base64.asd +s-dot2 http://beta.quicklisp.org/archive/s-dot2/2018-10-18/s-dot2-20181018-git.tgz 6015 2f0d0948c7ab66c0fb75a761f113b9e9 bb3d07b3bc6c9803b97c65aa3dbc1f69cc187299 s-dot2-20181018-git s-dot2.asd +s-http-client http://beta.quicklisp.org/archive/s-http-client/2015-10-31/s-http-client-20151031-git.tgz 10204 be5c11bdc2c80fcc100230c352476d92 3ce9ade130aaf5b304573d6c73c8f47706030341 s-http-client-20151031-git s-http-client.asd +s-http-server http://beta.quicklisp.org/archive/s-http-server/2013-01-28/s-http-server-20130128-git.tgz 25877 c394b2543bbc48895794fe332adba23d f3ac20bd1203ab639ae397746c9904c722a63f88 s-http-server-20130128-git s-http-server.asd +s-protobuf http://beta.quicklisp.org/archive/s-protobuf/2015-12-18/s-protobuf-20151218-git.tgz 22278 99af6c044952679ad08513f945c59c4f 2835943d57cac223243d9638260fbcc252321481 s-protobuf-20151218-git src/s-protobuf.asd +s-sysdeps http://beta.quicklisp.org/archive/s-sysdeps/2013-01-28/s-sysdeps-20130128-git.tgz 6002 2fe61fadafd62ef9597e17b4783889ef 455bdf64e9ce28f99bda8dc20202cbcdc8015424 s-sysdeps-20130128-git s-sysdeps.asd +s-utils http://beta.quicklisp.org/archive/s-utils/2013-01-28/s-utils-20130128-git.tgz 5511 50d0bada77503606b9ec7dc1b4318a71 0f8314edbd003064faf03c56ee957ed6690927cd s-utils-20130128-git s-utils.asd +s-xml http://beta.quicklisp.org/archive/s-xml/2015-06-08/s-xml-20150608-git.tgz 21248 9c31c80f0661777c493fab683f776716 03cb87aacf1c44877a76572510df60c563727125 s-xml-20150608-git s-xml.asd +s-xml-rpc http://beta.quicklisp.org/archive/s-xml-rpc/2019-05-21/s-xml-rpc-20190521-git.tgz 23981 33c268048222002af4d6232d71ee7222 d8b595ab60be528be3848eaf64d3b9a77fc62319 s-xml-rpc-20190521-git s-xml-rpc.asd +safe-queue http://beta.quicklisp.org/archive/safe-queue/2016-04-21/safe-queue-20160421-git.tgz 3667 211b677bc15a7ac3ce6e88ee7f89d970 13efd7ab3e541ba00a86cfc774fffa702f9ac3d9 safe-queue-20160421-git safe-queue.asd +safe-read http://beta.quicklisp.org/archive/safe-read/2018-10-18/safe-read-20181018-git.tgz 5487 54bd985ab5f3ad1d30a2a53f1da03410 c93d1baf7f8499a0383f8ae38a5a01bb36542801 safe-read-20181018-git safe-read.asd +safety-params http://beta.quicklisp.org/archive/safety-params/2019-02-02/safety-params-20190202-git.tgz 7110 44bdeb52d69878bf67ecf413613538cb 3380fbb899e4130dbc98475d1803f733245e54e5 safety-params-20190202-git safety-params.asd +salza2 http://beta.quicklisp.org/archive/salza2/2013-07-20/salza2-2.0.9.tgz 15525 e62383de435081c0f1f888ec363bb32c 7f2eecaa9582bbedf7278fcf77bf46c9c5474f5b salza2-2.0.9 salza2.asd +sandalphon.lambda-list http://beta.quicklisp.org/archive/sandalphon.lambda-list/2018-07-11/sandalphon.lambda-list-20180711-git.tgz 11120 6b75d6bcd35d610abb1278547266246f 49223fc82d7af2364aba90b495442be3153b4494 sandalphon.lambda-list-20180711-git sandalphon.lambda-list.asd +sanity-clause http://beta.quicklisp.org/archive/sanity-clause/2019-11-30/sanity-clause-20191130-git.tgz 34489 5fadf7e610de59840d1208f80d767efd 1d64f5903d202b95dce700a1d4867e5b48217d2d sanity-clause-20191130-git sanity-clause.asd +sapaclisp http://beta.quicklisp.org/archive/sapaclisp/2012-05-20/sapaclisp-1.0a.tgz 141501 5a9d213d0063de0cc1ef9fd3aea811ca 2f3bbe44b16bc0bdc6c29be6f00312e9372f61cb sapaclisp-1.0a sapaclisp.asd +sb-cga http://beta.quicklisp.org/archive/sb-cga/2017-12-27/sb-cga-20171227-git.tgz 34033 46f69ae11e29b16a8da92965bddeb0e3 e59084d49f3a915c0cde0793f74ab68073ac948e sb-cga-20171227-git sb-cga.asd +sb-fastcgi http://beta.quicklisp.org/archive/sb-fastcgi/2019-12-27/sb-fastcgi-20191227-git.tgz 3835 b2f177181308a88dd65909d60e85d755 bbc4710baadd2d3bf61cac73fbefba83df0e5990 sb-fastcgi-20191227-git sb-fastcgi.asd +sb-vector-io http://beta.quicklisp.org/archive/sb-vector-io/2011-08-29/sb-vector-io-20110829-git.tgz 5263 a57684e11ed481a7c4cf7f2623942e49 15faae433ceb327a16f5bcf29cdcd7728a5c1aca sb-vector-io-20110829-git sb-vector-io.asd +sc-extensions http://beta.quicklisp.org/archive/sc-extensions/2019-11-30/sc-extensions-20191130-git.tgz 8141 b929525a11725794c55b86dfdb6798c7 14a000be3e6b719a491ff9ce2ee376cdb2d33538 sc-extensions-20191130-git sc-extensions.asd +scalpl http://beta.quicklisp.org/archive/scalpl/2019-12-27/scalpl-20191227-git.tgz 50929 0187001e6d53616d588fa0dc385c6e83 eee08d1d92f743f59496f96201c2155bf6c4fd5e scalpl-20191227-git scalpl.asd +screamer http://beta.quicklisp.org/archive/screamer/2019-07-10/screamer-20190710-git.tgz 953872 6eb822a63c82ed6007f2c1f662005f1f 15d7e15f78b9d23db8da9efa3ae260a17a3038e4 screamer-20190710-git screamer-tests.asd screamer.asd +scriba http://beta.quicklisp.org/archive/scriba/2015-12-18/scriba-20151218-git.tgz 33936 867dbaf3a2660a23f29d27e5633abd94 4e79592dfc97bb7997c32696439706dabe16d4d5 scriba-20151218-git scriba-test.asd scriba.asd +scribble http://beta.quicklisp.org/archive/scribble/2016-06-28/scribble-20160628-git.tgz 15810 976a908f6bbe7ac8516a4916dd6cee20 e1e46a668bfda1cb2848b489176ea6d82d5800d7 scribble-20160628-git scribble.asd +scriptl http://beta.quicklisp.org/archive/scriptl/2018-02-28/scriptl-20180228-git.tgz 125271 37927d71784ccef1cdeb309272416d0a 3f940ab4a12dcbb23f78f2a3d8b33f3aaf454793 scriptl-20180228-git scriptl-examples.asd scriptl-util.asd scriptl.asd +sdl2-game-controller-db http://beta.quicklisp.org/archive/sdl2-game-controller-db/2018-02-28/sdl2-game-controller-db-release-quicklisp-335d2b68-git.tgz 7352 ad3ab5458419a5a259313807c8e0b181 770ccc1def893343b1d3ed5ad511b3537b5c7b02 sdl2-game-controller-db-release-quicklisp-335d2b68-git sdl2-game-controller-db.asd +sdl2kit http://beta.quicklisp.org/archive/sdl2kit/2017-11-30/sdl2kit-20171130-git.tgz 11804 906f93a606d1ff2ed8ed613a3fb2d553 0e077fd40e966e93f505a90a9027fe784dc8aaaf sdl2kit-20171130-git sdl2kit-examples.asd sdl2kit.asd +sealable-metaobjects http://beta.quicklisp.org/archive/sealable-metaobjects/2019-12-27/sealable-metaobjects-20191227-git.tgz 11693 89191336d30215431ee3c916974e5127 1acc25792468db5251863b324ac36e22628791ef sealable-metaobjects-20191227-git code/sealable-metaobjects.asd test-suite/sealable-metaobjects-test-suite.asd +secret-values http://beta.quicklisp.org/archive/secret-values/2017-10-19/secret-values-20171019-git.tgz 2590 02ce6929d8923975f7368470730be760 516f54287f35b7c90e82f64cf769502fd47ef8e2 secret-values-20171019-git secret-values.asd +secure-random http://beta.quicklisp.org/archive/secure-random/2016-02-08/secure-random-20160208-git.tgz 2912 ee57beb30d51da8b3969c27ca52fd0d7 5f5b15e224164c1658ed62532759761ba9c26ccc secure-random-20160208-git secure-random.asd +sel http://beta.quicklisp.org/archive/sel/2019-12-27/sel-20191227-git.tgz 1265692 843828381be7aa65b2ae07d9e5e78147 a2ec44c65fd2a5addb6656feb5b059d4568c5934 sel-20191227-git software-evolution-library.asd +select http://beta.quicklisp.org/archive/select/2019-10-07/select-20191007-git.tgz 271138 d5e63be051777d39e0d74791ab88e078 384cb66fd750ce8ae601f19502ab299dac85abbf select-20191007-git select.asd +semantic-spinneret http://beta.quicklisp.org/archive/semantic-spinneret/2017-08-30/semantic-spinneret-20170830-git.tgz 2079 3cdc958d8000f1e26f683aa30f0950cb afeea07a5ef5c41d6d90ba0c7b7dfbb9d9569e15 semantic-spinneret-20170830-git semantic-spinneret.asd +sequence-iterators http://beta.quicklisp.org/archive/sequence-iterators/2013-08-13/sequence-iterators-20130813-darcs.tgz 34899 a6b61a5e9026a03c4978f3721bb17632 7cab8da70f985eb5165aa2145e937a04c605e23c sequence-iterators-20130813-darcs extensible-sequences/extensible-sequences.asd sequence-iterators.asd +serapeum http://beta.quicklisp.org/archive/serapeum/2019-12-27/serapeum-20191227-git.tgz 188510 dabf40eb6c6af7509da66450790cbf4e c5c3041a39533725c8c1b0278dea67dbdddba8e9 serapeum-20191227-git serapeum.asd +serializable-object http://beta.quicklisp.org/archive/serializable-object/2019-12-27/serializable-object-20191227-git.tgz 22152 5035427309018750274ef7767cf2b2e7 bbdcb991e44ad56e18b3fc8e4873539b731a937e serializable-object-20191227-git serializable-object.asd serializable-object.test.asd +series http://beta.quicklisp.org/archive/series/2013-11-11/series-20131111-git.tgz 151865 396c160a736ad38829dce1db13a75bcc 6bf27684cdd5fae7ab739d954a72bfde7154bc67 series-20131111-git series.asd +session-token http://beta.quicklisp.org/archive/session-token/2014-11-06/session-token-20141106-git.tgz 3020 5e7727a5a92a8ca9b70304f47b6b52b6 713d1d511e522fe2bd1732e03b088ff062852e8f session-token-20141106-git session-token.asd +sexml http://beta.quicklisp.org/archive/sexml/2014-07-13/sexml-20140713-git.tgz 27508 f71d4ee8da885671be8b779266cd865a f4f482c546f955b9eb4f8c200cc5947528ae6b7e sexml-20140713-git contrib/sexml-objects/sexml-objects.asd sexml.asd +sha1 http://beta.quicklisp.org/archive/sha1/2018-10-18/sha1-20181018-git.tgz 3198 1e49b3c92abf33a84a4e7a18fafc6ec7 96078e0ee02b1811391c36d46356856606156c0a sha1-20181018-git sha1.asd +sha3 http://beta.quicklisp.org/archive/sha3/2018-02-28/sha3-20180228-git.tgz 17156 26078e9dcb90cc6d6e3174880c4514cb 6ba93591c151ee6b04f0aadfc5f93292ef238527 sha3-20180228-git sha3.asd +shadchen http://beta.quicklisp.org/archive/shadchen/2013-10-03/shadchen-20131003-git.tgz 11298 159f11f77ef2c1c2279e502213a97d43 751e9e27c0d249076ae7a14c275d22f5007c9f69 shadchen-20131003-git shadchen.asd +shadow http://beta.quicklisp.org/archive/shadow/2019-12-27/shadow-20191227-git.tgz 15478 bec5fb5889cfc6d91d0095c61a994457 200b818cf6aae5a86a4a7fe1d3d2e651eca11e63 shadow-20191227-git shadow.asd +sheeple http://beta.quicklisp.org/archive/sheeple/2015-03-02/sheeple-20150302-git.tgz 623383 3077aa64386b96c2aae8b42ea750503d b8c84650eb413b8c6187e5a8d0b8cb0de4217d0e sheeple-20150302-git sheeple.asd +shellpool http://beta.quicklisp.org/archive/shellpool/2015-05-05/shellpool-20150505-git.tgz 26021 5f8713d9dcfd08d3db2bce7ef3f6ed44 1d0065a166713f7e02493d3acdaf735cfcbd09cd shellpool-20150505-git shellpool.asd +shelly http://beta.quicklisp.org/archive/shelly/2014-11-06/shelly-20141106-git.tgz 18127 824938aaaac93602dc927a9734aa1581 2dc9eff9949e91277a0db6376a431b6992681d4b shelly-20141106-git shelly-test.asd shelly.asd +shorty http://beta.quicklisp.org/archive/shorty/2018-02-28/shorty-20180228-git.tgz 4280 4141a8fd8c22806935284b312bdbae6f 38a21fee651b92c319e4d00215d84f01138557fc shorty-20180228-git shorty.asd +should-test http://beta.quicklisp.org/archive/should-test/2019-10-07/should-test-20191007-git.tgz 7618 f27c9a9c25be4f67204f7c3dccde755f 32aeafca31add71fa61077717e5e5e932033f85f should-test-20191007-git should-test.asd +shuffletron http://beta.quicklisp.org/archive/shuffletron/2018-10-18/shuffletron-20181018-git.tgz 125912 ffa1e84964f41af31bbb853d0b0776a9 7a8f2aaf66cd8978094dacd5e92242dc859deca7 shuffletron-20181018-git shuffletron.asd +simple-actors http://beta.quicklisp.org/archive/simple-actors/2019-07-10/simple-actors-20190710-git.tgz 4857 449f12288ea6f0bb441bc93936283bb1 3403542e34ca9033faf5935ce4c894e1d3385775 simple-actors-20190710-git simple-actors.asd +simple-config http://beta.quicklisp.org/archive/simple-config/2019-12-27/simple-config-20191227-git.tgz 2421 581baa322bb5c6924fb37bcb391ca719 ab402780a2ba1ee230bacaf4fa3d0a73127ad2c0 simple-config-20191227-git simple-config-test.asd simple-config.asd +simple-currency http://beta.quicklisp.org/archive/simple-currency/2017-11-30/simple-currency-20171130-git.tgz 12557 71ea0f64c63b4287fc56ece336e08ef9 aa40c0d344e0c9c4b20583d8df86887e55081b2b simple-currency-20171130-git simple-currency.asd +simple-date-time http://beta.quicklisp.org/archive/simple-date-time/2016-04-21/simple-date-time-20160421-git.tgz 5688 a5b1e4af539646723dafacbc8cf732a0 74ea55a0c7d77d7b967b3ad94f9f67137c9cd01e simple-date-time-20160421-git simple-date-time.asd +simple-finalizer http://beta.quicklisp.org/archive/simple-finalizer/2010-10-06/simple-finalizer-20101006-git.tgz 3415 fcc7c3966af77de524e6f24bb9dc1c94 6ac4c1cb19186e78e445885f86da20ba99d868bb simple-finalizer-20101006-git simple-finalizer.asd +simple-flow-dispatcher http://beta.quicklisp.org/archive/simple-flow-dispatcher/2018-07-11/simple-flow-dispatcher-stable-a7b66fbc-git.tgz 2472 04fa311af0ae1be7e1b9c6fc3eaa0630 f398b15e606b6fdb4480b5b010365ba0520da616 simple-flow-dispatcher-stable-a7b66fbc-git simple-flow-dispatcher.asd +simple-inferiors http://beta.quicklisp.org/archive/simple-inferiors/2019-07-10/simple-inferiors-20190710-git.tgz 9654 e3194d746e03dd1dbf8d0f185a7cb457 7f287a3f922a929483e1e03f5273deefd0701603 simple-inferiors-20190710-git simple-inferiors.asd +simple-logger http://beta.quicklisp.org/archive/simple-logger/2018-02-28/simple-logger-20180228-git.tgz 2800 bae2008abb490d9ab93474676dbe944a a00039c9467b7f09977bbe9a0d500a1b8cf5e371 simple-logger-20180228-git simple-logger.asd +simple-parallel-tasks http://beta.quicklisp.org/archive/simple-parallel-tasks/2019-11-30/simple-parallel-tasks-20191130-git.tgz 14217 a7d4af2253c91d4dca663e14c99e918d 18111bf3848866bd1cc5276388526012f3e0995d simple-parallel-tasks-20191130-git simple-parallel-tasks-tests.asd simple-parallel-tasks.asd +simple-rgb http://beta.quicklisp.org/archive/simple-rgb/2019-05-21/simple-rgb-20190521-git.tgz 5464 8afe42c3bb2bec023cfae77a8153c668 2573e45d315e8fe7a0b30f90bd5bb9624044cdb5 simple-rgb-20190521-git simple-rgb.asd +simple-routes http://beta.quicklisp.org/archive/simple-routes/2018-02-28/simple-routes-20180228-git.tgz 6209 95b881171c381674a275da21692442f2 06b1a640d86490ed1e346b2a37306e4a8c7a66f2 simple-routes-20180228-git simple-routes.asd +simple-tasks http://beta.quicklisp.org/archive/simple-tasks/2019-07-10/simple-tasks-20190710-git.tgz 12567 8e88a9a762bc8691f92217d256baa55e 3fdcc5d1debf45d1480f31ce5f7de206ff6aeb87 simple-tasks-20190710-git simple-tasks.asd +simplet http://beta.quicklisp.org/archive/simplet/2019-12-27/simplet-20191227-git.tgz 16303 9fa3343c7a0b9f6f7f43d8b4ed706d98 bf0ee7b1a8770cc028a66ffd6da9770ab6492a3a simplet-20191227-git simplet-asdf.asd simplet.asd +simplified-types http://beta.quicklisp.org/archive/simplified-types/2019-08-13/simplified-types-20190813-git.tgz 6647 c3666e2faf2aed0ec040912db0a91285 c89aa23f3c54e114a3c8de9f3b8254d128bdf7f3 simplified-types-20190813-git code/simplified-types.asd test-suite/simplified-types-test-suite.asd +simpsamp http://beta.quicklisp.org/archive/simpsamp/2010-10-06/simpsamp-0.1.tgz 44485 afd8bdfae4b4f0924839753086bab0bf 38b802cbd0a7855ff101020e71ee2e9fd7927316 simpsamp-0.1 simpsamp.asd +single-threaded-ccl http://beta.quicklisp.org/archive/single-threaded-ccl/2015-06-08/single-threaded-ccl-20150608-git.tgz 2611 fa4c2cf5223e2c57e1b3352edeecca0c 3f7bedd0e7741ac4503bd09a6a84da5921e62b81 single-threaded-ccl-20150608-git single-threaded-ccl.asd +sip-hash http://beta.quicklisp.org/archive/sip-hash/2016-08-25/sip-hash-20160825-git.tgz 5396 a79aea8e4847580308bcc46ac2ddeaa2 89284d247a8403a555731ca5dd8bd135bd22609a sip-hash-20160825-git sip-hash-test.asd sip-hash.asd +skeleton-creator http://beta.quicklisp.org/archive/skeleton-creator/2019-12-27/skeleton-creator-20191227-git.tgz 42572 ca2c99e3eb2951f96db1190da7ed3c15 68ef28b145fe342fbc69df5b67d300f23733fea4 skeleton-creator-20191227-git skeleton-creator.asd +sketch http://beta.quicklisp.org/archive/sketch/2017-11-30/sketch-20171130-git.tgz 1117712 4074bf2418d86d392ce6dcca5e379f31 e4f1d2eccd31d987648b90668a7b33025057d3c4 sketch-20171130-git sketch-examples.asd sketch.asd +skippy http://beta.quicklisp.org/archive/skippy/2015-04-07/skippy-1.3.12.tgz 31965 c64deda635cd8b93768ff837c3b66a72 0a9255fa75a12a7c2f74db9ad584abe68d66a538 skippy-1.3.12 skippy.asd +skippy-renderer http://beta.quicklisp.org/archive/skippy-renderer/2018-01-31/skippy-renderer-20180131-git.tgz 2045 38e6ebfbf61921f6d3d8c3b523d7af45 06d79b76393363b593af29a89ce637d62908b5ba skippy-renderer-20180131-git skippy-renderer.asd +skitter http://beta.quicklisp.org/archive/skitter/2018-02-28/skitter-release-quicklisp-620772ae-git.tgz 21551 d9148bdb15605412b813b955cc9fb46b 984a7e9102c2fc65635cec373b3944f884e65a03 skitter-release-quicklisp-620772ae-git skitter.asd skitter.glop.asd skitter.sdl2.asd +slack-client http://beta.quicklisp.org/archive/slack-client/2016-08-25/slack-client-20160825-git.tgz 7752 245f64f7188363f1eabbb4b8a2e9c572 c500065dbbd1bf63fc37ec82114d0f76ebc9d906 slack-client-20160825-git slack-client-test.asd slack-client.asd +slime http://beta.quicklisp.org/archive/slime/2019-07-10/slime-v2.24.tgz 813432 05f421f7a9dffa4ba206c548524ef1c0 2a03cc43352ffec5d863568af298c54fe36138e7 slime-v2.24 swank.asd +slk-581 http://beta.quicklisp.org/archive/slk-581/2019-01-07/slk-581-20190107-git.tgz 4848 d90326b00b92d657b6424002dee00a56 f367c37a8378bddf0810f8fc91a87cbae39a4097 slk-581-20190107-git eclecticse.slk-581.asd +sly http://beta.quicklisp.org/archive/sly/2019-12-27/sly-20191227-git.tgz 1821100 6c38ce18567734425fff81326b7eda5f 7e735a1f2257de7c00b3043399008d1d6e98b5ae sly-20191227-git slynk/slynk.asd +smackjack http://beta.quicklisp.org/archive/smackjack/2018-02-28/smackjack-20180228-git.tgz 17449 398e790adbd5c3d1c85d211d8e119990 9de59527f4fa97c9c09aaaa448978fdc9d3e4ac7 smackjack-20180228-git demo/smackjack-demo.asd smackjack.asd +smart-buffer http://beta.quicklisp.org/archive/smart-buffer/2016-06-28/smart-buffer-20160628-git.tgz 3176 454d8510618da8111c7ca687549b7035 a4f22d227b6266c70e94597af8adf7dfc67b193a smart-buffer-20160628-git smart-buffer-test.asd smart-buffer.asd +smug http://beta.quicklisp.org/archive/smug/2016-04-21/smug-20160421-git.tgz 77846 8139d7813bb3130497b6da3bb4cb8924 588308bcd788fff31da9b464a0e6df1c2386cf16 smug-20160421-git smug.asd +sn.man http://beta.quicklisp.org/archive/sn.man/2019-02-02/sn.man-20190202-git.tgz 1563 c8398aefe8bc3818fbe9a6994bce7f8b 0b2fac544b0edf64f5b7fc0ee520a3853914ff96 sn.man-20190202-git sn.man.asd +snakes http://beta.quicklisp.org/archive/snakes/2018-12-10/snakes-20181210-git.tgz 16534 0bdb11ea92090dabcdc3509af16f0d2a 26c6e7ac29960d3ede577ecc75aceed7461a688f snakes-20181210-git snakes.asd +snappy http://beta.quicklisp.org/archive/snappy/2015-10-31/snappy-20151031-git.tgz 1319848 a454814a316902731bb6e28d4eadd115 8e8a9c046eab9ad4e5497201d4c1e547d5fbc20e snappy-20151031-git snappy-test.asd snappy.asd +snark http://beta.quicklisp.org/archive/snark/2016-04-21/snark-20160421-git.tgz 275436 b7ee5cb5350f5c675359022c10fc6bb9 b265505c5c331237e1fffbb0aa19fa68ff581cee snark-20160421-git snark-agenda.asd snark-auxiliary-packages.asd snark-deque.asd snark-dpll.asd snark-examples.asd snark-feature.asd snark-implementation.asd snark-infix-reader.asd snark-lisp.asd snark-loads.asd snark-numbering.asd snark-pkg.asd snark-sparse-array.asd snark.asd +sndfile-blob http://beta.quicklisp.org/archive/sndfile-blob/2018-02-28/sndfile-blob-stable-d904a06e-git.tgz 4041275 159b41bc37d6fcd4ef294bfd275c051c 8b39988db1b0581af5bf6509e01cf7b9c81bcaec sndfile-blob-stable-d904a06e-git sndfile-blob.asd +snmp http://beta.quicklisp.org/archive/snmp/2016-10-31/snmp-6.1.tgz 4454924 9ea185bf039906911b5f48b73a43c31f 826501f7973e77cd5e2cb19a7ce79d3cb2ecdf1d snmp-6.1 snmp-server.asd snmp-test.asd snmp-ui.asd snmp.asd +snooze http://beta.quicklisp.org/archive/snooze/2019-07-10/snooze-20190710-git.tgz 36180 9c30dee1f9b15e97f7fcc0509291e6f0 9f95a32ebfa69e910a64e56601ccd6758a88448f snooze-20190710-git snooze.asd +softdrink http://beta.quicklisp.org/archive/softdrink/2019-07-10/softdrink-20190710-git.tgz 5640 3fb4add6efa5aa90b69db11b6a0444f7 cff7e8b2e476a2050f1b39fa93d7193f00c47398 softdrink-20190710-git softdrink.asd +solid-engine http://beta.quicklisp.org/archive/solid-engine/2019-05-21/solid-engine-20190521-git.tgz 6543 f666e1d94dd1a915ce8c680d43ddbf02 a8f3345f2690c751b2df8522c9ad200db016960f solid-engine-20190521-git solid-engine.asd +soundex http://beta.quicklisp.org/archive/soundex/2010-10-06/soundex-1.0.tgz 1652 247f7c15b49b230100d37bbc3964bd10 8515dcfcd3bf21025931ca0837e9fe83c2622012 soundex-1.0 soundex.asd +south http://beta.quicklisp.org/archive/south/2019-07-10/south-20190710-git.tgz 20288 5635201c1fe341b9e75f1c0ea97e4e33 77c9ede6f2025cc776071555e2fc2844fce08650 south-20190710-git south.asd +spatial-trees http://beta.quicklisp.org/archive/spatial-trees/2014-08-26/spatial-trees-20140826-git.tgz 21925 2772b963aae5c4d06fff83c22e5c8aa9 5038860caf1e9687de757b3158f9df3086a4d54e spatial-trees-20140826-git spatial-trees.asd spatial-trees.nns.asd spatial-trees.nns.test.asd spatial-trees.test.asd +specialization-store http://beta.quicklisp.org/archive/specialization-store/2019-01-07/specialization-store-v0.0.4.tgz 64336 0d979c5e42a73aa6c764da38506c95bb 7fc8577146bd23a00a1dfabfdc4719429d743335 specialization-store-v0.0.4 specialization-store-features.asd specialization-store-tests.asd specialization-store.asd +specialized-function http://beta.quicklisp.org/archive/specialized-function/2019-12-27/specialized-function-20191227-git.tgz 101044 63a158875039df164af5c3a9b8c6a82d 245ec60790a804b0d859e579f333ae7ddcd445fc specialized-function-20191227-git specialized-function.asd specialized-function.test.asd +spell http://beta.quicklisp.org/archive/spell/2019-03-07/spell-20190307-git.tgz 3643983 f765650ae77e3aa237817ea9d0edf292 b8280c38fd4e628358ffc445d233b4c2a55c1f36 spell-20190307-git spell.asd +spellcheck http://beta.quicklisp.org/archive/spellcheck/2013-10-03/spellcheck-20131003-git.tgz 2375587 1633f18983bbb368192d1355f3f4f13e f6de93b47beda9d56e14184826bb8b49e10cb789 spellcheck-20131003-git spellcheck.asd +spinneret http://beta.quicklisp.org/archive/spinneret/2019-10-07/spinneret-20191007-git.tgz 26495 64de57957fcc72e90b43e1cb26357e4d 5522c52b347f5fbdfe70b8c62b70997bf7db987a spinneret-20191007-git spinneret.asd +split-sequence http://beta.quicklisp.org/archive/split-sequence/2019-05-21/split-sequence-v2.0.0.tgz 10329 88aadc6c9da23663ebbb39d546991df4 54314a3e7e3cb272f6ceec84acd23309bbdbba0f split-sequence-v2.0.0 split-sequence.asd +sprint-stars http://beta.quicklisp.org/archive/sprint-stars/2018-08-31/sprint-stars-20180831-git.tgz 1517 db7adeef5208184377f65388661f7ed2 a9de0cfd9e556c34cd2807084fc6ad2e2328a54f sprint-stars-20180831-git stars.asd +st-json http://beta.quicklisp.org/archive/st-json/2018-10-18/st-json-20181018-git.tgz 7402 75d772cb5d9367f44b924aa1f5620260 d33eaaaa20c73c2ce2a542e7c087ef0273b0d185 st-json-20181018-git st-json.asd +staple http://beta.quicklisp.org/archive/staple/2019-11-30/staple-20191130-git.tgz 98804 e79eb9df05381d830a30256a37f2b105 b097d9a02e2912e8669b7a295f41c9a0515cacec staple-20191130-git parser/staple-code-parser.asd server/staple-server.asd staple-markdown.asd staple-markless.asd staple-package-recording.asd staple-restructured-text.asd staple.asd +static-dispatch http://beta.quicklisp.org/archive/static-dispatch/2019-12-27/static-dispatch-20191227-git.tgz 13045 d796924e4669809b5a4fe74e55af584a 36280bd7c6cb42de15a30b2cbaf2bc2a92e8fdea static-dispatch-20191227-git static-dispatch.asd +static-vectors http://beta.quicklisp.org/archive/static-vectors/2019-11-30/static-vectors-v1.8.4.tgz 7420 401085c3ec0edc3ab47409e5a4b534c7 f0618189731f3099f2790f5b07f1247d2b59ff18 static-vectors-v1.8.4 static-vectors.asd +stealth-mixin http://beta.quicklisp.org/archive/stealth-mixin/2018-12-10/stealth-mixin-20181210-git.tgz 2180 2b6ba6744ac4c4fcdcf1a8c8b71ce567 f3a18458497c73a2a7b901f6f97eb2ce0133c5d9 stealth-mixin-20181210-git stealth-mixin.asd +stefil http://beta.quicklisp.org/archive/stefil/2018-12-10/stefil-20181210-git.tgz 18041 3418bf358366748593f65e4b6e1bb8cf f974b02c814ebaaa804f2ecf4c86b0a18abfe6b2 stefil-20181210-git stefil.asd +stem http://beta.quicklisp.org/archive/stem/2015-06-08/stem-20150608-git.tgz 116071 0dc7713fb0412a4d116304960410cdd7 2eecde21d5d4c35d095bc83b2dd26b55bf8d461e stem-20150608-git stem.asd +stl http://beta.quicklisp.org/archive/stl/2017-10-19/stl-20171019-git.tgz 3089 01a69ac8892b8f4a4bb97c57cf4a9da7 90d1d6084da63bf66ecf50ebf2f84d28531d10b4 stl-20171019-git stl.asd +stmx http://beta.quicklisp.org/archive/stmx/2018-10-18/stmx-stable-4d915e33-git.tgz 360397 817d021e01c934d21a0edadb726e49d4 dc1b0dfe140635e1f2e2974780112e6bf64dc703 stmx-stable-4d915e33-git stmx.asd +string-case http://beta.quicklisp.org/archive/string-case/2018-07-11/string-case-20180711-git.tgz 9081 145c4e13f1e90a070b0a95ca979a9680 ff3958a84d23a5b9e743fbf30726a1d9b6c0fbfd string-case-20180711-git string-case.asd +string-escape http://beta.quicklisp.org/archive/string-escape/2015-04-07/string-escape-20150407-http.tgz 15485 8e2acbd7ce3914258979b87a0284a4a1 1d9841f3e851d744c21af85156651eba4aa322d6 string-escape-20150407-http string-escape.asd +stripe http://beta.quicklisp.org/archive/stripe/2019-08-13/stripe-20190813-git.tgz 11794 df2fada3fcb94abac84dde39ebfbfaaa 9ff3e4e67910a7418362012df2bd894611af8828 stripe-20190813-git stripe.asd +structy-defclass http://beta.quicklisp.org/archive/structy-defclass/2017-06-30/structy-defclass-20170630-git.tgz 2769 ae666e7951c4137242d95fff9ca6c31e df7f719fa42dc7d3115ed1e0e14cd289eb9f7cce structy-defclass-20170630-git structy-defclass.asd +studio-client http://beta.quicklisp.org/archive/studio-client/2019-11-30/studio-client-20191130-git.tgz 8792 5b8fd01399af33f5244d4ecb1bf9ca4d 1e83a2a60bd8b087412e8824a4fb3fc626c4908b studio-client-20191130-git studio-client.asd +stumpwm http://beta.quicklisp.org/archive/stumpwm/2019-12-27/stumpwm-20191227-git.tgz 217019 247f56ddbdc8bdf4cf087a467ddce6f6 c658a1e8528de2113f6a15d55c6c5db3de81dd83 stumpwm-20191227-git stumpwm-tests.asd stumpwm.asd +submarine http://beta.quicklisp.org/archive/submarine/2012-09-09/submarine-20120909-darcs.tgz 38895 461d3050c80b3bbfa73e0ccddc3c00f3 2695b1d9c135e05e6f8bbcb23f0b663a438961e8 submarine-20120909-darcs submarine.asd +sucle http://beta.quicklisp.org/archive/sucle/2019-05-21/sucle-20190521-git.tgz 1010033 53bfdeeb528acc9be632877ac21625a3 f713be4086345e3b3f3fa201a77b90b59e1369a6 sucle-20190521-git application/app-subsystem/application/application.asd application/app-subsystem/clock/clock.asd application/app-subsystem/control/control.asd application/app-subsystem/deflazy/deflazy.asd application/app-subsystem/fps-independent-timestep/fps-independent-timestep.asd application/app-subsystem/opengl-immediate/opengl-immediate.asd application/app-subsystem/scratch-buffer/scratch-buffer.asd application/app-subsystem/window/window.asd application/application-example-hello-world/application-example-hello-world.asd application/basic0/sucle.asd application/subsystems/cartesian-graphing/cartesian-graphing.asd application/subsystems/fast-text-grid-sprites/fast-text-grid-sprites.asd application/subsystems/sandbox/sandbox.asd application/subsystems/sketch-sucle/sketch-sucle-examples.asd application/subsystems/sketch-sucle/sketch-sucle.asd application/subsystems/text-subsystem/doc/text-subsystem-generate-font.asd application/subsystems/text-subsystem/text-subsystem.asd application/subsystems/vecto-test/vecto-stuff.asd application/sucle2/sucle2.asd application/testbed/testbed.asd src/character-modifier-bits/character-modifier-bits.asd src/data-structures/doubly-linked-list/sucle-doubly-linked-list.asd src/data-structures/matrix/matrix.asd src/data-structures/reverse-array-array/example/reverse-array-array-example.asd src/data-structures/reverse-array-array/reverse-array-array.asd src/data-structures/reverse-array-iterator/reverse-array-iterator.asd src/data-structures/sprite-chain/sprite-chain.asd src/euclidean-geometry/aabbcc/aabbcc.asd src/euclidean-geometry/camera-matrix/camera-matrix.asd src/euclidean-geometry/quads/quads.asd src/image/image-utility/image-utility.asd src/nsb-cga/nsb-cga.asd src/opengl/glhelp.asd src/uncommon-lisp/uncommon-lisp.asd src/window-opengl-glfw3/opengl-glfw3.asd +swank-client http://beta.quicklisp.org/archive/swank-client/2019-10-07/swank-client-20191007-git.tgz 15470 e9956d8033709c673ba16a2d7a7fb43e 07830b6ade8802791510e40241ba38b042a9f06e swank-client-20191007-git swank-client-test.asd swank-client.asd +swank-crew http://beta.quicklisp.org/archive/swank-crew/2015-10-31/swank-crew-20151031-git.tgz 15837 8a792387ad5d695a0d80ab5cd44866d0 b0e5cbbe82a9c95199a67ec21769f3f2167a6b07 swank-crew-20151031-git swank-crew-test.asd swank-crew.asd +swank-protocol http://beta.quicklisp.org/archive/swank-protocol/2015-12-18/swank-protocol-20151218-git.tgz 7391 715d26e8b7d0a2d8e18d2a7dc2b946f1 0d695ac0968fa294475c425b5a3345d76973f692 swank-protocol-20151218-git swank-protocol.asd +swank.live http://beta.quicklisp.org/archive/swank.live/2016-02-08/swank.live-20160208-git.tgz 1754 0cfd0cc920b37a27359244797dfd8817 0e98e9c945773a2f6e8e79688081c942a3327f9d swank.live-20160208-git swank.live.asd +swap-bytes http://beta.quicklisp.org/archive/swap-bytes/2019-11-30/swap-bytes-v1.2.tgz 4342 eea516d7fdbe20bc963a6708c225d719 e1ab274454408933c57dd932be413f0b11f18444 swap-bytes-v1.2 swap-bytes.asd +sxql http://beta.quicklisp.org/archive/sxql/2019-11-30/sxql-20191130-git.tgz 25711 f46e9a33b39f5b069b805e00f80a5410 d2291dc7e569deeb81b2f0d5665d99d46e92c5cd sxql-20191130-git sxql-test.asd sxql.asd +sycamore http://beta.quicklisp.org/archive/sycamore/2018-10-18/sycamore-20181018-git.tgz 55595 ecc982173a52ead05a35454a23e60cc3 dde17ef19ba0c690a9790acaab9344b7f67e7f5c sycamore-20181018-git src/sycamore.asd +symbol-munger http://beta.quicklisp.org/archive/symbol-munger/2015-04-07/symbol-munger-20150407-git.tgz 5298 b1e35b63d7ad1451868d1c40e2fbfab7 a8589c60f470b8b280eacd9c983d96bc5f337341 symbol-munger-20150407-git symbol-munger.asd +symbol-namespaces http://beta.quicklisp.org/archive/symbol-namespaces/2013-01-28/symbol-namespaces-1.0.tgz 4915 0ffbf4f50332e324feb40269ca1848cd 1088d4f5d922d472fc16a77da01c498ec956a9a7 symbol-namespaces-1.0 symbol-namespaces.asd +synonyms http://beta.quicklisp.org/archive/synonyms/2019-03-07/synonyms-20190307-hg.tgz 1628 6f956534aa5f68cd03988303fdc40f30 2a5f07c4a581566a998f4a56048850c9e7f6268b synonyms-20190307-hg synonyms.asd +system-locale http://beta.quicklisp.org/archive/system-locale/2019-07-10/system-locale-20190710-git.tgz 6241 1f2bbaabf7b0c8122666cdd688592c09 e2c3f0c6894a1480f6ab9fb01aac138ef2c75998 system-locale-20190710-git system-locale.asd +tagger http://beta.quicklisp.org/archive/tagger/2019-03-07/tagger-20190307-git.tgz 1107234 8eceb5a9684410e3f4f8471c1e10608b 9b157554e13131da1f942375cb4d647a3717d686 tagger-20190307-git tagger.asd +taglib http://beta.quicklisp.org/archive/taglib/2018-07-11/taglib-20180711-git.tgz 49606 4c8725f03df326ab12ce2b810e79724b 114161a2d82899942d7c36f8f66f5f345cdc2ba1 taglib-20180711-git taglib-tests.asd taglib.asd +talcl http://beta.quicklisp.org/archive/talcl/2018-02-28/talcl-20180228-git.tgz 32272 12f54d47f90bc8385b3fa8bc4ded7530 39bf555e8bcdb9497663597dc6fe0d725d4c9388 talcl-20180228-git talcl.asd +tap-unit-test http://beta.quicklisp.org/archive/tap-unit-test/2017-12-27/tap-unit-test-20171227-git.tgz 6640 999414b562bcad22ad8be263d13cf813 bee7f65ad728387c7496f6ee412711c2982d8d7c tap-unit-test-20171227-git tap-unit-test.asd +targa http://beta.quicklisp.org/archive/targa/2018-10-18/targa-20181018-git.tgz 6717 abdb921075c2f42c314bcaa6af93402a 5d82e49c058ae56f9c586a82424f853476023ee7 targa-20181018-git targa.asd +teepeedee2 http://beta.quicklisp.org/archive/teepeedee2/2016-04-21/teepeedee2-20160421-git.tgz 92218 1685bc037dcaaeba1f5b9224fda7dccb 1d8e266e9e2f6063bfabccd37b55c66fa42ddb49 teepeedee2-20160421-git teepeedee2-test.asd teepeedee2.asd +telnetlib http://beta.quicklisp.org/archive/telnetlib/2014-12-17/telnetlib-20141217-git.tgz 9030 d002d6c2aa8cda700fa7b0e114404197 65dff3a01133aacc554aea10ecfb2d4a95ad6c12 telnetlib-20141217-git telnetlib.asd +template http://beta.quicklisp.org/archive/template/2019-03-07/template-20190307-hg.tgz 3558 f1f963f928879fb2ef6903e5e0466d6d a2a448c28c9b96927ef288929c04f931a86ed63c template-20190307-hg template.asd +template-function http://beta.quicklisp.org/archive/template-function/2017-11-30/template-function-v0.0.1-git.tgz 28074 cfe8ff39d2006b55a46b7f0bdf770ecb 327ad56f17a4923c9124834168791462d5274252 template-function-v0.0.1-git template-function-tests.asd template-function.asd +temporal-functions http://beta.quicklisp.org/archive/temporal-functions/2017-10-19/temporal-functions-20171019-git.tgz 6586 0a4ad318c90a9cc2c7ca391d2c471c1a 70bfe85677d18c3de5434d054d6dd7b6ae3395d4 temporal-functions-20171019-git temporal-functions.asd +temporary-file http://beta.quicklisp.org/archive/temporary-file/2015-06-08/temporary-file-20150608-git.tgz 10812 0df609812523566a84604d768158f3b0 1ac3046923b6136defee3d28344f9c4e69d8e83a temporary-file-20150608-git temporary-file.asd +terminfo http://beta.quicklisp.org/archive/terminfo/2018-08-31/terminfo-20180831-git.tgz 12813 0b3ee86845c43c92cfb8eaddaa94ce42 39995b17e1b4fe3a6e6bd4aaf16720bb646cfa7c terminfo-20180831-git terminfo.asd +terrable http://beta.quicklisp.org/archive/terrable/2019-07-10/terrable-20190710-git.tgz 8756 99d92ae77464827a2c3f17cbcef09388 5b7f6b7821374d913cc4f8aa34968db75a065480 terrable-20190710-git terrable.asd +test-utils http://beta.quicklisp.org/archive/test-utils/2018-08-31/test-utils-20180831-git.tgz 5073 dff3c30e51b7ff5812b6eb7671342033 b11396183f5751bb224571c8981290a59fab14f0 test-utils-20180831-git test-utils.asd +testbild http://beta.quicklisp.org/archive/testbild/2010-12-07/testbild-20101207-git.tgz 52330 d3008e32481ed01aaf4bf8d2fd0bcbad 95fca0344bb5af81f7f9c0453ed51e24fd27419f testbild-20101207-git testbild-test.asd testbild.asd +texp http://beta.quicklisp.org/archive/texp/2015-12-18/texp-20151218-git.tgz 16321 0ded17b1ba2ad4506e5f4bde9ba9a2d7 e73f7a2267913b386f31b78b6e68ddd4c896de92 texp-20151218-git texp.asd +text-query http://beta.quicklisp.org/archive/text-query/2011-11-05/text-query-1.1.tgz 5548 57d28b552f346a00ece98824b1bc898f f5ec2327f9d7049749d6bea161ea7d90a5db5017 text-query-1.1 text-query.asd +tfm http://beta.quicklisp.org/archive/tfm/2019-11-30/tfm-20191130-git.tgz 39947 a86c7c0f808b834cd42557375003bfc1 95a09ff4cf730fe82a9a03a85efb3d9e2bbf7542 tfm-20191130-git core/net.didierverna.tfm.core.asd net.didierverna.tfm.asd setup/net.didierverna.tfm.setup.asd +the-cost-of-nothing http://beta.quicklisp.org/archive/the-cost-of-nothing/2019-11-30/the-cost-of-nothing-20191130-git.tgz 6864 e7b9891f6a3827425124ed8c00b13bab c8f6ee5ed5ee075729d28dcbe354386ba555aab1 the-cost-of-nothing-20191130-git the-cost-of-nothing.asd +thnappy http://beta.quicklisp.org/archive/thnappy/2018-08-31/thnappy-20180831-git.tgz 2879 e399d3a0aea4a4d46b4f3779b083b759 e68599d93d642eb88c3c4ead9a7724c43c34bf5c thnappy-20180831-git thnappy.asd +thorn http://beta.quicklisp.org/archive/thorn/2015-06-08/thorn-20150608-git.tgz 4539 efcc67773fb54b4e4680d50ed5091f9a 436eb3485d54524cc23cc97d1d30ea4f3d1af29b thorn-20150608-git thorn-doc.asd thorn-test.asd thorn.asd +thread-pool http://beta.quicklisp.org/archive/thread-pool/2012-01-07/thread-pool-20120107-git.tgz 3061 9dfcb3dd5692d474d90f7916722d5bf8 5754230b3648ae4d84f80a8cf552518d6851e96b thread-pool-20120107-git thread-pool.asd +thread.comm.rendezvous http://beta.quicklisp.org/archive/thread.comm.rendezvous/2012-10-13/thread.comm.rendezvous-20121013-git.tgz 3295 819e6c2c9fc715f47b9fc1fae4dd9620 fb0ada0703f62f9d2c38cd8d100571b087d6f61f thread.comm.rendezvous-20121013-git thread.comm.rendezvous.asd thread.comm.rendezvous.test.asd +time-interval http://beta.quicklisp.org/archive/time-interval/2019-02-02/time-interval-20190202-git.tgz 3914 be8f598fa583bc02d5aef61c9da05497 2e3b1a01d3aca24e573fdf98ce81b5a15909ce2c time-interval-20190202-git time-interval.asd +timer-wheel http://beta.quicklisp.org/archive/timer-wheel/2018-02-28/timer-wheel-20180228-git.tgz 6804 aecee06490b30b7395bd6bf8e30e293f f5394005e0e5214210a8dd1a0d41fd35674c364d timer-wheel-20180228-git timer-wheel.asd timer-wheel.examples.asd +tinaa http://beta.quicklisp.org/archive/tinaa/2017-12-27/tinaa-20171227-git.tgz 80171 bc067fbe6af7f03f247e93c0d35c5f3a 7cb5eed990ef9deaa609f923c9361840131a90f2 tinaa-20171227-git tinaa-test.asd tinaa.asd +tm http://beta.quicklisp.org/archive/tm/2018-02-28/tm-v0.8.tgz 173992 8c2219879aa24677951a02235855dcf6 dbe34f193e9e3e16b829d8516ef3c510322408c0 tm-v0.8 tm.asd +tmpdir http://beta.quicklisp.org/archive/tmpdir/2019-11-30/tmpdir-20191130-git.tgz 1540 39548e71b34a0a43b2930eb248fe9695 26c38135426f38f3c4b8476b5f1dad1f2382e3e1 tmpdir-20191130-git tmpdir.asd +toadstool http://beta.quicklisp.org/archive/toadstool/2013-06-15/toadstool-20130615-git.tgz 14309 8bd093fb81edf56821b538339c70c1f1 404dd62b14525f642110dfd30dadbe4e753f1e9f toadstool-20130615-git toadstool-tests.asd toadstool.asd +toot http://beta.quicklisp.org/archive/toot/2012-11-25/toot-20121125-git.tgz 57834 569c801b0b9e880977df5ab9743ec23c b97041f2040590e8751eae383532996923ec5ad0 toot-20121125-git toot.asd +tooter http://beta.quicklisp.org/archive/tooter/2019-07-10/tooter-20190710-git.tgz 37879 b53a4836c868a7e2c0008f2d85d4cb98 b9089b0b627fb7378a50fb276b4f186af4530859 tooter-20190710-git tooter.asd +torta http://beta.quicklisp.org/archive/torta/2014-07-13/torta-20140713-git.tgz 126230 5f2ab2b6d6cb48f17dbf147adde1941e 77e116a79f5931c42d675485991dc5d8352beff1 torta-20140713-git torta.asd +towers http://beta.quicklisp.org/archive/towers/2014-12-17/towers-20141217-git.tgz 17597 2af927bf9a75351e0216b45dafef01ce 8949f07d1929307532b2b9ad4009480ea166c808 towers-20141217-git towers.asd +trace-db http://beta.quicklisp.org/archive/trace-db/2019-07-10/trace-db-20190710-git.tgz 52753 4fa5f75f0239ab1e04cf235fe3c0574c 59f7a19923caaceeaab8661b084c99e70485df46 trace-db-20190710-git trace-db.asd +track-best http://beta.quicklisp.org/archive/track-best/2018-10-18/track-best-20181018-git.tgz 6252 e8a45d9ea61867c6873bb5b78018a5f9 96a1746115744d3c733a52b9eaf14a40d9318a08 track-best-20181018-git track-best.asd +trainable-object http://beta.quicklisp.org/archive/trainable-object/2019-12-27/trainable-object-20191227-git.tgz 19230 9db5fb29c21927d7d1aee421e673ee66 bcb41c52a7278aaf9c381b14218eb79617290766 trainable-object-20191227-git trainable-object.asd trainable-object.test.asd +translate http://beta.quicklisp.org/archive/translate/2018-02-28/translate-20180228-git.tgz 6688 95c46dec58c83cd01efd27d60049712f 8660e413ff82b5e83b42bb0d3a64990ee1383db7 translate-20180228-git translate.asd +translate-client http://beta.quicklisp.org/archive/translate-client/2018-02-28/translate-client-20180228-git.tgz 4495 94b7fb3e9836500104348162732512be bdf15a4a38460632c85d3979ef08ea27e79f8c3c translate-client-20180228-git translate-client.asd +transparent-wrap http://beta.quicklisp.org/archive/transparent-wrap/2015-07-09/transparent-wrap-20150709-git.tgz 10282 fbbcfb41c7bdc8e959d4a6716d12fed9 60be87e9f50ecbbde5038341a990ab8e5aaa18f4 transparent-wrap-20150709-git transparent-wrap.asd +treedb http://beta.quicklisp.org/archive/treedb/2016-08-25/treedb-20160825-git.tgz 16294 af216acd41ca7a14497d3f045af39b26 d12e833c2d1c271e6ef49bc189a51ccd8f4edfde treedb-20160825-git doc/treedb.doc.asd tests/treedb.tests.asd treedb.asd +trees http://beta.quicklisp.org/archive/trees/2018-01-31/trees-20180131-git.tgz 20019 a1b156d15d444d114f475f7abc908064 3e5523710bbc6c5d96894e036377fbb4487460f9 trees-20180131-git trees.asd +trivia http://beta.quicklisp.org/archive/trivia/2019-12-27/trivia-20191227-git.tgz 58411 645f0e0fcf57ab37ebd4f0a1b7b05854 2354871dba25e2b875edd4cb9f4ebc6fc416badf trivia-20191227-git trivia.asd trivia.balland2006.asd trivia.benchmark.asd trivia.cffi.asd trivia.level0.asd trivia.level1.asd trivia.level2.asd trivia.ppcre.asd trivia.quasiquote.asd trivia.test.asd trivia.trivial.asd +trivial-arguments http://beta.quicklisp.org/archive/trivial-arguments/2019-07-10/trivial-arguments-20190710-git.tgz 3375 e18fa47699802dee1731e0c2d9903f96 3eac3be70009b856090eaee2c4d217eb702efe81 trivial-arguments-20190710-git trivial-arguments.asd +trivial-backtrace http://beta.quicklisp.org/archive/trivial-backtrace/2019-07-10/trivial-backtrace-20190710-git.tgz 9208 e9035ed00321b24278cbf5449a1aebed 15034f7fba32e86bfa374f97134b0bfda8760e32 trivial-backtrace-20190710-git trivial-backtrace-test.asd trivial-backtrace.asd +trivial-battery http://beta.quicklisp.org/archive/trivial-battery/2019-03-07/trivial-battery-20190307-git.tgz 2248 ccb8f68e7086523a8da2700fab0e5c7d f13fceb155f8e99202ae1d9c99ff0e140b4e4803 trivial-battery-20190307-git trivial-battery.asd +trivial-benchmark http://beta.quicklisp.org/archive/trivial-benchmark/2019-11-30/trivial-benchmark-20191130-git.tgz 14929 8b2be09b1d8312c790006118847261cf aa6d4b7201691f97b4808a34b28b29a1a438ad9b trivial-benchmark-20191130-git trivial-benchmark.asd +trivial-bit-streams http://beta.quicklisp.org/archive/trivial-bit-streams/2019-07-10/trivial-bit-streams-20190710-git.tgz 7667 c08ad7b58a972f45c4939ad6869a9283 819805e50d470ec6b09ee0ea53889f633754408e trivial-bit-streams-20190710-git trivial-bit-streams-tests.asd trivial-bit-streams.asd +trivial-build http://beta.quicklisp.org/archive/trivial-build/2015-12-18/trivial-build-20151218-git.tgz 3150 51479b61f4cbe7a113065b0f3ac50834 654770325c8c5ebd1632430aae2bc3f4ac027fd7 trivial-build-20151218-git trivial-build-test.asd trivial-build.asd +trivial-channels http://beta.quicklisp.org/archive/trivial-channels/2016-04-21/trivial-channels-20160421-git.tgz 2810 7bd8731f8ffbbc61aeaf7fde3309c2a3 2c856642b1ac4006d2f8a1f8bd55d18697c9329e trivial-channels-20160421-git trivial-channels.asd +trivial-clipboard http://beta.quicklisp.org/archive/trivial-clipboard/2019-02-02/trivial-clipboard-20190202-git.tgz 4086 d9b9ee3754e10888ce243172681a0db2 2078c5844dd927ec38e8d7103090b440715dbc32 trivial-clipboard-20190202-git trivial-clipboard-test.asd trivial-clipboard.asd +trivial-cltl2 http://beta.quicklisp.org/archive/trivial-cltl2/2019-07-10/trivial-cltl2-20190710-git.tgz 5067 8114f96b9770a9f0e0a94933918dc171 2530e30e0927283650c2f36c38025edbd84e2473 trivial-cltl2-20190710-git trivial-cltl2.asd +trivial-compress http://beta.quicklisp.org/archive/trivial-compress/2016-04-21/trivial-compress-20160421-git.tgz 2838 8d531a2607e6b206c3bbfe51d003c8b6 d228a5309280c996ceaa25e9234e238359050c16 trivial-compress-20160421-git trivial-compress-test.asd trivial-compress.asd +trivial-continuation http://beta.quicklisp.org/archive/trivial-continuation/2019-10-07/trivial-continuation-20191007-git.tgz 6021 cd66f3f621bd6004b18c8cfb834fa61c b031d2c2d477949c038e14b9a84fb13cba7f5ae6 trivial-continuation-20191007-git trivial-continuation.asd +trivial-debug-console http://beta.quicklisp.org/archive/trivial-debug-console/2015-04-07/trivial-debug-console-20150407-git.tgz 2602 570ce84cfc527c3ce9a66eb9a3e32a33 c78bc7dbf398faba7518f9edc3fa7ef64ac74768 trivial-debug-console-20150407-git trivial-debug-console.asd +trivial-documentation http://beta.quicklisp.org/archive/trivial-documentation/2016-12-04/trivial-documentation-20161204-git.tgz 15596 9f092a90567e4f77dc9bd1d06fa58ed0 be1d89ac255c31e9de3ad7966312cfa1e6cda9e2 trivial-documentation-20161204-git trivial-documentation-test.asd trivial-documentation.asd +trivial-download http://beta.quicklisp.org/archive/trivial-download/2015-12-18/trivial-download-20151218-git.tgz 3819 486d3b0da2d832e3f0a6176e40adc449 c975d97de65d514f66b82ce1f52f4a8dcc8ec68e trivial-download-20151218-git trivial-download-test.asd trivial-download.asd +trivial-dump-core http://beta.quicklisp.org/archive/trivial-dump-core/2017-02-27/trivial-dump-core-20170227-git.tgz 5550 1ba1e853c238b2545002db6ee9530144 8a54cef6a4d0dea05cb5844ebb44f0cf03da762d trivial-dump-core-20170227-git trivial-dump-core.asd +trivial-escapes http://beta.quicklisp.org/archive/trivial-escapes/2018-02-28/trivial-escapes-20180228-git.tgz 6079 b8afeb445f9a3fd8e046d5899fd21e2e 102cfd6ba8f9af527302062704cbd04974848bae trivial-escapes-20180228-git test/trivial-escapes-test.asd trivial-escapes.asd +trivial-exe http://beta.quicklisp.org/archive/trivial-exe/2015-12-18/trivial-exe-20151218-git.tgz 1983 d85a8e198c31aa3d6c07351a41732e49 a860186969c29240babffd1c0e2209635a5e2e3a trivial-exe-20151218-git trivial-exe-test.asd trivial-exe.asd +trivial-extensible-sequences http://beta.quicklisp.org/archive/trivial-extensible-sequences/2019-08-13/trivial-extensible-sequences-20190813-git.tgz 15428 7001347e293ccd5cd15026e0a7ec4158 0f339cefb94cc1225113d7f64ebccbb87e28c8c0 trivial-extensible-sequences-20190813-git trivial-extensible-sequences.asd +trivial-extract http://beta.quicklisp.org/archive/trivial-extract/2016-04-21/trivial-extract-20160421-git.tgz 3545 b9c3ede33a7f4d565f6916a52a6ea708 c89c03f8cd08876c412a3ae40b0ac763b1930635 trivial-extract-20160421-git trivial-extract-test.asd trivial-extract.asd +trivial-features http://beta.quicklisp.org/archive/trivial-features/2019-07-10/trivial-features-20190710-git.tgz 10765 3907b044e00a812ebae989134fe57c55 67b7502615c36002f611536020ee5ffb3e23513a trivial-features-20190710-git trivial-features-tests.asd trivial-features.asd +trivial-file-size http://beta.quicklisp.org/archive/trivial-file-size/2018-01-31/trivial-file-size-20180131-git.tgz 3254 ac921679334dd8bd12f927f0bd806f4b cf8f78bbbbb18e547dd47cff487ac30a4f356c43 trivial-file-size-20180131-git trivial-file-size.asd +trivial-garbage http://beta.quicklisp.org/archive/trivial-garbage/2019-05-21/trivial-garbage-20190521-git.tgz 10438 38fb70797069d4402c6b0fe91f4ca5a8 d9013ebd6a0ea3bd5a23dc9368fb0e318d651fcd trivial-garbage-20190521-git trivial-garbage.asd +trivial-gray-streams http://beta.quicklisp.org/archive/trivial-gray-streams/2018-10-18/trivial-gray-streams-20181018-git.tgz 8024 0a9f564079dc41ce10d7869d82cc0952 27c3dc766e7c8fed3051403e0c38468a235f6acf trivial-gray-streams-20181018-git trivial-gray-streams-test.asd trivial-gray-streams.asd +trivial-hashtable-serialize http://beta.quicklisp.org/archive/trivial-hashtable-serialize/2019-10-07/trivial-hashtable-serialize-20191007-git.tgz 4010 9983c4dff65eb69b0eadb067cf03a834 79afe82d413cd42fbcd64a6f66a7bdb0f15ad245 trivial-hashtable-serialize-20191007-git trivial-hashtable-serialize.asd +trivial-http http://beta.quicklisp.org/archive/trivial-http/2011-02-19/trivial-http-20110219-http.tgz 12646 9f6b15eb07fd99fd0b6b69387a520a4f c71ab658c7c6a98eefdd9a69f8d358a9752bb1dc trivial-http-20110219-http trivial-http-test.asd trivial-http.asd +trivial-indent http://beta.quicklisp.org/archive/trivial-indent/2019-10-07/trivial-indent-20191007-git.tgz 3419 d0489ff824d58c03b5c2a9b16279f583 480bc42651968cf7b9566c190c83d39a42be03d3 trivial-indent-20191007-git trivial-indent.asd +trivial-irc http://beta.quicklisp.org/archive/trivial-irc/2017-10-19/trivial-irc-20171019-git.tgz 22705 e63a9436c7db593d5aab25d4eb89679b 1fd2165891ad015f7d978e275dc7f99063a605fa trivial-irc-20171019-git trivial-irc-echobot.asd trivial-irc.asd +trivial-json-codec http://beta.quicklisp.org/archive/trivial-json-codec/2019-10-07/trivial-json-codec-20191007-git.tgz 8065 1c55c7d97d49750189d5bd9fbc5afd15 2261bc37879f3f0be83fd74bcdc6964ebec13dbe trivial-json-codec-20191007-git trivial-json-codec.asd +trivial-jumptables http://beta.quicklisp.org/archive/trivial-jumptables/2019-11-30/trivial-jumptables_1.1.tgz 12374 f8ef2c3b2659c6874a0d3f5555b353af 83d069ac067e1a258ad39ee3b5d0cc437f33469f trivial-jumptables_1.1 tests/trivial-jumptables_tests.asd trivial-jumptables.asd +trivial-lazy http://beta.quicklisp.org/archive/trivial-lazy/2015-07-09/trivial-lazy-20150709-git.tgz 1714 ebb499de9ea8b79b0d580222d36ddee9 e9b99256aeec0f0184f3ae5cf20a9e294c1dd972 trivial-lazy-20150709-git trivial-lazy.asd +trivial-ldap http://beta.quicklisp.org/archive/trivial-ldap/2018-07-11/trivial-ldap-20180711-git.tgz 28258 355759d2c532a377b0ec3c0a689548fd 160ff42b50f8f664b029cb53e598301cd8f2d7f4 trivial-ldap-20180711-git trivial-ldap.asd +trivial-left-pad http://beta.quicklisp.org/archive/trivial-left-pad/2019-08-13/trivial-left-pad-20190813-git.tgz 6592 04a7ef287111319605989f582bf7ce4f 544fa2a3c678fe11f7a5a65e7f3e591abf9bcd5e trivial-left-pad-20190813-git trivial-left-pad.asd +trivial-macroexpand-all http://beta.quicklisp.org/archive/trivial-macroexpand-all/2017-10-23/trivial-macroexpand-all-20171023-git.tgz 1968 9cec494869344eb64ebce802c01928c5 87006c97029637389a4371efc28ba43ececfc315 trivial-macroexpand-all-20171023-git trivial-macroexpand-all.asd +trivial-main-thread http://beta.quicklisp.org/archive/trivial-main-thread/2019-07-10/trivial-main-thread-20190710-git.tgz 6114 ab95906f1831aa5b40f271eebdfe11a3 899bc9fa1f863baeece94f9aea0d7f6b7385dbbb trivial-main-thread-20190710-git trivial-main-thread.asd +trivial-method-combinations http://beta.quicklisp.org/archive/trivial-method-combinations/2019-11-30/trivial-method-combinations-20191130-git.tgz 1502 810ed9f3459831000b175970a35c0a0f 323703b64bd61e9dbe911d601c8360e4500c0057 trivial-method-combinations-20191130-git trivial-method-combinations.asd +trivial-mimes http://beta.quicklisp.org/archive/trivial-mimes/2019-07-10/trivial-mimes-20190710-git.tgz 20215 b7fa1cb9382a2a562343c6ca87b1b4ac 9ab070fa12b583fee21df36d50f102b29ef648c5 trivial-mimes-20190710-git trivial-mimes.asd +trivial-mmap http://beta.quicklisp.org/archive/trivial-mmap/2018-07-11/trivial-mmap-20180711-git.tgz 3387 17bfc83b320be648da993a83991f911a efaef0202a10f2416443adea49d225bc9da3e3ff trivial-mmap-20180711-git trivial-mmap.asd +trivial-monitored-thread http://beta.quicklisp.org/archive/trivial-monitored-thread/2019-10-07/trivial-monitored-thread-20191007-git.tgz 6500 2ae90d97c0abe51cd14fc59427233ced 482f9c9a177bd73291fdfc24b9e21c5ae48751ce trivial-monitored-thread-20191007-git trivial-monitored-thread.asd +trivial-msi http://beta.quicklisp.org/archive/trivial-msi/2016-02-08/trivial-msi-20160208-git.tgz 2142 c2b860a6959e61707142419756f7cf3e 0d6d8cf48d175a6616a245801fa44a165baee4c4 trivial-msi-20160208-git trivial-msi-test.asd trivial-msi.asd +trivial-nntp http://beta.quicklisp.org/archive/trivial-nntp/2016-12-04/trivial-nntp-20161204-git.tgz 4937 f03c13ee62ce27792941d9f9d8cd7c43 b311c46a549c4dbffaed13b8c338ce976ad7b892 trivial-nntp-20161204-git trivial-nntp.asd +trivial-object-lock http://beta.quicklisp.org/archive/trivial-object-lock/2019-10-07/trivial-object-lock-20191007-git.tgz 128346 c0fe973e9a00faf5286895d18952c231 6e0a1fc45e98e903b54182cf2ac1d01bee87993c trivial-object-lock-20191007-git trivial-object-lock.asd +trivial-octet-streams http://beta.quicklisp.org/archive/trivial-octet-streams/2013-01-28/trivial-octet-streams-20130128-git.tgz 3452 00d2c8cd41b5ace65519f366bc6542fb e0b865e9b1787e6f91b5d5e6c454a1a5890e077e trivial-octet-streams-20130128-git trivial-octet-streams.asd +trivial-open-browser http://beta.quicklisp.org/archive/trivial-open-browser/2016-08-25/trivial-open-browser-20160825-git.tgz 1176 038c4cd110fa9b34a77fe655bc1e35ba bac02728c1ed3037f88b89764dacf204bb8a1b4a trivial-open-browser-20160825-git trivial-open-browser.asd +trivial-openstack http://beta.quicklisp.org/archive/trivial-openstack/2016-06-28/trivial-openstack-20160628-git.tgz 9849 fd4cea1d1a6e3079f4778c226fbb08b1 d7bb60c337b47ad21205099b8ac38efb7b48bd59 trivial-openstack-20160628-git trivial-openstack-test.asd trivial-openstack.asd +trivial-package-local-nicknames http://beta.quicklisp.org/archive/trivial-package-local-nicknames/2019-11-30/trivial-package-local-nicknames-20191130-git.tgz 3681 703a57785a11477361ac4253aab0698e 56036aae9c02f10390e91c6c141e9a15bf0e0462 trivial-package-local-nicknames-20191130-git trivial-package-local-nicknames.asd +trivial-package-manager http://beta.quicklisp.org/archive/trivial-package-manager/2017-12-27/trivial-package-manager-20171227-git.tgz 6042 161ae810ca261f04aae86068365839da bdda9666a328e2d6e8278fceb8d6b9dff46e1c31 trivial-package-manager-20171227-git trivial-package-manager.asd trivial-package-manager.test.asd +trivial-pooled-database http://beta.quicklisp.org/archive/trivial-pooled-database/2019-10-07/trivial-pooled-database-20191007-git.tgz 6240 4649ea77d57c2e1a5a01656f8f480eb9 2d7e41c5267119fb0a7a10f77c115ece76804b29 trivial-pooled-database-20191007-git trivial-pooled-database.asd +trivial-project http://beta.quicklisp.org/archive/trivial-project/2017-08-30/trivial-project-quicklisp-9e3fe231-git.tgz 7676 1702cda33bf5d228c4f865f4ca2f28da f9050c412d5c9851d3f384000a6b8b8eaab82473 trivial-project-quicklisp-9e3fe231-git trivial-project.asd +trivial-raw-io http://beta.quicklisp.org/archive/trivial-raw-io/2014-12-17/trivial-raw-io-20141217-git.tgz 2861 627f83a54a94278675c03c14934b272a f89b8c4e06554471bfcb9216dd2eb385b5dd8e8a trivial-raw-io-20141217-git trivial-raw-io.asd +trivial-renamer http://beta.quicklisp.org/archive/trivial-renamer/2017-08-30/trivial-renamer-quicklisp-1282597d-git.tgz 3794 ff77e08decb7ca7b5b18e7b03c6cb05b 071cd2c4f5eb569ca958dbfd91a8effb3f0df647 trivial-renamer-quicklisp-1282597d-git trivial-renamer.asd +trivial-rfc-1123 http://beta.quicklisp.org/archive/trivial-rfc-1123/2017-01-24/trivial-rfc-1123-20170124-git.tgz 5622 a91a7fc1fae5a5da9e34ff58b72236e7 8fd5bfe63f661ab64c368a0831c81bedf9f0d015 trivial-rfc-1123-20170124-git trivial-rfc-1123.asd +trivial-shell http://beta.quicklisp.org/archive/trivial-shell/2018-02-28/trivial-shell-20180228-git.tgz 14473 d7b93648abd06be95148d43d09fa2ed0 cea06f83f2a0a7f17ba75b612535dc2676296025 trivial-shell-20180228-git trivial-shell-test.asd trivial-shell.asd +trivial-signal http://beta.quicklisp.org/archive/trivial-signal/2019-07-10/trivial-signal-20190710-git.tgz 13446 835a39ed6f968c22862be53487bab640 f1eda45929be115101e995590fefd4fcf8abd6f3 trivial-signal-20190710-git trivial-signal.asd +trivial-sockets http://beta.quicklisp.org/archive/trivial-sockets/2019-01-07/trivial-sockets-20190107-git.tgz 11603 bd56e19a9716b8beb0d482d38fc16472 da768132611e7d7ff0b44212a8011bf17b45e99f trivial-sockets-20190107-git trivial-sockets.asd +trivial-ssh http://beta.quicklisp.org/archive/trivial-ssh/2019-11-30/trivial-ssh-20191130-git.tgz 16118 d1b5dcc547de445a4fde156b66942ab1 001183c4093a3ff5b6133f9f81327f062842d8a5 trivial-ssh-20191130-git trivial-ssh-libssh2.asd trivial-ssh-test.asd trivial-ssh.asd +trivial-string-template http://beta.quicklisp.org/archive/trivial-string-template/2016-10-31/trivial-string-template-20161031-git.tgz 9755 d9836199d9f7a53e1c3e7625c08a6208 cf82a2302fffcbbc86b385e73aba958fd26a6044 trivial-string-template-20161031-git trivial-string-template-test.asd trivial-string-template.asd +trivial-swank http://beta.quicklisp.org/archive/trivial-swank/2018-02-28/trivial-swank-quicklisp-ab90d90f-git.tgz 5553 a5ca451d2b9c5bf338f16f5bbf52fd14 840a996a64f567f46af09caa8213fc7b38fd184a trivial-swank-quicklisp-ab90d90f-git trivial-swank.asd +trivial-tco http://beta.quicklisp.org/archive/trivial-tco/2013-10-03/trivial-tco-20131003-git.tgz 2541 9123b9c05aec84967cb9db6648c958f4 2416c68735324bfec2f53d16abfd76cc29846861 trivial-tco-20131003-git trivial-tco-test.asd trivial-tco.asd +trivial-thumbnail http://beta.quicklisp.org/archive/trivial-thumbnail/2019-07-10/trivial-thumbnail-20190710-git.tgz 5331 c8bfe5f627830e849104d7e0ba54bca6 86865b4054ada83afe01f1a5fbebf35076328215 trivial-thumbnail-20190710-git trivial-thumbnail.asd +trivial-timeout http://beta.quicklisp.org/archive/trivial-timeout/2018-01-31/trivial-timeout-20180131-git.tgz 8556 43a318a74a174a0a5bb0921f650f0727 afe9bd2217f8ebc0c67c9c66d4b3d76a678a4d98 trivial-timeout-20180131-git trivial-timeout.asd +trivial-timer http://beta.quicklisp.org/archive/trivial-timer/2019-10-07/trivial-timer-20191007-git.tgz 5648 5da2440d5bf9b090992aa9df04751858 337112f3b0548401daaa336c0ad865ff259128e0 trivial-timer-20191007-git trivial-timer.asd +trivial-timers http://beta.quicklisp.org/archive/trivial-timers/2010-10-06/trivial-timers-20101006-http.tgz 4064 c2191b98e93888880e7b99c5f3db050e caf09574cc58601410b46b2b03654f0e7742347b trivial-timers-20101006-http trivial-timers.asd +trivial-types http://beta.quicklisp.org/archive/trivial-types/2012-04-07/trivial-types-20120407-git.tgz 3228 b14dbe0564dcea33d8f4e852a612d7db acf9e5a4b0ef99bdcb121cfbc8f07c647c302e57 trivial-types-20120407-git trivial-types.asd +trivial-update http://beta.quicklisp.org/archive/trivial-update/2018-01-31/trivial-update-20180131-git.tgz 2718 d8c0e6814b49272876ea768cd1e46e2f 4b672e0127418b00f5c12a21f24f5db7cc8af279 trivial-update-20180131-git trivial-update.asd +trivial-utf-8 http://beta.quicklisp.org/archive/trivial-utf-8/2011-10-01/trivial-utf-8-20111001-darcs.tgz 6055 0206c4ba7a6c0b9b23762f244aca6614 a6eb987246e5f233c6b9c4b8b15edbbe2770d848 trivial-utf-8-20111001-darcs trivial-utf-8.asd +trivial-utilities http://beta.quicklisp.org/archive/trivial-utilities/2019-10-07/trivial-utilities-20191007-git.tgz 7187 bb0a1b0c7edd5783ff7e2717fde2df60 9a64bfa3b0c977f7d4f4c5856be3a1853a76c3a3 trivial-utilities-20191007-git trivial-utilities.asd +trivial-variable-bindings http://beta.quicklisp.org/archive/trivial-variable-bindings/2019-10-07/trivial-variable-bindings-20191007-git.tgz 4594 13e84f4912598f04d5da6a4bd4c7be5f 8bfa3f68d6b82a13767f88f5595cecc8a6df2d3a trivial-variable-bindings-20191007-git trivial-variable-bindings.asd +trivial-wish http://beta.quicklisp.org/archive/trivial-wish/2017-06-30/trivial-wish-quicklisp-910afeea-git.tgz 3604 37c6d054b8047635f893bcca3b20043f 477cbc87778ab161717f3247495b99ce82d26fe0 trivial-wish-quicklisp-910afeea-git trivial-wish.asd +trivial-with http://beta.quicklisp.org/archive/trivial-with/2017-08-30/trivial-with-quicklisp-2fd8ca54-git.tgz 1554 8b816ed9e2c29f3f8015efb749417e1f ee005208b66ede42608dd15837b701d270932620 trivial-with-quicklisp-2fd8ca54-git trivial-with.asd +trivial-ws http://beta.quicklisp.org/archive/trivial-ws/2018-01-31/trivial-ws-20180131-git.tgz 2798 d94a58b084bfae82b57533be1ab60d22 6b21f895b2401e4b6ba676597db3398d4d45eeaa trivial-ws-20180131-git trivial-ws-client.asd trivial-ws-test.asd trivial-ws.asd +trivial-yenc http://beta.quicklisp.org/archive/trivial-yenc/2016-12-04/trivial-yenc-20161204-git.tgz 24777 3e30073ec4a3aac9eb79bcedd773afd3 63208129d025e58445a65f7da343aaf5a2661d96 trivial-yenc-20161204-git trivial-yenc.asd +trivialib.bdd http://beta.quicklisp.org/archive/trivialib.bdd/2018-03-28/trivialib.bdd-20180328-git.tgz 5701 13f189714290a75342f159476d9df3d1 f71adf02c9caabe16c2f23318d992d67d7c2b25a trivialib.bdd-20180328-git trivialib.bdd.asd trivialib.bdd.test.asd +trivialib.type-unify http://beta.quicklisp.org/archive/trivialib.type-unify/2016-08-25/trivialib.type-unify-20160825-git.tgz 6556 039773d2b44f8c1fd8f517288b88a4ff 6bd076666d819c7e6443509bd6405d7e5d3704c9 trivialib.type-unify-20160825-git trivialib.type-unify.asd trivialib.type-unify.test.asd +twfy http://beta.quicklisp.org/archive/twfy/2013-04-20/twfy-20130420-git.tgz 6872 970b20e4c143014bf2faf5d470e3cf72 3840c3c70a63c07bf225bea595bc196ed243b17c twfy-20130420-git twfy.asd +type-i http://beta.quicklisp.org/archive/type-i/2019-12-27/type-i-20191227-git.tgz 5932 af344179d3f97b836d1e3106f8d1c306 ef2cd7a2e099a2d1c1bc1f5d913a711872735f1b type-i-20191227-git type-i.asd type-i.test.asd +type-r http://beta.quicklisp.org/archive/type-r/2019-12-27/type-r-20191227-git.tgz 10627 9dd5400746e6c8352fc4248e5384669a 82c0916f793c2f678770c2c0152dbd26af130259 type-r-20191227-git type-r.asd type-r.test.asd +uax-14 http://beta.quicklisp.org/archive/uax-14/2019-10-07/uax-14-20191007-git.tgz 130672 6b9518e234152ca5cb540e2ca6b81c17 e9838d6abfd6bc21873d737cc59eacc4aee37b8e uax-14-20191007-git uax-14-test.asd uax-14.asd +uax-9 http://beta.quicklisp.org/archive/uax-9/2019-10-07/uax-9-20191007-git.tgz 1794867 dc653d87a4ddfb75efec85030a074cbc 7cdb719c1cdc1b1724860826c9436f71db9898c8 uax-9-20191007-git uax-9-test.asd uax-9.asd +ubiquitous http://beta.quicklisp.org/archive/ubiquitous/2019-07-10/ubiquitous-20190710-git.tgz 43252 f1300d3ed47beda6abc92ef0d85a8eee 30b0eb81f56864c4e07a916d94a849c72577cd9e ubiquitous-20190710-git ubiquitous-concurrent.asd ubiquitous.asd +ucons http://beta.quicklisp.org/archive/ucons/2019-03-07/ucons-20190307-git.tgz 5200 44d78424883fa78514e14bfd24ddde67 d8fbdea632c3050f1a4bbd2f63b74e1cc0f626c7 ucons-20190307-git code/ucons.asd +ucw http://beta.quicklisp.org/archive/ucw/2016-02-08/ucw-20160208-darcs.tgz 164029 b5a4f28e311b70010bd98be79e544c48 d461b81886f15d368a521ba254c282f224638623 ucw-20160208-darcs ucw-core.asd ucw.asd +uffi http://beta.quicklisp.org/archive/uffi/2018-02-28/uffi-20180228-git.tgz 179928 b0dfb2f966912f4797327948aa7e9119 3fa7b46bc21bcbbc59528bf4c2ea9bda84f57088 uffi-20180228-git uffi-tests.asd uffi.asd +ufo http://beta.quicklisp.org/archive/ufo/2016-12-04/ufo-20161204-git.tgz 5130 bb490f5b3086088cab2746a7c7a102eb ff24b84a9e8f1118e87b77fe8edb002005b91883 ufo-20161204-git ufo-test.asd ufo.asd +ugly-tiny-infix-macro http://beta.quicklisp.org/archive/ugly-tiny-infix-macro/2016-08-25/ugly-tiny-infix-macro-20160825-git.tgz 8284 ed38d0a89cf772f96244934a78bc1ec4 3d5e3f693c1f45322d1c7f6d117fa96a3d9d4557 ugly-tiny-infix-macro-20160825-git ugly-tiny-infix-macro.asd +uiop http://beta.quicklisp.org/archive/uiop/2019-05-21/uiop-3.3.3.tgz 99847 64d561117f048ad8621eff7a6173d65e c044515fda0bcb9d12c1b53ba47f1aee03031f49 uiop-3.3.3 asdf-driver.asd uiop.asd +umbra http://beta.quicklisp.org/archive/umbra/2019-12-27/umbra-20191227-git.tgz 24348 7a8a74b32f35a6541c115af22f20a04e 716e497a8588bd0de7b3c30fa9f5decf78ce5dc1 umbra-20191227-git umbra.asd +umlisp http://beta.quicklisp.org/archive/umlisp/2018-02-28/umlisp-20180228-git.tgz 46926 26b8f39fc0e8833f389a322c41bb7a30 a7fbd8c2636c3dbc182355c9637fb7c90bcd1351 umlisp-20180228-git umlisp-tests.asd umlisp.asd +umlisp-orf http://beta.quicklisp.org/archive/umlisp-orf/2015-09-23/umlisp-orf-20150923-git.tgz 31495 401d1d133f874eccafc76426495bdfc6 340233287e9c9c427e2d0260eb2cb457cb494a56 umlisp-orf-20150923-git umlisp-orf.asd +unicly http://beta.quicklisp.org/archive/unicly/2012-09-09/unicly-20120909-git.tgz 101223 bb1940ca1f2a88b46863874742c7e469 74a73d2f1507e0bd808aefffa5e7519ccadcdfbb unicly-20120909-git unicly.asd +unit-formula http://beta.quicklisp.org/archive/unit-formula/2018-07-11/unit-formula-20180711-git.tgz 22478 4739cdb264153430300215eec7d8a766 43c9faa30a3d9bf36d81be4df653f66c5104a8c2 unit-formula-20180711-git unit-formulas.asd +unit-test http://beta.quicklisp.org/archive/unit-test/2012-05-20/unit-test-20120520-git.tgz 5026 ffcde1c03dd33862cd4f7288649c3cbc a90ba788826db66fb183ef221a2bd57550d66d51 unit-test-20120520-git unit-test.asd +universal-config http://beta.quicklisp.org/archive/universal-config/2018-04-30/universal-config-20180430-git.tgz 18717 ea3d382afa8904aa76d6e3131c89a1b8 b177d9d562fe68db71f805451e6d7e357647d055 universal-config-20180430-git universal-config.asd +unix-options http://beta.quicklisp.org/archive/unix-options/2015-10-31/unix-options-20151031-git.tgz 11220 3bbdeafbef3e7a2e94b9756bf173f636 64c26167d493cca5c981c1c9a3f923f7406d6e25 unix-options-20151031-git unix-options.asd +unix-opts http://beta.quicklisp.org/archive/unix-opts/2018-04-30/unix-opts-20180430-git.tgz 11405 2875ea0a1f5c49ef2697bb1046c4c4e5 4a650a081079badf6f7e93f4f50f5efa2ea77dae unix-opts-20180430-git unix-opts-tests.asd unix-opts.asd +uri-template http://beta.quicklisp.org/archive/uri-template/2019-08-13/uri-template-1.3.1.tgz 20667 2819c38acf5408c90ef2c4f12bfaf73e 42d350f11de6975925bd1aba0878e322836b8817 uri-template-1.3.1 uri-template.asd uri-template.test.asd +url-rewrite http://beta.quicklisp.org/archive/url-rewrite/2017-12-27/url-rewrite-20171227-git.tgz 12733 a27f51e1cd3b62263386c02b07b754b5 16fe74d55e44c734edc7286ac793686150721520 url-rewrite-20171227-git url-rewrite.asd +userial http://beta.quicklisp.org/archive/userial/2011-06-19/userial_0.8.2011.06.02.tgz 25305 18ca2d20cbb483ddb2cb6712387384dc 358b810d26b835ff5a26e1be33aeb6721801d94d userial_0.8.2011.06.02 userial-tests.asd userial.asd +usocket http://beta.quicklisp.org/archive/usocket/2019-12-27/usocket-0.8.3.tgz 85851 b1103034f32565487ab3b6eb92c0ca2b 12cc3af115d1d393cad4eae8e9b3e3aa123617ed usocket-0.8.3 usocket-server.asd usocket-test.asd usocket.asd +utilities.binary-dump http://beta.quicklisp.org/archive/utilities.binary-dump/2018-12-10/utilities.binary-dump-20181210-git.tgz 13155 2f2ae5e2669f8d4f3e0bbea638cf473f 437ea86b8f923e9929ffc644beebc1e687433e9f utilities.binary-dump-20181210-git utilities.binary-dump.asd +utilities.print-items http://beta.quicklisp.org/archive/utilities.print-items/2019-08-13/utilities.print-items-20190813-git.tgz 10205 0f26580bb5d3587ed1815f70976b2a0a 6ac5606c1d28cb88aa5f1c3e861653d738b756dc utilities.print-items-20190813-git utilities.print-items.asd +utilities.print-tree http://beta.quicklisp.org/archive/utilities.print-tree/2017-12-27/utilities.print-tree-20171227-git.tgz 9725 5a730c9e31eeaf14dd40a04fcb1c126e a9d3766bf42b8ffbfa90400e62430cd9612ab7c7 utilities.print-tree-20171227-git utilities.print-tree.asd +utility http://beta.quicklisp.org/archive/utility/2019-02-02/utility-20190202-git.tgz 5158 55e9e5ba352fe19b956af04fa4dc19bc 62360ca825f0bbbbaf2d244698a01cbf75f6e86e utility-20190202-git utility.asd +utility-arguments http://beta.quicklisp.org/archive/utility-arguments/2016-12-04/utility-arguments-20161204-git.tgz 8656 0f60552f326f7164cac4b957e4d48099 9cdfeb9cad7d4e0d84c18ac8f895ce7561bf62e4 utility-arguments-20161204-git utility-arguments.asd +utils-kt http://beta.quicklisp.org/archive/utils-kt/2018-03-28/utils-kt-20180328-git.tgz 17087 d953652f3e3d5bfa076af8d99abf8b6f bd13212a6d0d1e3538d9e0e21fe6d555ca461ee1 utils-kt-20180328-git utils-kt.asd +utm http://beta.quicklisp.org/archive/utm/2018-10-18/utm-20181018-git.tgz 5031 947c9a1da25a77c21cf9417245c0d170 d9f0506f6eb45e71215c986c569ed1d5b5f78331 utm-20181018-git utm.asd utm.test.asd +uuid http://beta.quicklisp.org/archive/uuid/2018-08-31/uuid-20180831-git.tgz 22230 ad7c7cbe9889e1ccd6aea7e63a230919 dbf0542e03040e75c3583c69aa252b5575446d17 uuid-20180831-git uuid.asd +varjo http://beta.quicklisp.org/archive/varjo/2019-10-07/varjo-release-quicklisp-6150bdcb-git.tgz 335430 d7a1a178eb64d77ee41be43c5c62b415 ee6c88aab96f8a3f9d5bf712ef5dde106c46e2ee varjo-release-quicklisp-6150bdcb-git varjo.asd varjo.import.asd varjo.tests.asd +vas-string-metrics http://beta.quicklisp.org/archive/vas-string-metrics/2016-02-08/vas-string-metrics-20160208-git.tgz 6807 5f38d4ee241c11286be6147f481e7fd0 f8d0b6752ab519cc94a92c2371aca239867a4b9f vas-string-metrics-20160208-git test.vas-string-metrics.asd vas-string-metrics.asd +vecto http://beta.quicklisp.org/archive/vecto/2017-12-27/vecto-1.5.tgz 70758 69e6b2f7fa10066d50f9134942afad73 e5c820e88138ed60294d2987002a523ce37e2b02 vecto-1.5 vecto.asd vectometry/vectometry.asd +vector http://beta.quicklisp.org/archive/vector/2013-01-28/vector-20130128-git.tgz 13555 d00644c19ce7e0d1302acda0bf238081 042f916e4c5c4648ab2b8e2d41f164783563522a vector-20130128-git com.elbeno.vector.asd +vectors http://beta.quicklisp.org/archive/vectors/2017-12-27/vectors-20171227-git.tgz 4968 413caa1cced2681421c9ee3438079a7c a52d5b2e5ff875860d90cd76f8cf63650041e60a vectors-20171227-git vectors.asd +verbose http://beta.quicklisp.org/archive/verbose/2019-10-07/verbose-20191007-git.tgz 61584 e3c00fd4bf624d2c6982e1fc4ff2f410 c803731cb2f4bada32b942a19a83034d5b6c0b35 verbose-20191007-git verbose.asd +vernacular http://beta.quicklisp.org/archive/vernacular/2019-11-30/vernacular-20191130-git.tgz 40968 8cd9c408b36fb1a34616cb2d35341cfa f947b87120806fe045a2641f04e0e0be2b3b3055 vernacular-20191130-git vernacular.asd +verrazano http://beta.quicklisp.org/archive/verrazano/2012-09-09/verrazano-20120909-darcs.tgz 154093 fdb516677e8414b3400fd8dd6f91817b 3dfe039d928da642c40544b7418fcc8929a43dae verrazano-20120909-darcs verrazano-runtime.asd verrazano.asd +vertex http://beta.quicklisp.org/archive/vertex/2015-06-08/vertex-20150608-git.tgz 3549 f0e1a725b6733155306c4dd9d8245ea8 27473fcccbf03bd3a904a3c0d04b8c40413c514d vertex-20150608-git vertex-test.asd vertex.asd +vgplot http://beta.quicklisp.org/archive/vgplot/2018-12-10/vgplot-20181210-git.tgz 18197 58711ed4482a29cdc31a3434f59ade7b 0fb4df3cdd8986b89ef01a21bddde9ce24b93874 vgplot-20181210-git vgplot.asd +vom http://beta.quicklisp.org/archive/vom/2016-08-25/vom-20160825-git.tgz 4286 ad16bdc0221b08de371be6ce25ce3d47 4618a41b412c27f8a543c70bef09b49d68d9b1f7 vom-20160825-git vom.asd +water http://beta.quicklisp.org/archive/water/2019-01-07/water-20190107-git.tgz 2387 8340d15004bc9b07d822eb08d73846d7 679bc44d0f73f8963f5ced8211c3abd45e7cb8b8 water-20190107-git water.asd +weblocks http://beta.quicklisp.org/archive/weblocks/2018-02-28/weblocks-20180228-git.tgz 312275 b6f3ca9a3ded521dafa271773a659883 e416f64744e54eb0e7cb6e199c09d3b797ea21b3 weblocks-20180228-git contrib/jwr/yui/weblocks-yui.asd contrib/s11001001/weblocks-s11.asd contrib/yarek/examples/weblocks-demo-popover/weblocks-demo-popover.asd contrib/yarek/weblocks-yarek.asd weblocks-scripts.asd weblocks-test.asd weblocks-util.asd weblocks.asd +weblocks-examples http://beta.quicklisp.org/archive/weblocks-examples/2017-04-03/weblocks-examples-20170403-git.tgz 375952 1b9270e0836945d03becda9cdb5187a6 ed2905772b09a5f2b2a053c3e6c080f8384e45bd weblocks-examples-20170403-git simple-blog/simple-blog.asd weblocks-clsql-demo/weblocks-clsql-demo.asd weblocks-demo/weblocks-demo.asd +weblocks-prototype-js http://beta.quicklisp.org/archive/weblocks-prototype-js/2016-09-29/weblocks-prototype-js-20160929-git.tgz 90118 d0771a1127d33de4a5151f53e728dd1c 507c4195da245c61e9cbd80863039b51661b8dc7 weblocks-prototype-js-20160929-git weblocks-prototype-js.asd +weblocks-stores http://beta.quicklisp.org/archive/weblocks-stores/2016-12-08/weblocks-stores-20161208-git.tgz 25350 e1af85f0729db0461ae83c659b2532cd 55f2582051f6490ec3e505ddc8c81edb063794c8 weblocks-stores-20161208-git src/store/clsql/weblocks-clsql.asd src/store/custom/weblocks-custom.asd src/store/memory/weblocks-memory.asd src/store/montezuma/weblocks-montezuma.asd src/store/perec/weblocks-perec.asd src/store/postmodern/weblocks-postmodern.asd src/store/prevalence/weblocks-prevalence.asd weblocks-store-test.asd weblocks-stores.asd +weblocks-tree-widget http://beta.quicklisp.org/archive/weblocks-tree-widget/2014-12-17/weblocks-tree-widget-20141217-git.tgz 10153 5b1d46fcd648d745bbaff396d3f36146 3c7ebac35e2c49ca5f288b84449f247475450854 weblocks-tree-widget-20141217-git weblocks-tree-widget.asd +weblocks-utils http://beta.quicklisp.org/archive/weblocks-utils/2017-01-24/weblocks-utils-20170124-git.tgz 15494 6434a0c9e0384261c38a620b4beeca8a d73a491d6787b8338f269427c1d0e740e5de042b weblocks-utils-20170124-git weblocks-utils.asd +websocket-driver http://beta.quicklisp.org/archive/websocket-driver/2019-01-07/websocket-driver-20190107-git.tgz 11394 d1504b09817ad229459d33120e9c52a1 7a704d461b3cde4dd89b4eab9d738a52bfcdae31 websocket-driver-20190107-git websocket-driver-base.asd websocket-driver-client.asd websocket-driver-server.asd websocket-driver.asd +weft http://beta.quicklisp.org/archive/weft/2018-02-28/weft-20180228-git.tgz 6282 ec7196f159294035d3c06b5723920058 d9ea5ff22d830c1f0deb6fd047e4b62ec280c74c weft-20180228-git weft.asd +westbrook http://beta.quicklisp.org/archive/westbrook/2018-01-31/westbrook-20180131-git.tgz 3249 43e514336921135f6fc3c1b3063eaf4b 97ed8af62728b92027a7321387a64b918475ca7c westbrook-20180131-git westbrook-tests.asd westbrook.asd +what3words http://beta.quicklisp.org/archive/what3words/2016-12-04/what3words-20161204-git.tgz 5600 54303b21497ffca394575c7376c8b9f3 7b37b1c4c32ab419d4f07cf6f1798f4a0b69b88f what3words-20161204-git what3words.asd +which http://beta.quicklisp.org/archive/which/2016-04-21/which-20160421-git.tgz 2063 d352101dca7f6e985c0e437bcdb6fe40 528a7fdbb3c1485e5685145fd0023ece6a9b32c5 which-20160421-git which-test.asd which.asd +whofields http://beta.quicklisp.org/archive/whofields/2018-08-31/whofields-20180831-git.tgz 5512 5679091e30971df0d7aae59146a3b1c6 520ef39d46eed4734d891be27a44fadd80b54ae4 whofields-20180831-git whofields.asd +wild-package-inferred-system http://beta.quicklisp.org/archive/wild-package-inferred-system/2019-01-07/wild-package-inferred-system-20190107-git.tgz 9603 5699a756f42960ef0c7ed450572e2f08 fbd51d7acb33d182d3b105fa01b7f4013bcbded8 wild-package-inferred-system-20190107-git test/foo-wild/foo-wild.asd wild-package-inferred-system.asd +winhttp http://beta.quicklisp.org/archive/winhttp/2019-01-07/winhttp-20190107-git.tgz 13864 03ad3ec6a6f5ca7f86fe4956dba43021 f2a6ac37a949396ed7898af1ffcb7f56ace0a2a1 winhttp-20190107-git winhttp.asd +winlock http://beta.quicklisp.org/archive/winlock/2019-11-30/winlock-20191130-git.tgz 3577 f637484323c2b64fc680325bcadef786 fc646ddf5184afcbf5c84370b68087120a63e7bd winlock-20191130-git winlock.asd +with-c-syntax http://beta.quicklisp.org/archive/with-c-syntax/2019-05-21/with-c-syntax-20190521-git.tgz 59911 7cf31666dd69c8cde2471fabeb593733 46347e74d5741633ee26723301c3b11c3be4c3b6 with-c-syntax-20190521-git with-c-syntax-test.asd with-c-syntax.asd +with-cached-reader-conditionals http://beta.quicklisp.org/archive/with-cached-reader-conditionals/2017-06-30/with-cached-reader-conditionals-20170630-git.tgz 2457 16049564ecfdb5a6db9edd1bdcf0a921 4be7101d32ea9f59c716ce5b822a58e0bb124a05 with-cached-reader-conditionals-20170630-git with-cached-reader-conditionals.asd +with-output-to-stream http://beta.quicklisp.org/archive/with-output-to-stream/2019-10-07/with-output-to-stream_1.0.tgz 4266 d9bee5027d6c04bcd7f63f4c48706f5c a3b23295277552cf9dd81191edd50ed8019a1c67 with-output-to-stream_1.0 tests/with-output-to-stream_tests.asd with-output-to-stream.asd +with-setf http://beta.quicklisp.org/archive/with-setf/2018-02-28/with-setf-release-quicklisp-df3eed9d-git.tgz 2558 9218b3765e9e2fd26a7f103e63fc89fe a6db3e7df0bb1b289e2134d8668be0ff51b4389e with-setf-release-quicklisp-df3eed9d-git with-setf.asd +with-shadowed-bindings http://beta.quicklisp.org/archive/with-shadowed-bindings/2019-01-07/with-shadowed-bindings-1.0.tgz 5127 1f583c77f5d2c67c934ab33d2ba810c3 a786cd36c9aee7348f63f7d6fe482225a728ccb2 with-shadowed-bindings-1.0 tests/with-shadowed-bindings_tests.asd with-shadowed-bindings.asd +with-user-abort http://beta.quicklisp.org/archive/with-user-abort/2019-11-30/with-user-abort-20191130-git.tgz 962 b66699b4f17ac57a0dfd3d4dc12c287b 1cdb0588df587008e8c151e547975707ba56c9e0 with-user-abort-20191130-git with-user-abort.asd +woo http://beta.quicklisp.org/archive/woo/2019-11-30/woo-20191130-git.tgz 225538 a876d194ed1ccb7439e3f3b6da63760e 1c4d4a1928361e61fc45518b6bcaf1f094484470 woo-20191130-git clack-handler-woo.asd woo-test.asd woo.asd +wookie http://beta.quicklisp.org/archive/wookie/2019-11-30/wookie-20191130-git.tgz 29738 5e5d6537637312919fd528bb1d0c1eba 660d6b8277d9bc3a82aeb0db51bb2d51e71a3678 wookie-20191130-git wookie.asd +wordnet http://beta.quicklisp.org/archive/wordnet/2019-05-21/wordnet-20190521-git.tgz 10484879 ee0272f4d2fa645dd13d555d759a3345 8638e9e3ac07cdbacab95baa0f03a5d20ecc83e9 wordnet-20190521-git wordnet.asd +workout-timer http://beta.quicklisp.org/archive/workout-timer/2017-12-27/workout-timer-20171227-git.tgz 319162 b5dc79cd91c6d2a4aed6f67a244bff9a d99a5b7d16a1b94b17b0c248b5bb4e1873d7dff8 workout-timer-20171227-git workout-timer.asd +wu-decimal http://beta.quicklisp.org/archive/wu-decimal/2013-01-28/wu-decimal-20130128-git.tgz 6244 e0676ea5ba7ce65e4d80cc5128c1e668 b37c145557a1b9541f9219629c1091976dc2656f wu-decimal-20130128-git wu-decimal.asd +wu-sugar http://beta.quicklisp.org/archive/wu-sugar/2016-08-25/wu-sugar-20160825-git.tgz 3555 ef7aec6772cda55c04bf117a2a8cb4ac a2dde559d7e28bdaa93dfcf0e1f080447873c9d3 wu-sugar-20160825-git wu-sugar.asd +wuwei http://beta.quicklisp.org/archive/wuwei/2019-02-02/wuwei-20190202-git.tgz 140953 e389c75644b0a8a5900e21e0daecfcd8 da295007ea36414aabdd389c4fff3aa3a40b10ce wuwei-20190202-git wuwei.asd +x.fdatatypes http://beta.quicklisp.org/archive/x.fdatatypes/2015-07-09/x.fdatatypes-20150709-git.tgz 15713 45c2b2939107acb4a07fbf66a1479750 8f58da1f8c5fb55a797b6458f81033ebe3caf9c4 x.fdatatypes-20150709-git x.fdatatypes-iterate.asd x.fdatatypes.asd +x.let-star http://beta.quicklisp.org/archive/x.let-star/2015-07-09/x.let-star-20150709-git.tgz 7921 2a0f7fbf6a621cd121020e140af08ded c66f72bf9b9e42964818dcc75c322203a262c52b x.let-star-20150709-git x.let-star.asd +xarray http://beta.quicklisp.org/archive/xarray/2014-01-13/xarray-20140113-git.tgz 26181 477bb421f87f6de0236065bf81949a32 5466b0687c3ac4a6466d2761b9d29510658785bb xarray-20140113-git xarray-test.asd xarray.asd +xecto http://beta.quicklisp.org/archive/xecto/2015-12-18/xecto-20151218-git.tgz 29803 f770596c9d7a9ce86fb2d7952bc9e40e 489a3f39048451dfaab304a73681d5f8ce779a8b xecto-20151218-git xecto.asd +xhtmlambda http://beta.quicklisp.org/archive/xhtmlambda/2019-01-07/xhtmlambda-20190107-git.tgz 49855 70ddb72e53acf4cfe8eb5610164e28f5 7c03dc39b2d88d62be563748aca9c86613c1c84c xhtmlambda-20190107-git xhtmlambda.asd +xhtmlgen http://beta.quicklisp.org/archive/xhtmlgen/2017-01-24/xhtmlgen-20170124-git.tgz 4264 17fc90eab99b1fb0cf6335065e84c109 bbb503e316f419d7cffb2f3f648e0227bc61cb15 xhtmlgen-20170124-git xhtmlgen.asd +xlsx http://beta.quicklisp.org/archive/xlsx/2018-07-11/xlsx-20180711-git.tgz 3050 10133595e8973f9acdd0301c00d04f8c 5a5dc8579c348ffae3625fbb088aa4ee008e3eaf xlsx-20180711-git xlsx.asd +xlunit http://beta.quicklisp.org/archive/xlunit/2015-09-23/xlunit-20150923-git.tgz 9484 1c673862f57e998c7a7b8e74de0d0c92 de0142632a8227f339178055eb5543a0c8dce789 xlunit-20150923-git xlunit.asd +xml-emitter http://beta.quicklisp.org/archive/xml-emitter/2019-11-30/xml-emitter-20191130-git.tgz 6734 6976af2c99934b14486c754dae996801 2895936a28c46607a5fb737b29d80c8e7f25a0df xml-emitter-20191130-git xml-emitter.asd +xml-mop http://beta.quicklisp.org/archive/xml-mop/2011-04-18/xml-mop-20110418-git.tgz 15391 028fde76c0d121865cb5167962a4b78b f5fb4a43a2defedb352b072be94d4c22f433dfc3 xml-mop-20110418-git xml-mop.asd +xml.location http://beta.quicklisp.org/archive/xml.location/2018-08-31/xml.location-20180831-git.tgz 31123 ad828a5b218d4a88e9e102ad534920ed 4679296b59b742a41b58a8d8f4be5e5e0a08be2c xml.location-20180831-git xml.location-and-local-time.asd xml.location.asd +xmls http://beta.quicklisp.org/archive/xmls/2018-04-30/xmls-3.0.2.tgz 113037 2462bab4a5d74e87ef7bdef41cd06dc8 80181e6c0ac15a4a41eb352b50b871679c65ab4d xmls-3.0.2 xmls.asd +xptest http://beta.quicklisp.org/archive/xptest/2015-09-23/xptest-20150923-git.tgz 6874 61f6ff5cc44cf8da5d8036084a31fbc3 09eebbc1fa611a9b628c9d2de12f6c81bf4420b8 xptest-20150923-git xptest.asd +xsubseq http://beta.quicklisp.org/archive/xsubseq/2017-08-30/xsubseq-20170830-git.tgz 4006 960bb8f329649b6e4b820e065e6b38e8 77ef22871e590349e22e892cd8f80121db1b1566 xsubseq-20170830-git xsubseq-test.asd xsubseq.asd +xuriella http://beta.quicklisp.org/archive/xuriella/2012-03-05/xuriella-20120305-git.tgz 122204 55eb6e13da338bc47b640a2767b0bd20 49899b4682e3a72322c69feb21ced8a109675833 xuriella-20120305-git xuriella.asd +yaclml http://beta.quicklisp.org/archive/yaclml/2018-01-31/yaclml-20180131-git.tgz 32006 b3dba0cd334aef4fc75b465b2b31a94a 76172119d82a08b4483721cc6746228c8d9b8079 yaclml-20180131-git yaclml.asd +yason http://beta.quicklisp.org/archive/yason/2019-12-27/yason-v0.7.8.tgz 27918 7c3231635aa494f1721273713ea8c56a ac532785adb017b0eecdd6dfa9b3ab1add7100f9 yason-v0.7.8 yason.asd +youtube http://beta.quicklisp.org/archive/youtube/2019-12-27/youtube-20191227-git.tgz 3054 36af0a0118f51e4e57d1dee28f720a44 dc8b73c9c8d14ba29827baf8ef5bda3b0a25d275 youtube-20191227-git youtube.asd +zacl http://beta.quicklisp.org/archive/zacl/2018-12-10/zacl-20181210-git.tgz 20817 08bff0310769f27a0d24ad7ebd8ae924 315cf8c605344323d082cdcd0bb82c6dfd59c697 zacl-20181210-git zacl.asd +zaws http://beta.quicklisp.org/archive/zaws/2015-04-07/zaws-20150407-git.tgz 13832 13ada144680e2f5d111df8f0a0217d99 8d181469163fac8b77280c98c5ab28ca7098fe4b zaws-20150407-git xml/zaws-xml.asd zaws.asd +zbucium http://beta.quicklisp.org/archive/zbucium/2019-07-10/zbucium-20190710-git.tgz 4503 90b10e33e3fa82d42174016881d557bc d0e1df0c25eb87e1e0e66af27fd2dac5b20c7fb4 zbucium-20190710-git zbucium.asd +zcdb http://beta.quicklisp.org/archive/zcdb/2015-04-07/zcdb-1.0.4.tgz 7393 e924c2b419f9875364cd662184fc55d1 db5f7a8e8a22f858794b64ef255f7dea015835f8 zcdb-1.0.4 zcdb.asd +zenekindarl http://beta.quicklisp.org/archive/zenekindarl/2017-11-30/zenekindarl-20171130-git.tgz 17395 2c8e9002b6434d92761ced8e187c5903 0a732633d8173828feec7a8b5eaab103de638e7f zenekindarl-20171130-git zenekindarl-test.asd zenekindarl.asd +zip http://beta.quicklisp.org/archive/zip/2015-06-08/zip-20150608-git.tgz 20940 5be194863779dcbd3c83e07524392f14 a8fa33dc2a19df78942e02c0e35a78f054992bd7 zip-20150608-git zip.asd +ziz http://beta.quicklisp.org/archive/ziz/2019-10-07/ziz-20191007-git.tgz 3184 24b32be09b15855c77b6fddc2d6d6ea3 f9d30703cd655564a12063a77b466930cd52a41d ziz-20191007-git ziz.asd +zlib http://beta.quicklisp.org/archive/zlib/2017-04-03/zlib-20170403-git.tgz 9104 67450036249df47288f4a8330ea28f57 498b41ab3e46c63d5f0ae3ece8eeb47c95009bad zlib-20170403-git zlib.asd +zpb-exif http://beta.quicklisp.org/archive/zpb-exif/2015-04-07/zpb-exif-1.2.3.tgz 15564 f2286ce8d693823e55886c2cd5d73390 69dfc9d86bdf5bd858815c453da0db024556dcfe zpb-exif-1.2.3 zpb-exif.asd +zpb-ttf http://beta.quicklisp.org/archive/zpb-ttf/2013-07-20/zpb-ttf-1.0.3.tgz 44869 1e896d8b0b01babab882e43fe4c3c2d4 f144607522f1fd0914e5576581b459e017cbde9f zpb-ttf-1.0.3 zpb-ttf.asd +zpng http://beta.quicklisp.org/archive/zpng/2015-04-07/zpng-1.2.2.tgz 40141 0a208f4ce0087ef578d477341d5f4078 0374a5e03f266152dea01c6fff9839798725697c zpng-1.2.2 zpng.asd +zs3 http://beta.quicklisp.org/archive/zs3/2019-10-07/zs3-1.3.3.tgz 57149 5ea13aa7a490758882e245c3f8bb063e 8b3bcc4f7a524ca09f3b6fa6600c510e1f2d9e3b zs3-1.3.3 zs3.asd +zsort http://beta.quicklisp.org/archive/zsort/2012-05-20/zsort-20120520-git.tgz 6259 08689032aed3f283c9ab84b536d0aca3 5b8b68c44983d394a8328f30cdc2b8fb6c96331a zsort-20120520-git zsort.asd diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/.boring b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/.boring new file mode 100644 index 0000000..dfa9e6d --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/.boring @@ -0,0 +1,13 @@ +# Boring file regexps: +~$ +^_darcs +^\{arch\} +^.arch-ids +\# +\.dfsl$ +\.ppcf$ +\.fasl$ +\.x86f$ +\.fas$ +\.lib$ +^public_html diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/.gitignore b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/.gitignore new file mode 100644 index 0000000..e832e94 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/.gitignore @@ -0,0 +1,4 @@ +*.fasl +*~ +\#* +*.patch diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/AUTHORS b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/AUTHORS new file mode 100644 index 0000000..b550ea5 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/AUTHORS @@ -0,0 +1,9 @@ + +ACTA EST FABULA PLAUDITE + +Nikodemus Siivola +Attila Lendvai +Marco Baringer +Robert Strandh +Luis Oliveira +Tobias C. Rittweiler \ No newline at end of file diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/LICENCE b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/LICENCE new file mode 100644 index 0000000..b5140fb --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/LICENCE @@ -0,0 +1,37 @@ +Alexandria software and associated documentation are in the public +domain: + + Authors dedicate this work to public domain, for the benefit of the + public at large and to the detriment of the authors' heirs and + successors. Authors intends this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights under + copyright law, whether vested or contingent, in the work. Authors + understands that such relinquishment of all rights includes the + relinquishment of all rights to enforce (by lawsuit or otherwise) + those copyrights in the work. + + Authors recognize that, once placed in the public domain, the work + may be freely reproduced, distributed, transmitted, used, modified, + built upon, or otherwise exploited by anyone for any purpose, + commercial or non-commercial, and in any way, including by methods + that have not yet been invented or conceived. + +In those legislations where public domain dedications are not +recognized or possible, Alexandria is distributed under the following +terms and conditions: + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/README b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/README new file mode 100644 index 0000000..59e49ab --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/README @@ -0,0 +1,52 @@ +Alexandria is a collection of portable public domain utilities that +meet the following constraints: + + * Utilities, not extensions: Alexandria will not contain conceptual + extensions to Common Lisp, instead limiting itself to tools and + utilities that fit well within the framework of standard ANSI + Common Lisp. Test-frameworks, system definitions, logging + facilities, serialization layers, etc. are all outside the scope of + Alexandria as a library, though well within the scope of Alexandria + as a project. + + * Conservative: Alexandria limits itself to what project members + consider conservative utilities. Alexandria does not and will not + include anaphoric constructs, loop-like binding macros, etc. + + * Portable: Alexandria limits itself to portable parts of Common + Lisp. Even apparently conservative and useful functions remain + outside the scope of Alexandria if they cannot be implemented + portably. Portability is here defined as portable within a + conforming implementation: implementation bugs are not considered + portability issues. + +Homepage: + + http://common-lisp.net/project/alexandria/ + +Mailing lists: + + http://lists.common-lisp.net/mailman/listinfo/alexandria-devel + http://lists.common-lisp.net/mailman/listinfo/alexandria-cvs + +Repository: + + git://common-lisp.net/projects/alexandria/alexandria.git + +Documentation: + + http://common-lisp.net/project/alexandria/draft/alexandria.html + + (To build docs locally: cd doc && make html pdf info) + +Patches: + + Patches are always welcome! Please send them to the mailing list as + attachments, generated by "git format-patch -1". + + Patches should include a commit message that explains what's being + done and /why/, and when fixing a bug or adding a feature you should + also include a test-case. + + Be advised though that right now new features are unlikely to be + accepted until 1.0 is officially out of the door. diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/alexandria-tests.asd b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/alexandria-tests.asd new file mode 100644 index 0000000..445c18c --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/alexandria-tests.asd @@ -0,0 +1,11 @@ +(defsystem "alexandria-tests" + :licence "Public Domain / 0-clause MIT" + :description "Tests for Alexandria, which is a collection of portable public domain utilities." + :author "Nikodemus Siivola , and others." + :depends-on (:alexandria #+sbcl :sb-rt #-sbcl :rt) + :components ((:file "tests")) + :perform (test-op (o c) + (flet ((run-tests (&rest args) + (apply (intern (string '#:run-tests) '#:alexandria-tests) args))) + (run-tests :compiled nil) + (run-tests :compiled t)))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/alexandria.asd b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/alexandria.asd new file mode 100644 index 0000000..db10e4f --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/alexandria.asd @@ -0,0 +1,62 @@ +(defsystem "alexandria" + :version "1.0.0" + :licence "Public Domain / 0-clause MIT" + :description "Alexandria is a collection of portable public domain utilities." + :author "Nikodemus Siivola and others." + :long-description + "Alexandria is a project and a library. + +As a project Alexandria's goal is to reduce duplication of effort and improve +portability of Common Lisp code according to its own idiosyncratic and rather +conservative aesthetic. + +As a library Alexandria is one of the means by which the project strives for +its goals. + +Alexandria is a collection of portable public domain utilities that meet +the following constraints: + + * Utilities, not extensions: Alexandria will not contain conceptual + extensions to Common Lisp, instead limiting itself to tools and utilities + that fit well within the framework of standard ANSI Common Lisp. + Test-frameworks, system definitions, logging facilities, serialization + layers, etc. are all outside the scope of Alexandria as a library, though + well within the scope of Alexandria as a project. + + * Conservative: Alexandria limits itself to what project members consider + conservative utilities. Alexandria does not and will not include anaphoric + constructs, loop-like binding macros, etc. + Also, its exported symbols are being imported by many other packages + already, so each new export carries the danger of causing conflicts. + + * Portable: Alexandria limits itself to portable parts of Common Lisp. Even + apparently conservative and useful functions remain outside the scope of + Alexandria if they cannot be implemented portably. Portability is here + defined as portable within a conforming implementation: implementation bugs + are not considered portability issues. + + * Team player: Alexandria will not (initially, at least) subsume or provide + functionality for which good-quality special-purpose packages exist, like + split-sequence. Instead, third party packages such as that may be + \"blessed\"." + :components + ((:static-file "LICENCE") + (:static-file "tests.lisp") + (:file "package") + (:file "definitions" :depends-on ("package")) + (:file "binding" :depends-on ("package")) + (:file "strings" :depends-on ("package")) + (:file "conditions" :depends-on ("package")) + (:file "io" :depends-on ("package" "macros" "lists" "types")) + (:file "macros" :depends-on ("package" "strings" "symbols")) + (:file "hash-tables" :depends-on ("package" "macros")) + (:file "control-flow" :depends-on ("package" "definitions" "macros")) + (:file "symbols" :depends-on ("package")) + (:file "functions" :depends-on ("package" "symbols" "macros")) + (:file "lists" :depends-on ("package" "functions")) + (:file "types" :depends-on ("package" "symbols" "lists")) + (:file "arrays" :depends-on ("package" "types")) + (:file "sequences" :depends-on ("package" "lists" "types")) + (:file "numbers" :depends-on ("package" "sequences")) + (:file "features" :depends-on ("package" "control-flow"))) + :in-order-to ((test-op (test-op "alexandria-tests")))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/arrays.lisp b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/arrays.lisp new file mode 100644 index 0000000..76c1879 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/arrays.lisp @@ -0,0 +1,18 @@ +(in-package :alexandria) + +(defun copy-array (array &key (element-type (array-element-type array)) + (fill-pointer (and (array-has-fill-pointer-p array) + (fill-pointer array))) + (adjustable (adjustable-array-p array))) + "Returns an undisplaced copy of ARRAY, with same fill-pointer and +adjustability (if any) as the original, unless overridden by the keyword +arguments." + (let* ((dimensions (array-dimensions array)) + (new-array (make-array dimensions + :element-type element-type + :adjustable adjustable + :fill-pointer fill-pointer))) + (dotimes (i (array-total-size array)) + (setf (row-major-aref new-array i) + (row-major-aref array i))) + new-array)) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/binding.lisp b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/binding.lisp new file mode 100644 index 0000000..37a3d52 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/binding.lisp @@ -0,0 +1,90 @@ +(in-package :alexandria) + +(defmacro if-let (bindings &body (then-form &optional else-form)) + "Creates new variable bindings, and conditionally executes either +THEN-FORM or ELSE-FORM. ELSE-FORM defaults to NIL. + +BINDINGS must be either single binding of the form: + + (variable initial-form) + +or a list of bindings of the form: + + ((variable-1 initial-form-1) + (variable-2 initial-form-2) + ... + (variable-n initial-form-n)) + +All initial-forms are executed sequentially in the specified order. Then all +the variables are bound to the corresponding values. + +If all variables were bound to true values, the THEN-FORM is executed with the +bindings in effect, otherwise the ELSE-FORM is executed with the bindings in +effect." + (let* ((binding-list (if (and (consp bindings) (symbolp (car bindings))) + (list bindings) + bindings)) + (variables (mapcar #'car binding-list))) + `(let ,binding-list + (if (and ,@variables) + ,then-form + ,else-form)))) + +(defmacro when-let (bindings &body forms) + "Creates new variable bindings, and conditionally executes FORMS. + +BINDINGS must be either single binding of the form: + + (variable initial-form) + +or a list of bindings of the form: + + ((variable-1 initial-form-1) + (variable-2 initial-form-2) + ... + (variable-n initial-form-n)) + +All initial-forms are executed sequentially in the specified order. Then all +the variables are bound to the corresponding values. + +If all variables were bound to true values, then FORMS are executed as an +implicit PROGN." + (let* ((binding-list (if (and (consp bindings) (symbolp (car bindings))) + (list bindings) + bindings)) + (variables (mapcar #'car binding-list))) + `(let ,binding-list + (when (and ,@variables) + ,@forms)))) + +(defmacro when-let* (bindings &body body) + "Creates new variable bindings, and conditionally executes BODY. + +BINDINGS must be either single binding of the form: + + (variable initial-form) + +or a list of bindings of the form: + + ((variable-1 initial-form-1) + (variable-2 initial-form-2) + ... + (variable-n initial-form-n)) + +Each INITIAL-FORM is executed in turn, and the variable bound to the +corresponding value. INITIAL-FORM expressions can refer to variables +previously bound by the WHEN-LET*. + +Execution of WHEN-LET* stops immediately if any INITIAL-FORM evaluates to NIL. +If all INITIAL-FORMs evaluate to true, then BODY is executed as an implicit +PROGN." + (let ((binding-list (if (and (consp bindings) (symbolp (car bindings))) + (list bindings) + bindings))) + (labels ((bind (bindings body) + (if bindings + `(let (,(car bindings)) + (when ,(caar bindings) + ,(bind (cdr bindings) body))) + `(progn ,@body)))) + (bind binding-list body)))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/conditions.lisp b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/conditions.lisp new file mode 100644 index 0000000..ac471cc --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/conditions.lisp @@ -0,0 +1,91 @@ +(in-package :alexandria) + +(defun required-argument (&optional name) + "Signals an error for a missing argument of NAME. Intended for +use as an initialization form for structure and class-slots, and +a default value for required keyword arguments." + (error "Required argument ~@[~S ~]missing." name)) + +(define-condition simple-style-warning (simple-warning style-warning) + ()) + +(defun simple-style-warning (message &rest args) + (warn 'simple-style-warning :format-control message :format-arguments args)) + +;; We don't specify a :report for simple-reader-error to let the +;; underlying implementation report the line and column position for +;; us. Unfortunately this way the message from simple-error is not +;; displayed, unless there's special support for that in the +;; implementation. But even then it's still inspectable from the +;; debugger... +(define-condition simple-reader-error + #-sbcl(simple-error reader-error) + #+sbcl(sb-int:simple-reader-error) + ()) + +(defun simple-reader-error (stream message &rest args) + (error 'simple-reader-error + :stream stream + :format-control message + :format-arguments args)) + +(define-condition simple-parse-error (simple-error parse-error) + ()) + +(defun simple-parse-error (message &rest args) + (error 'simple-parse-error + :format-control message + :format-arguments args)) + +(define-condition simple-program-error (simple-error program-error) + ()) + +(defun simple-program-error (message &rest args) + (error 'simple-program-error + :format-control message + :format-arguments args)) + +(defmacro ignore-some-conditions ((&rest conditions) &body body) + "Similar to CL:IGNORE-ERRORS but the (unevaluated) CONDITIONS +list determines which specific conditions are to be ignored." + `(handler-case + (progn ,@body) + ,@(loop for condition in conditions collect + `(,condition (c) (values nil c))))) + +(defmacro unwind-protect-case ((&optional abort-flag) protected-form &body clauses) + "Like CL:UNWIND-PROTECT, but you can specify the circumstances that +the cleanup CLAUSES are run. + + clauses ::= (:NORMAL form*)* | (:ABORT form*)* | (:ALWAYS form*)* + +Clauses can be given in any order, and more than one clause can be +given for each circumstance. The clauses whose denoted circumstance +occured, are executed in the order the clauses appear. + +ABORT-FLAG is the name of a variable that will be bound to T in +CLAUSES if the PROTECTED-FORM aborted preemptively, and to NIL +otherwise. + +Examples: + + (unwind-protect-case () + (protected-form) + (:normal (format t \"This is only evaluated if PROTECTED-FORM executed normally.~%\")) + (:abort (format t \"This is only evaluated if PROTECTED-FORM aborted preemptively.~%\")) + (:always (format t \"This is evaluated in either case.~%\"))) + + (unwind-protect-case (aborted-p) + (protected-form) + (:always (perform-cleanup-if aborted-p))) +" + (check-type abort-flag (or null symbol)) + (let ((gflag (gensym "FLAG+"))) + `(let ((,gflag t)) + (unwind-protect (multiple-value-prog1 ,protected-form (setf ,gflag nil)) + (let ,(and abort-flag `((,abort-flag ,gflag))) + ,@(loop for (cleanup-kind . forms) in clauses + collect (ecase cleanup-kind + (:normal `(when (not ,gflag) ,@forms)) + (:abort `(when ,gflag ,@forms)) + (:always `(progn ,@forms))))))))) \ No newline at end of file diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/control-flow.lisp b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/control-flow.lisp new file mode 100644 index 0000000..dd00df3 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/control-flow.lisp @@ -0,0 +1,106 @@ +(in-package :alexandria) + +(defun extract-function-name (spec) + "Useful for macros that want to mimic the functional interface for functions +like #'eq and 'eq." + (if (and (consp spec) + (member (first spec) '(quote function))) + (second spec) + spec)) + +(defun generate-switch-body (whole object clauses test key &optional default) + (with-gensyms (value) + (setf test (extract-function-name test)) + (setf key (extract-function-name key)) + (when (and (consp default) + (member (first default) '(error cerror))) + (setf default `(,@default "No keys match in SWITCH. Testing against ~S with ~S." + ,value ',test))) + `(let ((,value (,key ,object))) + (cond ,@(mapcar (lambda (clause) + (if (member (first clause) '(t otherwise)) + (progn + (when default + (error "Multiple default clauses or illegal use of a default clause in ~S." + whole)) + (setf default `(progn ,@(rest clause))) + '(())) + (destructuring-bind (key-form &body forms) clause + `((,test ,value ,key-form) + ,@forms)))) + clauses) + (t ,default))))) + +(defmacro switch (&whole whole (object &key (test 'eql) (key 'identity)) + &body clauses) + "Evaluates first matching clause, returning its values, or evaluates and +returns the values of T or OTHERWISE if no keys match." + (generate-switch-body whole object clauses test key)) + +(defmacro eswitch (&whole whole (object &key (test 'eql) (key 'identity)) + &body clauses) + "Like SWITCH, but signals an error if no key matches." + (generate-switch-body whole object clauses test key '(error))) + +(defmacro cswitch (&whole whole (object &key (test 'eql) (key 'identity)) + &body clauses) + "Like SWITCH, but signals a continuable error if no key matches." + (generate-switch-body whole object clauses test key '(cerror "Return NIL from CSWITCH."))) + +(defmacro whichever (&rest possibilities &environment env) + "Evaluates exactly one of POSSIBILITIES, chosen at random." + (setf possibilities (mapcar (lambda (p) (macroexpand p env)) possibilities)) + (if (every (lambda (p) (constantp p)) possibilities) + `(svref (load-time-value (vector ,@possibilities)) (random ,(length possibilities))) + (labels ((expand (possibilities position random-number) + (if (null (cdr possibilities)) + (car possibilities) + (let* ((length (length possibilities)) + (half (truncate length 2)) + (second-half (nthcdr half possibilities)) + (first-half (butlast possibilities (- length half)))) + `(if (< ,random-number ,(+ position half)) + ,(expand first-half position random-number) + ,(expand second-half (+ position half) random-number)))))) + (with-gensyms (random-number) + (let ((length (length possibilities))) + `(let ((,random-number (random ,length))) + ,(expand possibilities 0 random-number))))))) + +(defmacro xor (&rest datums) + "Evaluates its arguments one at a time, from left to right. If more than one +argument evaluates to a true value no further DATUMS are evaluated, and NIL is +returned as both primary and secondary value. If exactly one argument +evaluates to true, its value is returned as the primary value after all the +arguments have been evaluated, and T is returned as the secondary value. If no +arguments evaluate to true NIL is retuned as primary, and T as secondary +value." + (with-gensyms (xor tmp true) + `(let (,tmp ,true) + (block ,xor + ,@(mapcar (lambda (datum) + `(if (setf ,tmp ,datum) + (if ,true + (return-from ,xor (values nil nil)) + (setf ,true ,tmp)))) + datums) + (return-from ,xor (values ,true t)))))) + +(defmacro nth-value-or (nth-value &body forms) + "Evaluates FORM arguments one at a time, until the NTH-VALUE returned by one +of the forms is true. It then returns all the values returned by evaluating +that form. If none of the forms return a true nth value, this form returns +NIL." + (once-only (nth-value) + (with-gensyms (values) + `(let ((,values (multiple-value-list ,(first forms)))) + (if (nth ,nth-value ,values) + (values-list ,values) + ,(if (rest forms) + `(nth-value-or ,nth-value ,@(rest forms)) + nil)))))) + +(defmacro multiple-value-prog2 (first-form second-form &body forms) + "Evaluates FIRST-FORM, then SECOND-FORM, and then FORMS. Yields as its value +all the value returned by SECOND-FORM." + `(progn ,first-form (multiple-value-prog1 ,second-form ,@forms))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/definitions.lisp b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/definitions.lisp new file mode 100644 index 0000000..863e1f6 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/definitions.lisp @@ -0,0 +1,37 @@ +(in-package :alexandria) + +(defun %reevaluate-constant (name value test) + (if (not (boundp name)) + value + (let ((old (symbol-value name)) + (new value)) + (if (not (constantp name)) + (prog1 new + (cerror "Try to redefine the variable as a constant." + "~@<~S is an already bound non-constant variable ~ + whose value is ~S.~:@>" name old)) + (if (funcall test old new) + old + (restart-case + (error "~@<~S is an already defined constant whose value ~ + ~S is not equal to the provided initial value ~S ~ + under ~S.~:@>" name old new test) + (ignore () + :report "Retain the current value." + old) + (continue () + :report "Try to redefine the constant." + new))))))) + +(defmacro define-constant (name initial-value &key (test ''eql) documentation) + "Ensures that the global variable named by NAME is a constant with a value +that is equal under TEST to the result of evaluating INITIAL-VALUE. TEST is a +/function designator/ that defaults to EQL. If DOCUMENTATION is given, it +becomes the documentation string of the constant. + +Signals an error if NAME is already a bound non-constant variable. + +Signals an error if NAME is already a constant variable whose value is not +equal under TEST to result of evaluating INITIAL-VALUE." + `(defconstant ,name (%reevaluate-constant ',name ,initial-value ,test) + ,@(when documentation `(,documentation)))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/doc/.gitignore b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/doc/.gitignore new file mode 100644 index 0000000..f22577b --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/doc/.gitignore @@ -0,0 +1,3 @@ +alexandria +include + diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/doc/Makefile b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/doc/Makefile new file mode 100644 index 0000000..85eb818 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/doc/Makefile @@ -0,0 +1,28 @@ +.PHONY: clean html pdf include clean-include clean-crap info doc + +doc: pdf html info clean-crap + +clean-include: + rm -rf include + +clean-crap: + rm -f *.aux *.cp *.fn *.fns *.ky *.log *.pg *.toc *.tp *.tps *.vr + +clean: clean-include + rm -f *.pdf *.html *.info + +include: + sbcl --no-userinit --eval '(require :asdf)' \ + --eval '(let ((asdf:*central-registry* (list "../"))) (require :alexandria))' \ + --load docstrings.lisp \ + --eval '(sb-texinfo:generate-includes "include/" (list :alexandria) :base-package :alexandria)' \ + --eval '(quit)' + +pdf: include + texi2pdf alexandria.texinfo + +html: include + makeinfo --html --no-split alexandria.texinfo + +info: include + makeinfo alexandria.texinfo diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/doc/alexandria.texinfo b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/doc/alexandria.texinfo new file mode 100644 index 0000000..89b03ac --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/doc/alexandria.texinfo @@ -0,0 +1,277 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename alexandria.info +@settitle Alexandria Manual +@c %**end of header + +@settitle Alexandria Manual -- draft version + +@c for install-info +@dircategory Software development +@direntry +* alexandria: Common Lisp utilities. +@end direntry + +@copying +Alexandria software and associated documentation are in the public +domain: + +@quotation + Authors dedicate this work to public domain, for the benefit of the + public at large and to the detriment of the authors' heirs and + successors. Authors intends this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights under + copyright law, whether vested or contingent, in the work. Authors + understands that such relinquishment of all rights includes the + relinquishment of all rights to enforce (by lawsuit or otherwise) + those copyrights in the work. + + Authors recognize that, once placed in the public domain, the work + may be freely reproduced, distributed, transmitted, used, modified, + built upon, or otherwise exploited by anyone for any purpose, + commercial or non-commercial, and in any way, including by methods + that have not yet been invented or conceived. +@end quotation + +In those legislations where public domain dedications are not +recognized or possible, Alexandria is distributed under the following +terms and conditions: + +@quotation + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +@end quotation +@end copying + +@titlepage + +@title Alexandria Manual +@subtitle draft version + +@c The following two commands start the copyright page. +@page +@vskip 0pt plus 1filll +@insertcopying + +@end titlepage + +@contents + +@ifnottex + +@include include/ifnottex.texinfo + +@node Top +@comment node-name, next, previous, up +@top Alexandria + +@insertcopying + +@menu +* Hash Tables:: +* Data and Control Flow:: +* Conses:: +* Sequences:: +* IO:: +* Macro Writing:: +* Symbols:: +* Arrays:: +* Types:: +* Numbers:: +@end menu + +@end ifnottex + +@node Hash Tables +@comment node-name, next, previous, up +@chapter Hash Tables + +@include include/macro-alexandria-ensure-gethash.texinfo +@include include/fun-alexandria-copy-hash-table.texinfo +@include include/fun-alexandria-maphash-keys.texinfo +@include include/fun-alexandria-maphash-values.texinfo +@include include/fun-alexandria-hash-table-keys.texinfo +@include include/fun-alexandria-hash-table-values.texinfo +@include include/fun-alexandria-hash-table-alist.texinfo +@include include/fun-alexandria-hash-table-plist.texinfo +@include include/fun-alexandria-alist-hash-table.texinfo +@include include/fun-alexandria-plist-hash-table.texinfo + +@node Data and Control Flow +@comment node-name, next, previous, up +@chapter Data and Control Flow + +@include include/macro-alexandria-define-constant.texinfo +@include include/macro-alexandria-destructuring-case.texinfo +@include include/macro-alexandria-ensure-functionf.texinfo +@include include/macro-alexandria-multiple-value-prog2.texinfo +@include include/macro-alexandria-named-lambda.texinfo +@include include/macro-alexandria-nth-value-or.texinfo +@include include/macro-alexandria-if-let.texinfo +@include include/macro-alexandria-when-let.texinfo +@include include/macro-alexandria-when-let-star.texinfo +@include include/macro-alexandria-switch.texinfo +@include include/macro-alexandria-cswitch.texinfo +@include include/macro-alexandria-eswitch.texinfo +@include include/macro-alexandria-whichever.texinfo +@include include/macro-alexandria-xor.texinfo + +@include include/fun-alexandria-disjoin.texinfo +@include include/fun-alexandria-conjoin.texinfo +@include include/fun-alexandria-compose.texinfo +@include include/fun-alexandria-ensure-function.texinfo +@include include/fun-alexandria-multiple-value-compose.texinfo +@include include/fun-alexandria-curry.texinfo +@include include/fun-alexandria-rcurry.texinfo + +@node Conses +@comment node-name, next, previous, up +@chapter Conses + +@include include/type-alexandria-proper-list.texinfo +@include include/type-alexandria-circular-list.texinfo + +@include include/macro-alexandria-appendf.texinfo +@include include/macro-alexandria-nconcf.texinfo +@include include/macro-alexandria-remove-from-plistf.texinfo +@include include/macro-alexandria-delete-from-plistf.texinfo +@include include/macro-alexandria-reversef.texinfo +@include include/macro-alexandria-nreversef.texinfo +@include include/macro-alexandria-unionf.texinfo +@include include/macro-alexandria-nunionf.texinfo + +@include include/macro-alexandria-doplist.texinfo + +@include include/fun-alexandria-circular-list-p.texinfo +@include include/fun-alexandria-circular-tree-p.texinfo +@include include/fun-alexandria-proper-list-p.texinfo + +@include include/fun-alexandria-alist-plist.texinfo +@include include/fun-alexandria-plist-alist.texinfo +@include include/fun-alexandria-circular-list.texinfo +@include include/fun-alexandria-make-circular-list.texinfo +@include include/fun-alexandria-ensure-car.texinfo +@include include/fun-alexandria-ensure-cons.texinfo +@include include/fun-alexandria-ensure-list.texinfo +@include include/fun-alexandria-flatten.texinfo +@include include/fun-alexandria-lastcar.texinfo +@include include/fun-alexandria-setf-lastcar.texinfo +@include include/fun-alexandria-proper-list-length.texinfo +@include include/fun-alexandria-mappend.texinfo +@include include/fun-alexandria-map-product.texinfo +@include include/fun-alexandria-remove-from-plist.texinfo +@include include/fun-alexandria-delete-from-plist.texinfo +@include include/fun-alexandria-set-equal.texinfo +@include include/fun-alexandria-setp.texinfo + +@node Sequences +@comment node-name, next, previous, up +@chapter Sequences + +@include include/type-alexandria-proper-sequence.texinfo + +@include include/macro-alexandria-deletef.texinfo +@include include/macro-alexandria-removef.texinfo + +@include include/fun-alexandria-rotate.texinfo +@include include/fun-alexandria-shuffle.texinfo +@include include/fun-alexandria-random-elt.texinfo +@include include/fun-alexandria-emptyp.texinfo +@include include/fun-alexandria-sequence-of-length-p.texinfo +@include include/fun-alexandria-length-equals.texinfo +@include include/fun-alexandria-copy-sequence.texinfo +@include include/fun-alexandria-first-elt.texinfo +@include include/fun-alexandria-setf-first-elt.texinfo +@include include/fun-alexandria-last-elt.texinfo +@include include/fun-alexandria-setf-last-elt.texinfo +@include include/fun-alexandria-starts-with.texinfo +@include include/fun-alexandria-starts-with-subseq.texinfo +@include include/fun-alexandria-ends-with.texinfo +@include include/fun-alexandria-ends-with-subseq.texinfo +@include include/fun-alexandria-map-combinations.texinfo +@include include/fun-alexandria-map-derangements.texinfo +@include include/fun-alexandria-map-permutations.texinfo + +@node IO +@comment node-name, next, previous, up +@chapter IO + +@include include/fun-alexandria-read-stream-content-into-string.texinfo +@include include/fun-alexandria-read-file-into-string.texinfo +@include include/fun-alexandria-read-stream-content-into-byte-vector.texinfo +@include include/fun-alexandria-read-file-into-byte-vector.texinfo + +@node Macro Writing +@comment node-name, next, previous, up +@chapter Macro Writing + +@include include/macro-alexandria-once-only.texinfo +@include include/macro-alexandria-with-gensyms.texinfo +@include include/macro-alexandria-with-unique-names.texinfo +@include include/fun-alexandria-featurep.texinfo +@include include/fun-alexandria-parse-body.texinfo +@include include/fun-alexandria-parse-ordinary-lambda-list.texinfo + +@node Symbols +@comment node-name, next, previous, up +@chapter Symbols + +@include include/fun-alexandria-ensure-symbol.texinfo +@include include/fun-alexandria-format-symbol.texinfo +@include include/fun-alexandria-make-keyword.texinfo +@include include/fun-alexandria-make-gensym.texinfo +@include include/fun-alexandria-make-gensym-list.texinfo +@include include/fun-alexandria-symbolicate.texinfo + +@node Arrays +@comment node-name, next, previous, up +@chapter Arrays + +@include include/type-alexandria-array-index.texinfo +@include include/type-alexandria-array-length.texinfo +@include include/fun-alexandria-copy-array.texinfo + +@node Types +@comment node-name, next, previous, up +@chapter Types + +@include include/type-alexandria-string-designator.texinfo +@include include/macro-alexandria-coercef.texinfo +@include include/fun-alexandria-of-type.texinfo +@include include/fun-alexandria-type-equals.texinfo + +@node Numbers +@comment node-name, next, previous, up +@chapter Numbers + +@include include/macro-alexandria-maxf.texinfo +@include include/macro-alexandria-minf.texinfo + +@include include/fun-alexandria-binomial-coefficient.texinfo +@include include/fun-alexandria-count-permutations.texinfo +@include include/fun-alexandria-clamp.texinfo +@include include/fun-alexandria-lerp.texinfo +@include include/fun-alexandria-factorial.texinfo +@include include/fun-alexandria-subfactorial.texinfo +@include include/fun-alexandria-gaussian-random.texinfo +@include include/fun-alexandria-iota.texinfo +@include include/fun-alexandria-map-iota.texinfo +@include include/fun-alexandria-mean.texinfo +@include include/fun-alexandria-median.texinfo +@include include/fun-alexandria-variance.texinfo +@include include/fun-alexandria-standard-deviation.texinfo + +@bye diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/doc/docstrings.lisp b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/doc/docstrings.lisp new file mode 100644 index 0000000..51dda07 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/doc/docstrings.lisp @@ -0,0 +1,881 @@ +;;; -*- lisp -*- + +;;;; A docstring extractor for the sbcl manual. Creates +;;;; @include-ready documentation from the docstrings of exported +;;;; symbols of specified packages. + +;;;; This software is part of the SBCL software system. SBCL is in the +;;;; public domain and is provided with absolutely no warranty. See +;;;; the COPYING file for more information. +;;;; +;;;; Written by Rudi Schlatte , mangled +;;;; by Nikodemus Siivola. + +;;;; TODO +;;;; * Verbatim text +;;;; * Quotations +;;;; * Method documentation untested +;;;; * Method sorting, somehow +;;;; * Index for macros & constants? +;;;; * This is getting complicated enough that tests would be good +;;;; * Nesting (currently only nested itemizations work) +;;;; * doc -> internal form -> texinfo (so that non-texinfo format are also +;;;; easily generated) + +;;;; FIXME: The description below is no longer complete. This +;;;; should possibly be turned into a contrib with proper documentation. + +;;;; Formatting heuristics (tweaked to format SAVE-LISP-AND-DIE sanely): +;;;; +;;;; Formats SYMBOL as @code{symbol}, or @var{symbol} if symbol is in +;;;; the argument list of the defun / defmacro. +;;;; +;;;; Lines starting with * or - that are followed by intented lines +;;;; are marked up with @itemize. +;;;; +;;;; Lines containing only a SYMBOL that are followed by indented +;;;; lines are marked up as @table @code, with the SYMBOL as the item. + +(eval-when (:compile-toplevel :load-toplevel :execute) + (require 'sb-introspect)) + +(defpackage :sb-texinfo + (:use :cl :sb-mop) + (:shadow #:documentation) + (:export #:generate-includes #:document-package) + (:documentation + "Tools to generate TexInfo documentation from docstrings.")) + +(in-package :sb-texinfo) + +;;;; various specials and parameters + +(defvar *texinfo-output*) +(defvar *texinfo-variables*) +(defvar *documentation-package*) +(defvar *base-package*) + +(defparameter *undocumented-packages* '(sb-pcl sb-int sb-kernel sb-sys sb-c)) + +(defparameter *documentation-types* + '(compiler-macro + function + method-combination + setf + ;;structure ; also handled by `type' + type + variable) + "A list of symbols accepted as second argument of `documentation'") + +(defparameter *character-replacements* + '((#\* . "star") (#\/ . "slash") (#\+ . "plus") + (#\< . "lt") (#\> . "gt") + (#\= . "equals")) + "Characters and their replacement names that `alphanumize' uses. If +the replacements contain any of the chars they're supposed to replace, +you deserve to lose.") + +(defparameter *characters-to-drop* '(#\\ #\` #\') + "Characters that should be removed by `alphanumize'.") + +(defparameter *texinfo-escaped-chars* "@{}" + "Characters that must be escaped with #\@ for Texinfo.") + +(defparameter *itemize-start-characters* '(#\* #\-) + "Characters that might start an itemization in docstrings when + at the start of a line.") + +(defparameter *symbol-characters* "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890*:-+&#'" + "List of characters that make up symbols in a docstring.") + +(defparameter *symbol-delimiters* " ,.!?;") + +(defparameter *ordered-documentation-kinds* + '(package type structure condition class macro)) + +;;;; utilities + +(defun flatten (list) + (cond ((null list) + nil) + ((consp (car list)) + (nconc (flatten (car list)) (flatten (cdr list)))) + ((null (cdr list)) + (cons (car list) nil)) + (t + (cons (car list) (flatten (cdr list)))))) + +(defun whitespacep (char) + (find char #(#\tab #\space #\page))) + +(defun setf-name-p (name) + (or (symbolp name) + (and (listp name) (= 2 (length name)) (eq (car name) 'setf)))) + +(defgeneric specializer-name (specializer)) + +(defmethod specializer-name ((specializer eql-specializer)) + (list 'eql (eql-specializer-object specializer))) + +(defmethod specializer-name ((specializer class)) + (class-name specializer)) + +(defun ensure-class-precedence-list (class) + (unless (class-finalized-p class) + (finalize-inheritance class)) + (class-precedence-list class)) + +(defun specialized-lambda-list (method) + ;; courtecy of AMOP p. 61 + (let* ((specializers (method-specializers method)) + (lambda-list (method-lambda-list method)) + (n-required (length specializers))) + (append (mapcar (lambda (arg specializer) + (if (eq specializer (find-class 't)) + arg + `(,arg ,(specializer-name specializer)))) + (subseq lambda-list 0 n-required) + specializers) + (subseq lambda-list n-required)))) + +(defun string-lines (string) + "Lines in STRING as a vector." + (coerce (with-input-from-string (s string) + (loop for line = (read-line s nil nil) + while line collect line)) + 'vector)) + +(defun indentation (line) + "Position of first non-SPACE character in LINE." + (position-if-not (lambda (c) (char= c #\Space)) line)) + +(defun docstring (x doc-type) + (cl:documentation x doc-type)) + +(defun flatten-to-string (list) + (format nil "~{~A~^-~}" (flatten list))) + +(defun alphanumize (original) + "Construct a string without characters like *`' that will f-star-ck +up filename handling. See `*character-replacements*' and +`*characters-to-drop*' for customization." + (let ((name (remove-if (lambda (x) (member x *characters-to-drop*)) + (if (listp original) + (flatten-to-string original) + (string original)))) + (chars-to-replace (mapcar #'car *character-replacements*))) + (flet ((replacement-delimiter (index) + (cond ((or (< index 0) (>= index (length name))) "") + ((alphanumericp (char name index)) "-") + (t "")))) + (loop for index = (position-if #'(lambda (x) (member x chars-to-replace)) + name) + while index + do (setf name (concatenate 'string (subseq name 0 index) + (replacement-delimiter (1- index)) + (cdr (assoc (aref name index) + *character-replacements*)) + (replacement-delimiter (1+ index)) + (subseq name (1+ index)))))) + name)) + +;;;; generating various names + +(defgeneric name (thing) + (:documentation "Name for a documented thing. Names are either +symbols or lists of symbols.")) + +(defmethod name ((symbol symbol)) + symbol) + +(defmethod name ((cons cons)) + cons) + +(defmethod name ((package package)) + (short-package-name package)) + +(defmethod name ((method method)) + (list + (generic-function-name (method-generic-function method)) + (method-qualifiers method) + (specialized-lambda-list method))) + +;;; Node names for DOCUMENTATION instances + +(defgeneric name-using-kind/name (kind name doc)) + +(defmethod name-using-kind/name (kind (name string) doc) + (declare (ignore kind doc)) + name) + +(defmethod name-using-kind/name (kind (name symbol) doc) + (declare (ignore kind)) + (format nil "~@[~A:~]~A" (short-package-name (get-package doc)) name)) + +(defmethod name-using-kind/name (kind (name list) doc) + (declare (ignore kind)) + (assert (setf-name-p name)) + (format nil "(setf ~@[~A:~]~A)" (short-package-name (get-package doc)) (second name))) + +(defmethod name-using-kind/name ((kind (eql 'method)) name doc) + (format nil "~A~{ ~A~} ~A" + (name-using-kind/name nil (first name) doc) + (second name) + (third name))) + +(defun node-name (doc) + "Returns TexInfo node name as a string for a DOCUMENTATION instance." + (let ((kind (get-kind doc))) + (format nil "~:(~A~) ~(~A~)" kind (name-using-kind/name kind (get-name doc) doc)))) + +(defun short-package-name (package) + (unless (eq package *base-package*) + (car (sort (copy-list (cons (package-name package) (package-nicknames package))) + #'< :key #'length)))) + +;;; Definition titles for DOCUMENTATION instances + +(defgeneric title-using-kind/name (kind name doc)) + +(defmethod title-using-kind/name (kind (name string) doc) + (declare (ignore kind doc)) + name) + +(defmethod title-using-kind/name (kind (name symbol) doc) + (declare (ignore kind)) + (format nil "~@[~A:~]~A" (short-package-name (get-package doc)) name)) + +(defmethod title-using-kind/name (kind (name list) doc) + (declare (ignore kind)) + (assert (setf-name-p name)) + (format nil "(setf ~@[~A:~]~A)" (short-package-name (get-package doc)) (second name))) + +(defmethod title-using-kind/name ((kind (eql 'method)) name doc) + (format nil "~{~A ~}~A" + (second name) + (title-using-kind/name nil (first name) doc))) + +(defun title-name (doc) + "Returns a string to be used as name of the definition." + (string-downcase (title-using-kind/name (get-kind doc) (get-name doc) doc))) + +(defun include-pathname (doc) + (let* ((kind (get-kind doc)) + (name (nstring-downcase + (if (eq 'package kind) + (format nil "package-~A" (alphanumize (get-name doc))) + (format nil "~A-~A-~A" + (case (get-kind doc) + ((function generic-function) "fun") + (structure "struct") + (variable "var") + (otherwise (symbol-name (get-kind doc)))) + (alphanumize (let ((*base-package* nil)) + (short-package-name (get-package doc)))) + (alphanumize (get-name doc))))))) + (make-pathname :name name :type "texinfo"))) + +;;;; documentation class and related methods + +(defclass documentation () + ((name :initarg :name :reader get-name) + (kind :initarg :kind :reader get-kind) + (string :initarg :string :reader get-string) + (children :initarg :children :initform nil :reader get-children) + (package :initform *documentation-package* :reader get-package))) + +(defmethod print-object ((documentation documentation) stream) + (print-unreadable-object (documentation stream :type t) + (princ (list (get-kind documentation) (get-name documentation)) stream))) + +(defgeneric make-documentation (x doc-type string)) + +(defmethod make-documentation ((x package) doc-type string) + (declare (ignore doc-type)) + (make-instance 'documentation + :name (name x) + :kind 'package + :string string)) + +(defmethod make-documentation (x (doc-type (eql 'function)) string) + (declare (ignore doc-type)) + (let* ((fdef (and (fboundp x) (fdefinition x))) + (name x) + (kind (cond ((and (symbolp x) (special-operator-p x)) + 'special-operator) + ((and (symbolp x) (macro-function x)) + 'macro) + ((typep fdef 'generic-function) + (assert (or (symbolp name) (setf-name-p name))) + 'generic-function) + (fdef + (assert (or (symbolp name) (setf-name-p name))) + 'function))) + (children (when (eq kind 'generic-function) + (collect-gf-documentation fdef)))) + (make-instance 'documentation + :name (name x) + :string string + :kind kind + :children children))) + +(defmethod make-documentation ((x method) doc-type string) + (declare (ignore doc-type)) + (make-instance 'documentation + :name (name x) + :kind 'method + :string string)) + +(defmethod make-documentation (x (doc-type (eql 'type)) string) + (make-instance 'documentation + :name (name x) + :string string + :kind (etypecase (find-class x nil) + (structure-class 'structure) + (standard-class 'class) + (sb-pcl::condition-class 'condition) + ((or built-in-class null) 'type)))) + +(defmethod make-documentation (x (doc-type (eql 'variable)) string) + (make-instance 'documentation + :name (name x) + :string string + :kind (if (constantp x) + 'constant + 'variable))) + +(defmethod make-documentation (x (doc-type (eql 'setf)) string) + (declare (ignore doc-type)) + (make-instance 'documentation + :name (name x) + :kind 'setf-expander + :string string)) + +(defmethod make-documentation (x doc-type string) + (make-instance 'documentation + :name (name x) + :kind doc-type + :string string)) + +(defun maybe-documentation (x doc-type) + "Returns a DOCUMENTATION instance for X and DOC-TYPE, or NIL if +there is no corresponding docstring." + (let ((docstring (docstring x doc-type))) + (when docstring + (make-documentation x doc-type docstring)))) + +(defun lambda-list (doc) + (case (get-kind doc) + ((package constant variable type structure class condition nil) + nil) + (method + (third (get-name doc))) + (t + ;; KLUDGE: Eugh. + ;; + ;; believe it or not, the above comment was written before CSR + ;; came along and obfuscated this. (2005-07-04) + (when (symbolp (get-name doc)) + (labels ((clean (x &key optional key) + (typecase x + (atom x) + ((cons (member &optional)) + (cons (car x) (clean (cdr x) :optional t))) + ((cons (member &key)) + (cons (car x) (clean (cdr x) :key t))) + ((cons (member &whole &environment)) + ;; Skip these + (clean (cdr x) :optional optional :key key)) + ((cons cons) + (cons + (cond (key (if (consp (caar x)) + (caaar x) + (caar x))) + (optional (caar x)) + (t (clean (car x)))) + (clean (cdr x) :key key :optional optional))) + (cons + (cons + (cond ((or key optional) (car x)) + (t (clean (car x)))) + (clean (cdr x) :key key :optional optional)))))) + (clean (sb-introspect:function-lambda-list (get-name doc)))))))) + +(defun get-string-name (x) + (let ((name (get-name x))) + (cond ((symbolp name) + (symbol-name name)) + ((and (consp name) (eq 'setf (car name))) + (symbol-name (second name))) + ((stringp name) + name) + (t + (error "Don't know which symbol to use for name ~S" name))))) + +(defun documentation< (x y) + (let ((p1 (position (get-kind x) *ordered-documentation-kinds*)) + (p2 (position (get-kind y) *ordered-documentation-kinds*))) + (if (or (not (and p1 p2)) (= p1 p2)) + (string< (get-string-name x) (get-string-name y)) + (< p1 p2)))) + +;;;; turning text into texinfo + +(defun escape-for-texinfo (string &optional downcasep) + "Return STRING with characters in *TEXINFO-ESCAPED-CHARS* escaped +with #\@. Optionally downcase the result." + (let ((result (with-output-to-string (s) + (loop for char across string + when (find char *texinfo-escaped-chars*) + do (write-char #\@ s) + do (write-char char s))))) + (if downcasep (nstring-downcase result) result))) + +(defun empty-p (line-number lines) + (and (< -1 line-number (length lines)) + (not (indentation (svref lines line-number))))) + +;;; line markups + +(defvar *not-symbols* '("ANSI" "CLHS")) + +(defun locate-symbols (line) + "Return a list of index pairs of symbol-like parts of LINE." + ;; This would be a good application for a regex ... + (let (result) + (flet ((grab (start end) + (unless (member (subseq line start end) '("ANSI" "CLHS")) + (push (list start end) result)))) + (do ((begin nil) + (maybe-begin t) + (i 0 (1+ i))) + ((= i (length line)) + ;; symbol at end of line + (when (and begin (or (> i (1+ begin)) + (not (member (char line begin) '(#\A #\I))))) + (grab begin i)) + (nreverse result)) + (cond + ((and begin (find (char line i) *symbol-delimiters*)) + ;; symbol end; remember it if it's not "A" or "I" + (when (or (> i (1+ begin)) (not (member (char line begin) '(#\A #\I)))) + (grab begin i)) + (setf begin nil + maybe-begin t)) + ((and begin (not (find (char line i) *symbol-characters*))) + ;; Not a symbol: abort + (setf begin nil)) + ((and maybe-begin (not begin) (find (char line i) *symbol-characters*)) + ;; potential symbol begin at this position + (setf begin i + maybe-begin nil)) + ((find (char line i) *symbol-delimiters*) + ;; potential symbol begin after this position + (setf maybe-begin t)) + (t + ;; Not reading a symbol, not at potential start of symbol + (setf maybe-begin nil))))))) + +(defun texinfo-line (line) + "Format symbols in LINE texinfo-style: either as code or as +variables if the symbol in question is contained in symbols +*TEXINFO-VARIABLES*." + (with-output-to-string (result) + (let ((last 0)) + (dolist (symbol/index (locate-symbols line)) + (write-string (subseq line last (first symbol/index)) result) + (let ((symbol-name (apply #'subseq line symbol/index))) + (format result (if (member symbol-name *texinfo-variables* + :test #'string=) + "@var{~A}" + "@code{~A}") + (string-downcase symbol-name))) + (setf last (second symbol/index))) + (write-string (subseq line last) result)))) + +;;; lisp sections + +(defun lisp-section-p (line line-number lines) + "Returns T if the given LINE looks like start of lisp code -- +ie. if it starts with whitespace followed by a paren or +semicolon, and the previous line is empty" + (let ((offset (indentation line))) + (and offset + (plusp offset) + (find (find-if-not #'whitespacep line) "(;") + (empty-p (1- line-number) lines)))) + +(defun collect-lisp-section (lines line-number) + (let ((lisp (loop for index = line-number then (1+ index) + for line = (and (< index (length lines)) (svref lines index)) + while (indentation line) + collect line))) + (values (length lisp) `("@lisp" ,@lisp "@end lisp")))) + +;;; itemized sections + +(defun maybe-itemize-offset (line) + "Return NIL or the indentation offset if LINE looks like it starts +an item in an itemization." + (let* ((offset (indentation line)) + (char (when offset (char line offset)))) + (and offset + (member char *itemize-start-characters* :test #'char=) + (char= #\Space (find-if-not (lambda (c) (char= c char)) + line :start offset)) + offset))) + +(defun collect-maybe-itemized-section (lines starting-line) + ;; Return index of next line to be processed outside + (let ((this-offset (maybe-itemize-offset (svref lines starting-line))) + (result nil) + (lines-consumed 0)) + (loop for line-number from starting-line below (length lines) + for line = (svref lines line-number) + for indentation = (indentation line) + for offset = (maybe-itemize-offset line) + do (cond + ((not indentation) + ;; empty line -- inserts paragraph. + (push "" result) + (incf lines-consumed)) + ((and offset (> indentation this-offset)) + ;; nested itemization -- handle recursively + ;; FIXME: tables in itemizations go wrong + (multiple-value-bind (sub-lines-consumed sub-itemization) + (collect-maybe-itemized-section lines line-number) + (when sub-lines-consumed + (incf line-number (1- sub-lines-consumed)) ; +1 on next loop + (incf lines-consumed sub-lines-consumed) + (setf result (nconc (nreverse sub-itemization) result))))) + ((and offset (= indentation this-offset)) + ;; start of new item + (push (format nil "@item ~A" + (texinfo-line (subseq line (1+ offset)))) + result) + (incf lines-consumed)) + ((and (not offset) (> indentation this-offset)) + ;; continued item from previous line + (push (texinfo-line line) result) + (incf lines-consumed)) + (t + ;; end of itemization + (loop-finish)))) + ;; a single-line itemization isn't. + (if (> (count-if (lambda (line) (> (length line) 0)) result) 1) + (values lines-consumed `("@itemize" ,@(reverse result) "@end itemize")) + nil))) + +;;; table sections + +(defun tabulation-body-p (offset line-number lines) + (when (< line-number (length lines)) + (let ((offset2 (indentation (svref lines line-number)))) + (and offset2 (< offset offset2))))) + +(defun tabulation-p (offset line-number lines direction) + (let ((step (ecase direction + (:backwards (1- line-number)) + (:forwards (1+ line-number))))) + (when (and (plusp line-number) (< line-number (length lines))) + (and (eql offset (indentation (svref lines line-number))) + (or (when (eq direction :backwards) + (empty-p step lines)) + (tabulation-p offset step lines direction) + (tabulation-body-p offset step lines)))))) + +(defun maybe-table-offset (line-number lines) + "Return NIL or the indentation offset if LINE looks like it starts +an item in a tabulation. Ie, if it is (1) indented, (2) preceded by an +empty line, another tabulation label, or a tabulation body, (3) and +followed another tabulation label or a tabulation body." + (let* ((line (svref lines line-number)) + (offset (indentation line)) + (prev (1- line-number)) + (next (1+ line-number))) + (when (and offset (plusp offset)) + (and (or (empty-p prev lines) + (tabulation-body-p offset prev lines) + (tabulation-p offset prev lines :backwards)) + (or (tabulation-body-p offset next lines) + (tabulation-p offset next lines :forwards)) + offset)))) + +;;; FIXME: This and itemization are very similar: could they share +;;; some code, mayhap? + +(defun collect-maybe-table-section (lines starting-line) + ;; Return index of next line to be processed outside + (let ((this-offset (maybe-table-offset starting-line lines)) + (result nil) + (lines-consumed 0)) + (loop for line-number from starting-line below (length lines) + for line = (svref lines line-number) + for indentation = (indentation line) + for offset = (maybe-table-offset line-number lines) + do (cond + ((not indentation) + ;; empty line -- inserts paragraph. + (push "" result) + (incf lines-consumed)) + ((and offset (= indentation this-offset)) + ;; start of new item, or continuation of previous item + (if (and result (search "@item" (car result) :test #'char=)) + (push (format nil "@itemx ~A" (texinfo-line line)) + result) + (progn + (push "" result) + (push (format nil "@item ~A" (texinfo-line line)) + result))) + (incf lines-consumed)) + ((> indentation this-offset) + ;; continued item from previous line + (push (texinfo-line line) result) + (incf lines-consumed)) + (t + ;; end of itemization + (loop-finish)))) + ;; a single-line table isn't. + (if (> (count-if (lambda (line) (> (length line) 0)) result) 1) + (values lines-consumed + `("" "@table @emph" ,@(reverse result) "@end table" "")) + nil))) + +;;; section markup + +(defmacro with-maybe-section (index &rest forms) + `(multiple-value-bind (count collected) (progn ,@forms) + (when count + (dolist (line collected) + (write-line line *texinfo-output*)) + (incf ,index (1- count))))) + +(defun write-texinfo-string (string &optional lambda-list) + "Try to guess as much formatting for a raw docstring as possible." + (let ((*texinfo-variables* (flatten lambda-list)) + (lines (string-lines (escape-for-texinfo string nil)))) + (loop for line-number from 0 below (length lines) + for line = (svref lines line-number) + do (cond + ((with-maybe-section line-number + (and (lisp-section-p line line-number lines) + (collect-lisp-section lines line-number)))) + ((with-maybe-section line-number + (and (maybe-itemize-offset line) + (collect-maybe-itemized-section lines line-number)))) + ((with-maybe-section line-number + (and (maybe-table-offset line-number lines) + (collect-maybe-table-section lines line-number)))) + (t + (write-line (texinfo-line line) *texinfo-output*)))))) + +;;;; texinfo formatting tools + +(defun hide-superclass-p (class-name super-name) + (let ((super-package (symbol-package super-name))) + (or + ;; KLUDGE: We assume that we don't want to advertise internal + ;; classes in CP-lists, unless the symbol we're documenting is + ;; internal as well. + (and (member super-package #.'(mapcar #'find-package *undocumented-packages*)) + (not (eq super-package (symbol-package class-name)))) + ;; KLUDGE: We don't generally want to advertise SIMPLE-ERROR or + ;; SIMPLE-CONDITION in the CPLs of conditions that inherit them + ;; simply as a matter of convenience. The assumption here is that + ;; the inheritance is incidental unless the name of the condition + ;; begins with SIMPLE-. + (and (member super-name '(simple-error simple-condition)) + (let ((prefix "SIMPLE-")) + (mismatch prefix (string class-name) :end2 (length prefix))) + t ; don't return number from MISMATCH + )))) + +(defun hide-slot-p (symbol slot) + ;; FIXME: There is no pricipal reason to avoid the slot docs fo + ;; structures and conditions, but their DOCUMENTATION T doesn't + ;; currently work with them the way we'd like. + (not (and (typep (find-class symbol nil) 'standard-class) + (docstring slot t)))) + +(defun texinfo-anchor (doc) + (format *texinfo-output* "@anchor{~A}~%" (node-name doc))) + +;;; KLUDGE: &AUX *PRINT-PRETTY* here means "no linebreaks please" +(defun texinfo-begin (doc &aux *print-pretty*) + (let ((kind (get-kind doc))) + (format *texinfo-output* "@~A {~:(~A~)} ~({~A}~@[ ~{~A~^ ~}~]~)~%" + (case kind + ((package constant variable) + "defvr") + ((structure class condition type) + "deftp") + (t + "deffn")) + (map 'string (lambda (char) (if (eql char #\-) #\Space char)) (string kind)) + (title-name doc) + ;; &foo would be amusingly bold in the pdf thanks to TeX/Texinfo + ;; interactions,so we escape the ampersand -- amusingly for TeX. + ;; sbcl.texinfo defines macros that expand @&key and friends to &key. + (mapcar (lambda (name) + (if (member name lambda-list-keywords) + (format nil "@~A" name) + name)) + (lambda-list doc))))) + +(defun texinfo-index (doc) + (let ((title (title-name doc))) + (case (get-kind doc) + ((structure type class condition) + (format *texinfo-output* "@tindex ~A~%" title)) + ((variable constant) + (format *texinfo-output* "@vindex ~A~%" title)) + ((compiler-macro function method-combination macro generic-function) + (format *texinfo-output* "@findex ~A~%" title))))) + +(defun texinfo-inferred-body (doc) + (when (member (get-kind doc) '(class structure condition)) + (let ((name (get-name doc))) + ;; class precedence list + (format *texinfo-output* "Class precedence list: @code{~(~{@lw{~A}~^, ~}~)}~%~%" + (remove-if (lambda (class) (hide-superclass-p name class)) + (mapcar #'class-name (ensure-class-precedence-list (find-class name))))) + ;; slots + (let ((slots (remove-if (lambda (slot) (hide-slot-p name slot)) + (class-direct-slots (find-class name))))) + (when slots + (format *texinfo-output* "Slots:~%@itemize~%") + (dolist (slot slots) + (format *texinfo-output* + "@item ~(@code{~A}~#[~:; --- ~]~ + ~:{~2*~@[~2:*~A~P: ~{@code{@w{~S}}~^, ~}~]~:^; ~}~)~%~%" + (slot-definition-name slot) + (remove + nil + (mapcar + (lambda (name things) + (if things + (list name (length things) things))) + '("initarg" "reader" "writer") + (list + (slot-definition-initargs slot) + (slot-definition-readers slot) + (slot-definition-writers slot))))) + ;; FIXME: Would be neater to handler as children + (write-texinfo-string (docstring slot t))) + (format *texinfo-output* "@end itemize~%~%")))))) + +(defun texinfo-body (doc) + (write-texinfo-string (get-string doc))) + +(defun texinfo-end (doc) + (write-line (case (get-kind doc) + ((package variable constant) "@end defvr") + ((structure type class condition) "@end deftp") + (t "@end deffn")) + *texinfo-output*)) + +(defun write-texinfo (doc) + "Writes TexInfo for a DOCUMENTATION instance to *TEXINFO-OUTPUT*." + (texinfo-anchor doc) + (texinfo-begin doc) + (texinfo-index doc) + (texinfo-inferred-body doc) + (texinfo-body doc) + (texinfo-end doc) + ;; FIXME: Children should be sorted one way or another + (mapc #'write-texinfo (get-children doc))) + +;;;; main logic + +(defun collect-gf-documentation (gf) + "Collects method documentation for the generic function GF" + (loop for method in (generic-function-methods gf) + for doc = (maybe-documentation method t) + when doc + collect doc)) + +(defun collect-name-documentation (name) + (loop for type in *documentation-types* + for doc = (maybe-documentation name type) + when doc + collect doc)) + +(defun collect-symbol-documentation (symbol) + "Collects all docs for a SYMBOL and (SETF SYMBOL), returns a list of +the form DOC instances. See `*documentation-types*' for the possible +values of doc-type." + (nconc (collect-name-documentation symbol) + (collect-name-documentation (list 'setf symbol)))) + +(defun collect-documentation (package) + "Collects all documentation for all external symbols of the given +package, as well as for the package itself." + (let* ((*documentation-package* (find-package package)) + (docs nil)) + (check-type package package) + (do-external-symbols (symbol package) + (setf docs (nconc (collect-symbol-documentation symbol) docs))) + (let ((doc (maybe-documentation *documentation-package* t))) + (when doc + (push doc docs))) + docs)) + +(defmacro with-texinfo-file (pathname &body forms) + `(with-open-file (*texinfo-output* ,pathname + :direction :output + :if-does-not-exist :create + :if-exists :supersede) + ,@forms)) + +(defun write-ifnottex () + ;; We use @&key, etc to escape & from TeX in lambda lists -- so we need to + ;; define them for info as well. + (flet ((macro (name) + (let ((string (string-downcase name))) + (format *texinfo-output* "@macro ~A~%~A~%@end macro~%" string string)))) + (macro '&allow-other-keys) + (macro '&optional) + (macro '&rest) + (macro '&key) + (macro '&body))) + +(defun generate-includes (directory packages &key (base-package :cl-user)) + "Create files in `directory' containing Texinfo markup of all +docstrings of each exported symbol in `packages'. `directory' is +created if necessary. If you supply a namestring that doesn't end in a +slash, you lose. The generated files are of the form +\"__.texinfo\" and can be included +via @include statements. Texinfo syntax-significant characters are +escaped in symbol names, but if a docstring contains invalid Texinfo +markup, you lose." + (handler-bind ((warning #'muffle-warning)) + (let ((directory (merge-pathnames (pathname directory))) + (*base-package* (find-package base-package))) + (ensure-directories-exist directory) + (dolist (package packages) + (dolist (doc (collect-documentation (find-package package))) + (with-texinfo-file (merge-pathnames (include-pathname doc) directory) + (write-texinfo doc)))) + (with-texinfo-file (merge-pathnames "ifnottex.texinfo" directory) + (write-ifnottex)) + directory))) + +(defun document-package (package &optional filename) + "Create a file containing all available documentation for the +exported symbols of `package' in Texinfo format. If `filename' is not +supplied, a file \".texinfo\" is generated. + +The definitions can be referenced using Texinfo statements like +@ref{__.texinfo}. Texinfo +syntax-significant characters are escaped in symbol names, but if a +docstring contains invalid Texinfo markup, you lose." + (handler-bind ((warning #'muffle-warning)) + (let* ((package (find-package package)) + (filename (or filename (make-pathname + :name (string-downcase (short-package-name package)) + :type "texinfo"))) + (docs (sort (collect-documentation package) #'documentation<))) + (with-texinfo-file filename + (dolist (doc docs) + (write-texinfo doc))) + filename))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/features.lisp b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/features.lisp new file mode 100644 index 0000000..67348db --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/features.lisp @@ -0,0 +1,14 @@ +(in-package :alexandria) + +(defun featurep (feature-expression) + "Returns T if the argument matches the state of the *FEATURES* +list and NIL if it does not. FEATURE-EXPRESSION can be any atom +or list acceptable to the reader macros #+ and #-." + (etypecase feature-expression + (symbol (not (null (member feature-expression *features*)))) + (cons (check-type (first feature-expression) symbol) + (eswitch ((first feature-expression) :test 'string=) + (:and (every #'featurep (rest feature-expression))) + (:or (some #'featurep (rest feature-expression))) + (:not (assert (= 2 (length feature-expression))) + (not (featurep (second feature-expression)))))))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/functions.lisp b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/functions.lisp new file mode 100644 index 0000000..dd83e38 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/functions.lisp @@ -0,0 +1,161 @@ +(in-package :alexandria) + +;;; To propagate return type and allow the compiler to eliminate the IF when +;;; it is known if the argument is function or not. +(declaim (inline ensure-function)) + +(declaim (ftype (function (t) (values function &optional)) + ensure-function)) +(defun ensure-function (function-designator) + "Returns the function designated by FUNCTION-DESIGNATOR: +if FUNCTION-DESIGNATOR is a function, it is returned, otherwise +it must be a function name and its FDEFINITION is returned." + (if (functionp function-designator) + function-designator + (fdefinition function-designator))) + +(define-modify-macro ensure-functionf/1 () ensure-function) + +(defmacro ensure-functionf (&rest places) + "Multiple-place modify macro for ENSURE-FUNCTION: ensures that each of +PLACES contains a function." + `(progn ,@(mapcar (lambda (x) `(ensure-functionf/1 ,x)) places))) + +(defun disjoin (predicate &rest more-predicates) + "Returns a function that applies each of PREDICATE and MORE-PREDICATE +functions in turn to its arguments, returning the primary value of the first +predicate that returns true, without calling the remaining predicates. +If none of the predicates returns true, NIL is returned." + (declare (optimize (speed 3) (safety 1) (debug 1))) + (let ((predicate (ensure-function predicate)) + (more-predicates (mapcar #'ensure-function more-predicates))) + (lambda (&rest arguments) + (or (apply predicate arguments) + (some (lambda (p) + (declare (type function p)) + (apply p arguments)) + more-predicates))))) + +(defun conjoin (predicate &rest more-predicates) + "Returns a function that applies each of PREDICATE and MORE-PREDICATE +functions in turn to its arguments, returning NIL if any of the predicates +returns false, without calling the remaining predicates. If none of the +predicates returns false, returns the primary value of the last predicate." + (if (null more-predicates) + predicate + (lambda (&rest arguments) + (and (apply predicate arguments) + ;; Cannot simply use CL:EVERY because we want to return the + ;; non-NIL value of the last predicate if all succeed. + (do ((tail (cdr more-predicates) (cdr tail)) + (head (car more-predicates) (car tail))) + ((not tail) + (apply head arguments)) + (unless (apply head arguments) + (return nil))))))) + + +(defun compose (function &rest more-functions) + "Returns a function composed of FUNCTION and MORE-FUNCTIONS that applies its +arguments to to each in turn, starting from the rightmost of MORE-FUNCTIONS, +and then calling the next one with the primary value of the last." + (declare (optimize (speed 3) (safety 1) (debug 1))) + (reduce (lambda (f g) + (let ((f (ensure-function f)) + (g (ensure-function g))) + (lambda (&rest arguments) + (declare (dynamic-extent arguments)) + (funcall f (apply g arguments))))) + more-functions + :initial-value function)) + +(define-compiler-macro compose (function &rest more-functions) + (labels ((compose-1 (funs) + (if (cdr funs) + `(funcall ,(car funs) ,(compose-1 (cdr funs))) + `(apply ,(car funs) arguments)))) + (let* ((args (cons function more-functions)) + (funs (make-gensym-list (length args) "COMPOSE"))) + `(let ,(loop for f in funs for arg in args + collect `(,f (ensure-function ,arg))) + (declare (optimize (speed 3) (safety 1) (debug 1))) + (lambda (&rest arguments) + (declare (dynamic-extent arguments)) + ,(compose-1 funs)))))) + +(defun multiple-value-compose (function &rest more-functions) + "Returns a function composed of FUNCTION and MORE-FUNCTIONS that applies +its arguments to each in turn, starting from the rightmost of +MORE-FUNCTIONS, and then calling the next one with all the return values of +the last." + (declare (optimize (speed 3) (safety 1) (debug 1))) + (reduce (lambda (f g) + (let ((f (ensure-function f)) + (g (ensure-function g))) + (lambda (&rest arguments) + (declare (dynamic-extent arguments)) + (multiple-value-call f (apply g arguments))))) + more-functions + :initial-value function)) + +(define-compiler-macro multiple-value-compose (function &rest more-functions) + (labels ((compose-1 (funs) + (if (cdr funs) + `(multiple-value-call ,(car funs) ,(compose-1 (cdr funs))) + `(apply ,(car funs) arguments)))) + (let* ((args (cons function more-functions)) + (funs (make-gensym-list (length args) "MV-COMPOSE"))) + `(let ,(mapcar #'list funs args) + (declare (optimize (speed 3) (safety 1) (debug 1))) + (lambda (&rest arguments) + (declare (dynamic-extent arguments)) + ,(compose-1 funs)))))) + +(declaim (inline curry rcurry)) + +(defun curry (function &rest arguments) + "Returns a function that applies ARGUMENTS and the arguments +it is called with to FUNCTION." + (declare (optimize (speed 3) (safety 1))) + (let ((fn (ensure-function function))) + (lambda (&rest more) + (declare (dynamic-extent more)) + ;; Using M-V-C we don't need to append the arguments. + (multiple-value-call fn (values-list arguments) (values-list more))))) + +(define-compiler-macro curry (function &rest arguments) + (let ((curries (make-gensym-list (length arguments) "CURRY")) + (fun (gensym "FUN"))) + `(let ((,fun (ensure-function ,function)) + ,@(mapcar #'list curries arguments)) + (declare (optimize (speed 3) (safety 1))) + (lambda (&rest more) + (declare (dynamic-extent more)) + (apply ,fun ,@curries more))))) + +(defun rcurry (function &rest arguments) + "Returns a function that applies the arguments it is called +with and ARGUMENTS to FUNCTION." + (declare (optimize (speed 3) (safety 1))) + (let ((fn (ensure-function function))) + (lambda (&rest more) + (declare (dynamic-extent more)) + (multiple-value-call fn (values-list more) (values-list arguments))))) + +(define-compiler-macro rcurry (function &rest arguments) + (let ((rcurries (make-gensym-list (length arguments) "RCURRY")) + (fun (gensym "FUN"))) + `(let ((,fun (ensure-function ,function)) + ,@(mapcar #'list rcurries arguments)) + (declare (optimize (speed 3) (safety 1))) + (lambda (&rest more) + (declare (dynamic-extent more)) + (multiple-value-call ,fun (values-list more) ,@rcurries))))) + +(declaim (notinline curry rcurry)) + +(defmacro named-lambda (name lambda-list &body body) + "Expands into a lambda-expression within whose BODY NAME denotes the +corresponding function." + `(labels ((,name ,lambda-list ,@body)) + #',name)) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/hash-tables.lisp b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/hash-tables.lisp new file mode 100644 index 0000000..a9f7902 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/hash-tables.lisp @@ -0,0 +1,101 @@ +(in-package :alexandria) + +(defmacro ensure-gethash (key hash-table &optional default) + "Like GETHASH, but if KEY is not found in the HASH-TABLE saves the DEFAULT +under key before returning it. Secondary return value is true if key was +already in the table." + (once-only (key hash-table) + (with-unique-names (value presentp) + `(multiple-value-bind (,value ,presentp) (gethash ,key ,hash-table) + (if ,presentp + (values ,value ,presentp) + (values (setf (gethash ,key ,hash-table) ,default) nil)))))) + +(defun copy-hash-table (table &key key test size + rehash-size rehash-threshold) + "Returns a copy of hash table TABLE, with the same keys and values +as the TABLE. The copy has the same properties as the original, unless +overridden by the keyword arguments. + +Before each of the original values is set into the new hash-table, KEY +is invoked on the value. As KEY defaults to CL:IDENTITY, a shallow +copy is returned by default." + (setf key (or key 'identity)) + (setf test (or test (hash-table-test table))) + (setf size (or size (hash-table-size table))) + (setf rehash-size (or rehash-size (hash-table-rehash-size table))) + (setf rehash-threshold (or rehash-threshold (hash-table-rehash-threshold table))) + (let ((copy (make-hash-table :test test :size size + :rehash-size rehash-size + :rehash-threshold rehash-threshold))) + (maphash (lambda (k v) + (setf (gethash k copy) (funcall key v))) + table) + copy)) + +(declaim (inline maphash-keys)) +(defun maphash-keys (function table) + "Like MAPHASH, but calls FUNCTION with each key in the hash table TABLE." + (maphash (lambda (k v) + (declare (ignore v)) + (funcall function k)) + table)) + +(declaim (inline maphash-values)) +(defun maphash-values (function table) + "Like MAPHASH, but calls FUNCTION with each value in the hash table TABLE." + (maphash (lambda (k v) + (declare (ignore k)) + (funcall function v)) + table)) + +(defun hash-table-keys (table) + "Returns a list containing the keys of hash table TABLE." + (let ((keys nil)) + (maphash-keys (lambda (k) + (push k keys)) + table) + keys)) + +(defun hash-table-values (table) + "Returns a list containing the values of hash table TABLE." + (let ((values nil)) + (maphash-values (lambda (v) + (push v values)) + table) + values)) + +(defun hash-table-alist (table) + "Returns an association list containing the keys and values of hash table +TABLE." + (let ((alist nil)) + (maphash (lambda (k v) + (push (cons k v) alist)) + table) + alist)) + +(defun hash-table-plist (table) + "Returns a property list containing the keys and values of hash table +TABLE." + (let ((plist nil)) + (maphash (lambda (k v) + (setf plist (list* k v plist))) + table) + plist)) + +(defun alist-hash-table (alist &rest hash-table-initargs) + "Returns a hash table containing the keys and values of the association list +ALIST. Hash table is initialized using the HASH-TABLE-INITARGS." + (let ((table (apply #'make-hash-table hash-table-initargs))) + (dolist (cons alist) + (ensure-gethash (car cons) table (cdr cons))) + table)) + +(defun plist-hash-table (plist &rest hash-table-initargs) + "Returns a hash table containing the keys and values of the property list +PLIST. Hash table is initialized using the HASH-TABLE-INITARGS." + (let ((table (apply #'make-hash-table hash-table-initargs))) + (do ((tail plist (cddr tail))) + ((not tail)) + (ensure-gethash (car tail) table (cadr tail))) + table)) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/io.lisp b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/io.lisp new file mode 100644 index 0000000..28bf5e6 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/io.lisp @@ -0,0 +1,172 @@ +;; Copyright (c) 2002-2006, Edward Marco Baringer +;; All rights reserved. + +(in-package :alexandria) + +(defmacro with-open-file* ((stream filespec &key direction element-type + if-exists if-does-not-exist external-format) + &body body) + "Just like WITH-OPEN-FILE, but NIL values in the keyword arguments mean to use +the default value specified for OPEN." + (once-only (direction element-type if-exists if-does-not-exist external-format) + `(with-open-stream + (,stream (apply #'open ,filespec + (append + (when ,direction + (list :direction ,direction)) + (when ,element-type + (list :element-type ,element-type)) + (when ,if-exists + (list :if-exists ,if-exists)) + (when ,if-does-not-exist + (list :if-does-not-exist ,if-does-not-exist)) + (when ,external-format + (list :external-format ,external-format))))) + ,@body))) + +(defmacro with-input-from-file ((stream-name file-name &rest args + &key (direction nil direction-p) + &allow-other-keys) + &body body) + "Evaluate BODY with STREAM-NAME to an input stream on the file +FILE-NAME. ARGS is sent as is to the call to OPEN except EXTERNAL-FORMAT, +which is only sent to WITH-OPEN-FILE when it's not NIL." + (declare (ignore direction)) + (when direction-p + (error "Can't specify :DIRECTION for WITH-INPUT-FROM-FILE.")) + `(with-open-file* (,stream-name ,file-name :direction :input ,@args) + ,@body)) + +(defmacro with-output-to-file ((stream-name file-name &rest args + &key (direction nil direction-p) + &allow-other-keys) + &body body) + "Evaluate BODY with STREAM-NAME to an output stream on the file +FILE-NAME. ARGS is sent as is to the call to OPEN except EXTERNAL-FORMAT, +which is only sent to WITH-OPEN-FILE when it's not NIL." + (declare (ignore direction)) + (when direction-p + (error "Can't specify :DIRECTION for WITH-OUTPUT-TO-FILE.")) + `(with-open-file* (,stream-name ,file-name :direction :output ,@args) + ,@body)) + +(defun read-stream-content-into-string (stream &key (buffer-size 4096)) + "Return the \"content\" of STREAM as a fresh string." + (check-type buffer-size positive-integer) + (let ((*print-pretty* nil)) + (with-output-to-string (datum) + (let ((buffer (make-array buffer-size :element-type 'character))) + (loop + :for bytes-read = (read-sequence buffer stream) + :do (write-sequence buffer datum :start 0 :end bytes-read) + :while (= bytes-read buffer-size)))))) + +(defun read-file-into-string (pathname &key (buffer-size 4096) external-format) + "Return the contents of the file denoted by PATHNAME as a fresh string. + +The EXTERNAL-FORMAT parameter will be passed directly to WITH-OPEN-FILE +unless it's NIL, which means the system default." + (with-input-from-file + (file-stream pathname :external-format external-format) + (read-stream-content-into-string file-stream :buffer-size buffer-size))) + +(defun write-string-into-file (string pathname &key (if-exists :error) + if-does-not-exist + external-format) + "Write STRING to PATHNAME. + +The EXTERNAL-FORMAT parameter will be passed directly to WITH-OPEN-FILE +unless it's NIL, which means the system default." + (with-output-to-file (file-stream pathname :if-exists if-exists + :if-does-not-exist if-does-not-exist + :external-format external-format) + (write-sequence string file-stream))) + +(defun read-stream-content-into-byte-vector (stream &key ((%length length)) + (initial-size 4096)) + "Return \"content\" of STREAM as freshly allocated (unsigned-byte 8) vector." + (check-type length (or null non-negative-integer)) + (check-type initial-size positive-integer) + (do ((buffer (make-array (or length initial-size) + :element-type '(unsigned-byte 8))) + (offset 0) + (offset-wanted 0)) + ((or (/= offset-wanted offset) + (and length (>= offset length))) + (if (= offset (length buffer)) + buffer + (subseq buffer 0 offset))) + (unless (zerop offset) + (let ((new-buffer (make-array (* 2 (length buffer)) + :element-type '(unsigned-byte 8)))) + (replace new-buffer buffer) + (setf buffer new-buffer))) + (setf offset-wanted (length buffer) + offset (read-sequence buffer stream :start offset)))) + +(defun read-file-into-byte-vector (pathname) + "Read PATHNAME into a freshly allocated (unsigned-byte 8) vector." + (with-input-from-file (stream pathname :element-type '(unsigned-byte 8)) + (read-stream-content-into-byte-vector stream '%length (file-length stream)))) + +(defun write-byte-vector-into-file (bytes pathname &key (if-exists :error) + if-does-not-exist) + "Write BYTES to PATHNAME." + (check-type bytes (vector (unsigned-byte 8))) + (with-output-to-file (stream pathname :if-exists if-exists + :if-does-not-exist if-does-not-exist + :element-type '(unsigned-byte 8)) + (write-sequence bytes stream))) + +(defun copy-file (from to &key (if-to-exists :supersede) + (element-type '(unsigned-byte 8)) finish-output) + (with-input-from-file (input from :element-type element-type) + (with-output-to-file (output to :element-type element-type + :if-exists if-to-exists) + (copy-stream input output + :element-type element-type + :finish-output finish-output)))) + +(defun copy-stream (input output &key (element-type (stream-element-type input)) + (buffer-size 4096) + (buffer (make-array buffer-size :element-type element-type)) + (start 0) end + finish-output) + "Reads data from INPUT and writes it to OUTPUT. Both INPUT and OUTPUT must +be streams, they will be passed to READ-SEQUENCE and WRITE-SEQUENCE and must have +compatible element-types." + (check-type start non-negative-integer) + (check-type end (or null non-negative-integer)) + (check-type buffer-size positive-integer) + (when (and end + (< end start)) + (error "END is smaller than START in ~S" 'copy-stream)) + (let ((output-position 0) + (input-position 0)) + (unless (zerop start) + ;; FIXME add platform specific optimization to skip seekable streams + (loop while (< input-position start) + do (let ((n (read-sequence buffer input + :end (min (length buffer) + (- start input-position))))) + (when (zerop n) + (error "~@" 'copy-stream start)) + (incf input-position n)))) + (assert (= input-position start)) + (loop while (or (null end) (< input-position end)) + do (let ((n (read-sequence buffer input + :end (when end + (min (length buffer) + (- end input-position)))))) + (when (zerop n) + (if end + (error "~@" 'copy-stream end) + (return))) + (incf input-position n) + (write-sequence buffer output :end n) + (incf output-position n))) + (when finish-output + (finish-output output)) + output-position)) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/lists.lisp b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/lists.lisp new file mode 100644 index 0000000..5128607 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/lists.lisp @@ -0,0 +1,367 @@ +(in-package :alexandria) + +(declaim (inline safe-endp)) +(defun safe-endp (x) + (declare (optimize safety)) + (endp x)) + +(defun alist-plist (alist) + "Returns a property list containing the same keys and values as the +association list ALIST in the same order." + (let (plist) + (dolist (pair alist) + (push (car pair) plist) + (push (cdr pair) plist)) + (nreverse plist))) + +(defun plist-alist (plist) + "Returns an association list containing the same keys and values as the +property list PLIST in the same order." + (let (alist) + (do ((tail plist (cddr tail))) + ((safe-endp tail) (nreverse alist)) + (push (cons (car tail) (cadr tail)) alist)))) + +(declaim (inline racons)) +(defun racons (key value ralist) + (acons value key ralist)) + +(macrolet + ((define-alist-get (name get-entry get-value-from-entry add doc) + `(progn + (declaim (inline ,name)) + (defun ,name (alist key &key (test 'eql)) + ,doc + (let ((entry (,get-entry key alist :test test))) + (values (,get-value-from-entry entry) entry))) + (define-setf-expander ,name (place key &key (test ''eql) + &environment env) + (multiple-value-bind + (temporary-variables initforms newvals setter getter) + (get-setf-expansion place env) + (when (cdr newvals) + (error "~A cannot store multiple values in one place" ',name)) + (with-unique-names (new-value key-val test-val alist entry) + (values + (append temporary-variables + (list alist + key-val + test-val + entry)) + (append initforms + (list getter + key + test + `(,',get-entry ,key-val ,alist :test ,test-val))) + `(,new-value) + `(cond + (,entry + (setf (,',get-value-from-entry ,entry) ,new-value)) + (t + (let ,newvals + (setf ,(first newvals) (,',add ,key ,new-value ,alist)) + ,setter + ,new-value))) + `(,',get-value-from-entry ,entry)))))))) + (define-alist-get assoc-value assoc cdr acons +"ASSOC-VALUE is an alist accessor very much like ASSOC, but it can +be used with SETF.") + (define-alist-get rassoc-value rassoc car racons +"RASSOC-VALUE is an alist accessor very much like RASSOC, but it can +be used with SETF.")) + +(defun malformed-plist (plist) + (error "Malformed plist: ~S" plist)) + +(defmacro doplist ((key val plist &optional values) &body body) + "Iterates over elements of PLIST. BODY can be preceded by +declarations, and is like a TAGBODY. RETURN may be used to terminate +the iteration early. If RETURN is not used, returns VALUES." + (multiple-value-bind (forms declarations) (parse-body body) + (with-gensyms (tail loop results) + `(block nil + (flet ((,results () + (let (,key ,val) + (declare (ignorable ,key ,val)) + (return ,values)))) + (let* ((,tail ,plist) + (,key (if ,tail + (pop ,tail) + (,results))) + (,val (if ,tail + (pop ,tail) + (malformed-plist ',plist)))) + (declare (ignorable ,key ,val)) + ,@declarations + (tagbody + ,loop + ,@forms + (setf ,key (if ,tail + (pop ,tail) + (,results)) + ,val (if ,tail + (pop ,tail) + (malformed-plist ',plist))) + (go ,loop)))))))) + +(define-modify-macro appendf (&rest lists) append + "Modify-macro for APPEND. Appends LISTS to the place designated by the first +argument.") + +(define-modify-macro nconcf (&rest lists) nconc + "Modify-macro for NCONC. Concatenates LISTS to place designated by the first +argument.") + +(define-modify-macro unionf (list &rest args) union + "Modify-macro for UNION. Saves the union of LIST and the contents of the +place designated by the first argument to the designated place.") + +(define-modify-macro nunionf (list &rest args) nunion + "Modify-macro for NUNION. Saves the union of LIST and the contents of the +place designated by the first argument to the designated place. May modify +either argument.") + +(define-modify-macro reversef () reverse + "Modify-macro for REVERSE. Copies and reverses the list stored in the given +place and saves back the result into the place.") + +(define-modify-macro nreversef () nreverse + "Modify-macro for NREVERSE. Reverses the list stored in the given place by +destructively modifying it and saves back the result into the place.") + +(defun circular-list (&rest elements) + "Creates a circular list of ELEMENTS." + (let ((cycle (copy-list elements))) + (nconc cycle cycle))) + +(defun circular-list-p (object) + "Returns true if OBJECT is a circular list, NIL otherwise." + (and (listp object) + (do ((fast object (cddr fast)) + (slow (cons (car object) (cdr object)) (cdr slow))) + (nil) + (unless (and (consp fast) (listp (cdr fast))) + (return nil)) + (when (eq fast slow) + (return t))))) + +(defun circular-tree-p (object) + "Returns true if OBJECT is a circular tree, NIL otherwise." + (labels ((circularp (object seen) + (and (consp object) + (do ((fast (cons (car object) (cdr object)) (cddr fast)) + (slow object (cdr slow))) + (nil) + (when (or (eq fast slow) (member slow seen)) + (return-from circular-tree-p t)) + (when (or (not (consp fast)) (not (consp (cdr slow)))) + (return + (do ((tail object (cdr tail))) + ((not (consp tail)) + nil) + (let ((elt (car tail))) + (circularp elt (cons object seen)))))))))) + (circularp object nil))) + +(defun proper-list-p (object) + "Returns true if OBJECT is a proper list." + (cond ((not object) + t) + ((consp object) + (do ((fast object (cddr fast)) + (slow (cons (car object) (cdr object)) (cdr slow))) + (nil) + (unless (and (listp fast) (consp (cdr fast))) + (return (and (listp fast) (not (cdr fast))))) + (when (eq fast slow) + (return nil)))) + (t + nil))) + +(deftype proper-list () + "Type designator for proper lists. Implemented as a SATISFIES type, hence +not recommended for performance intensive use. Main usefullness as a type +designator of the expected type in a TYPE-ERROR." + `(and list (satisfies proper-list-p))) + +(defun circular-list-error (list) + (error 'type-error + :datum list + :expected-type '(and list (not circular-list)))) + +(macrolet ((def (name lambda-list doc step declare ret1 ret2) + (assert (member 'list lambda-list)) + `(defun ,name ,lambda-list + ,doc + (do ((last list fast) + (fast list (cddr fast)) + (slow (cons (car list) (cdr list)) (cdr slow)) + ,@(when step (list step))) + (nil) + (declare (dynamic-extent slow) ,@(when declare (list declare)) + (ignorable last)) + (when (safe-endp fast) + (return ,ret1)) + (when (safe-endp (cdr fast)) + (return ,ret2)) + (when (eq fast slow) + (circular-list-error list)))))) + (def proper-list-length (list) + "Returns length of LIST, signalling an error if it is not a proper list." + (n 1 (+ n 2)) + ;; KLUDGE: Most implementations don't actually support lists with bignum + ;; elements -- and this is WAY faster on most implementations then declaring + ;; N to be an UNSIGNED-BYTE. + (fixnum n) + (1- n) + n) + + (def lastcar (list) + "Returns the last element of LIST. Signals a type-error if LIST is not a +proper list." + nil + nil + (cadr last) + (car fast)) + + (def (setf lastcar) (object list) + "Sets the last element of LIST. Signals a type-error if LIST is not a proper +list." + nil + nil + (setf (cadr last) object) + (setf (car fast) object))) + +(defun make-circular-list (length &key initial-element) + "Creates a circular list of LENGTH with the given INITIAL-ELEMENT." + (let ((cycle (make-list length :initial-element initial-element))) + (nconc cycle cycle))) + +(deftype circular-list () + "Type designator for circular lists. Implemented as a SATISFIES type, so not +recommended for performance intensive use. Main usefullness as the +expected-type designator of a TYPE-ERROR." + `(satisfies circular-list-p)) + +(defun ensure-car (thing) + "If THING is a CONS, its CAR is returned. Otherwise THING is returned." + (if (consp thing) + (car thing) + thing)) + +(defun ensure-cons (cons) + "If CONS is a cons, it is returned. Otherwise returns a fresh cons with CONS + in the car, and NIL in the cdr." + (if (consp cons) + cons + (cons cons nil))) + +(defun ensure-list (list) + "If LIST is a list, it is returned. Otherwise returns the list designated by LIST." + (if (listp list) + list + (list list))) + +(defun remove-from-plist (plist &rest keys) + "Returns a propery-list with same keys and values as PLIST, except that keys +in the list designated by KEYS and values corresponding to them are removed. +The returned property-list may share structure with the PLIST, but PLIST is +not destructively modified. Keys are compared using EQ." + (declare (optimize (speed 3))) + ;; FIXME: possible optimization: (remove-from-plist '(:x 0 :a 1 :b 2) :a) + ;; could return the tail without consing up a new list. + (loop for (key . rest) on plist by #'cddr + do (assert rest () "Expected a proper plist, got ~S" plist) + unless (member key keys :test #'eq) + collect key and collect (first rest))) + +(defun delete-from-plist (plist &rest keys) + "Just like REMOVE-FROM-PLIST, but this version may destructively modify the +provided PLIST." + (declare (optimize speed)) + (loop with head = plist + with tail = nil ; a nil tail means an empty result so far + for (key . rest) on plist by #'cddr + do (assert rest () "Expected a proper plist, got ~S" plist) + (if (member key keys :test #'eq) + ;; skip over this pair + (let ((next (cdr rest))) + (if tail + (setf (cdr tail) next) + (setf head next))) + ;; keep this pair + (setf tail rest)) + finally (return head))) + +(define-modify-macro remove-from-plistf (&rest keys) remove-from-plist + "Modify macro for REMOVE-FROM-PLIST.") +(define-modify-macro delete-from-plistf (&rest keys) delete-from-plist + "Modify macro for DELETE-FROM-PLIST.") + +(declaim (inline sans)) +(defun sans (plist &rest keys) + "Alias of REMOVE-FROM-PLIST for backward compatibility." + (apply #'remove-from-plist plist keys)) + +(defun mappend (function &rest lists) + "Applies FUNCTION to respective element(s) of each LIST, appending all the +all the result list to a single list. FUNCTION must return a list." + (loop for results in (apply #'mapcar function lists) + append results)) + +(defun setp (object &key (test #'eql) (key #'identity)) + "Returns true if OBJECT is a list that denotes a set, NIL otherwise. A list +denotes a set if each element of the list is unique under KEY and TEST." + (and (listp object) + (let (seen) + (dolist (elt object t) + (let ((key (funcall key elt))) + (if (member key seen :test test) + (return nil) + (push key seen))))))) + +(defun set-equal (list1 list2 &key (test #'eql) (key nil keyp)) + "Returns true if every element of LIST1 matches some element of LIST2 and +every element of LIST2 matches some element of LIST1. Otherwise returns false." + (let ((keylist1 (if keyp (mapcar key list1) list1)) + (keylist2 (if keyp (mapcar key list2) list2))) + (and (dolist (elt keylist1 t) + (or (member elt keylist2 :test test) + (return nil))) + (dolist (elt keylist2 t) + (or (member elt keylist1 :test test) + (return nil)))))) + +(defun map-product (function list &rest more-lists) + "Returns a list containing the results of calling FUNCTION with one argument +from LIST, and one from each of MORE-LISTS for each combination of arguments. +In other words, returns the product of LIST and MORE-LISTS using FUNCTION. + +Example: + + (map-product 'list '(1 2) '(3 4) '(5 6)) + => ((1 3 5) (1 3 6) (1 4 5) (1 4 6) + (2 3 5) (2 3 6) (2 4 5) (2 4 6)) +" + (labels ((%map-product (f lists) + (let ((more (cdr lists)) + (one (car lists))) + (if (not more) + (mapcar f one) + (mappend (lambda (x) + (%map-product (curry f x) more)) + one))))) + (%map-product (ensure-function function) (cons list more-lists)))) + +(defun flatten (tree) + "Traverses the tree in order, collecting non-null leaves into a list." + (let (list) + (labels ((traverse (subtree) + (when subtree + (if (consp subtree) + (progn + (traverse (car subtree)) + (traverse (cdr subtree))) + (push subtree list))))) + (traverse tree)) + (nreverse list))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/macros.lisp b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/macros.lisp new file mode 100644 index 0000000..4364ad6 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/macros.lisp @@ -0,0 +1,370 @@ +(in-package :alexandria) + +(defmacro with-gensyms (names &body forms) + "Binds a set of variables to gensyms and evaluates the implicit progn FORMS. + +Each element within NAMES is either a symbol SYMBOL or a pair (SYMBOL +STRING-DESIGNATOR). Bare symbols are equivalent to the pair (SYMBOL SYMBOL). + +Each pair (SYMBOL STRING-DESIGNATOR) specifies that the variable named by SYMBOL +should be bound to a symbol constructed using GENSYM with the string designated +by STRING-DESIGNATOR being its first argument." + `(let ,(mapcar (lambda (name) + (multiple-value-bind (symbol string) + (etypecase name + (symbol + (values name (symbol-name name))) + ((cons symbol (cons string-designator null)) + (values (first name) (string (second name))))) + `(,symbol (gensym ,string)))) + names) + ,@forms)) + +(defmacro with-unique-names (names &body forms) + "Alias for WITH-GENSYMS." + `(with-gensyms ,names ,@forms)) + +(defmacro once-only (specs &body forms) + "Constructs code whose primary goal is to help automate the handling of +multiple evaluation within macros. Multiple evaluation is handled by introducing +intermediate variables, in order to reuse the result of an expression. + +The returned value is a list of the form + + (let (( ) + ... + ( )) + ) + +where GENSYM-1, ..., GENSYM-N are the intermediate variables introduced in order +to evaluate EXPR-1, ..., EXPR-N once, only. RES is code that is the result of +evaluating the implicit progn FORMS within a special context determined by +SPECS. RES should make use of (reference) the intermediate variables. + +Each element within SPECS is either a symbol SYMBOL or a pair (SYMBOL INITFORM). +Bare symbols are equivalent to the pair (SYMBOL SYMBOL). + +Each pair (SYMBOL INITFORM) specifies a single intermediate variable: + +- INITFORM is an expression evaluated to produce EXPR-i + +- SYMBOL is the name of the variable that will be bound around FORMS to the + corresponding gensym GENSYM-i, in order for FORMS to generate RES that + references the intermediate variable + +The evaluation of INITFORMs and binding of SYMBOLs resembles LET. INITFORMs of +all the pairs are evaluated before binding SYMBOLs and evaluating FORMS. + +Example: + + The following expression + + (let ((x '(incf y))) + (once-only (x) + `(cons ,x ,x))) + + ;;; => + ;;; (let ((#1=#:X123 (incf y))) + ;;; (cons #1# #1#)) + + could be used within a macro to avoid multiple evaluation like so + + (defmacro cons1 (x) + (once-only (x) + `(cons ,x ,x))) + + (let ((y 0)) + (cons1 (incf y))) + + ;;; => (1 . 1) + +Example: + + The following expression demonstrates the usage of the INITFORM field + + (let ((expr '(incf y))) + (once-only ((var `(1+ ,expr))) + `(list ',expr ,var ,var))) + + ;;; => + ;;; (let ((#1=#:VAR123 (1+ (incf y)))) + ;;; (list '(incf y) #1# #1)) + + which could be used like so + + (defmacro print-succ-twice (expr) + (once-only ((var `(1+ ,expr))) + `(format t \"Expr: ~s, Once: ~s, Twice: ~s~%\" ',expr ,var ,var))) + + (let ((y 10)) + (print-succ-twice (incf y))) + + ;;; >> + ;;; Expr: (INCF Y), Once: 12, Twice: 12" + (let ((gensyms (make-gensym-list (length specs) "ONCE-ONLY")) + (names-and-forms (mapcar (lambda (spec) + (etypecase spec + (list + (destructuring-bind (name form) spec + (cons name form))) + (symbol + (cons spec spec)))) + specs))) + ;; bind in user-macro + `(let ,(mapcar (lambda (g n) (list g `(gensym ,(string (car n))))) + gensyms names-and-forms) + ;; bind in final expansion + `(let (,,@(mapcar (lambda (g n) + ``(,,g ,,(cdr n))) + gensyms names-and-forms)) + ;; bind in user-macro + ,(let ,(mapcar (lambda (n g) (list (car n) g)) + names-and-forms gensyms) + ,@forms))))) + +(defun parse-body (body &key documentation whole) + "Parses BODY into (values remaining-forms declarations doc-string). +Documentation strings are recognized only if DOCUMENTATION is true. +Syntax errors in body are signalled and WHOLE is used in the signal +arguments when given." + (let ((doc nil) + (decls nil) + (current nil)) + (tagbody + :declarations + (setf current (car body)) + (when (and documentation (stringp current) (cdr body)) + (if doc + (error "Too many documentation strings in ~S." (or whole body)) + (setf doc (pop body))) + (go :declarations)) + (when (and (listp current) (eql (first current) 'declare)) + (push (pop body) decls) + (go :declarations))) + (values body (nreverse decls) doc))) + +(defun parse-ordinary-lambda-list (lambda-list &key (normalize t) + allow-specializers + (normalize-optional normalize) + (normalize-keyword normalize) + (normalize-auxilary normalize)) + "Parses an ordinary lambda-list, returning as multiple values: + +1. Required parameters. + +2. Optional parameter specifications, normalized into form: + + (name init suppliedp) + +3. Name of the rest parameter, or NIL. + +4. Keyword parameter specifications, normalized into form: + + ((keyword-name name) init suppliedp) + +5. Boolean indicating &ALLOW-OTHER-KEYS presence. + +6. &AUX parameter specifications, normalized into form + + (name init). + +7. Existence of &KEY in the lambda-list. + +Signals a PROGRAM-ERROR is the lambda-list is malformed." + (let ((state :required) + (allow-other-keys nil) + (auxp nil) + (required nil) + (optional nil) + (rest nil) + (keys nil) + (keyp nil) + (aux nil)) + (labels ((fail (elt) + (simple-program-error "Misplaced ~S in ordinary lambda-list:~% ~S" + elt lambda-list)) + (check-variable (elt what &optional (allow-specializers allow-specializers)) + (unless (and (or (symbolp elt) + (and allow-specializers + (consp elt) (= 2 (length elt)) (symbolp (first elt)))) + (not (constantp elt))) + (simple-program-error "Invalid ~A ~S in ordinary lambda-list:~% ~S" + what elt lambda-list))) + (check-spec (spec what) + (destructuring-bind (init suppliedp) spec + (declare (ignore init)) + (check-variable suppliedp what nil)))) + (dolist (elt lambda-list) + (case elt + (&optional + (if (eq state :required) + (setf state elt) + (fail elt))) + (&rest + (if (member state '(:required &optional)) + (setf state elt) + (fail elt))) + (&key + (if (member state '(:required &optional :after-rest)) + (setf state elt) + (fail elt)) + (setf keyp t)) + (&allow-other-keys + (if (eq state '&key) + (setf allow-other-keys t + state elt) + (fail elt))) + (&aux + (cond ((eq state '&rest) + (fail elt)) + (auxp + (simple-program-error "Multiple ~S in ordinary lambda-list:~% ~S" + elt lambda-list)) + (t + (setf auxp t + state elt)) + )) + (otherwise + (when (member elt '#.(set-difference lambda-list-keywords + '(&optional &rest &key &allow-other-keys &aux))) + (simple-program-error + "Bad lambda-list keyword ~S in ordinary lambda-list:~% ~S" + elt lambda-list)) + (case state + (:required + (check-variable elt "required parameter") + (push elt required)) + (&optional + (cond ((consp elt) + (destructuring-bind (name &rest tail) elt + (check-variable name "optional parameter") + (cond ((cdr tail) + (check-spec tail "optional-supplied-p parameter")) + ((and normalize-optional tail) + (setf elt (append elt '(nil)))) + (normalize-optional + (setf elt (append elt '(nil nil))))))) + (t + (check-variable elt "optional parameter") + (when normalize-optional + (setf elt (cons elt '(nil nil)))))) + (push (ensure-list elt) optional)) + (&rest + (check-variable elt "rest parameter") + (setf rest elt + state :after-rest)) + (&key + (cond ((consp elt) + (destructuring-bind (var-or-kv &rest tail) elt + (cond ((consp var-or-kv) + (destructuring-bind (keyword var) var-or-kv + (unless (symbolp keyword) + (simple-program-error "Invalid keyword name ~S in ordinary ~ + lambda-list:~% ~S" + keyword lambda-list)) + (check-variable var "keyword parameter"))) + (t + (check-variable var-or-kv "keyword parameter") + (when normalize-keyword + (setf var-or-kv (list (make-keyword var-or-kv) var-or-kv))))) + (cond ((cdr tail) + (check-spec tail "keyword-supplied-p parameter")) + ((and normalize-keyword tail) + (setf tail (append tail '(nil)))) + (normalize-keyword + (setf tail '(nil nil)))) + (setf elt (cons var-or-kv tail)))) + (t + (check-variable elt "keyword parameter") + (setf elt (if normalize-keyword + (list (list (make-keyword elt) elt) nil nil) + elt)))) + (push elt keys)) + (&aux + (if (consp elt) + (destructuring-bind (var &optional init) elt + (declare (ignore init)) + (check-variable var "&aux parameter")) + (progn + (check-variable elt "&aux parameter") + (setf elt (list* elt (when normalize-auxilary + '(nil)))))) + (push elt aux)) + (t + (simple-program-error "Invalid ordinary lambda-list:~% ~S" lambda-list))))))) + (values (nreverse required) (nreverse optional) rest (nreverse keys) + allow-other-keys (nreverse aux) keyp))) + +;;;; DESTRUCTURING-*CASE + +(defun expand-destructuring-case (key clauses case) + (once-only (key) + `(if (typep ,key 'cons) + (,case (car ,key) + ,@(mapcar (lambda (clause) + (destructuring-bind ((keys . lambda-list) &body body) clause + `(,keys + (destructuring-bind ,lambda-list (cdr ,key) + ,@body)))) + clauses)) + (error "Invalid key to DESTRUCTURING-~S: ~S" ',case ,key)))) + +(defmacro destructuring-case (keyform &body clauses) + "DESTRUCTURING-CASE, -CCASE, and -ECASE are a combination of CASE and DESTRUCTURING-BIND. +KEYFORM must evaluate to a CONS. + +Clauses are of the form: + + ((CASE-KEYS . DESTRUCTURING-LAMBDA-LIST) FORM*) + +The clause whose CASE-KEYS matches CAR of KEY, as if by CASE, CCASE, or ECASE, +is selected, and FORMs are then executed with CDR of KEY is destructured and +bound by the DESTRUCTURING-LAMBDA-LIST. + +Example: + + (defun dcase (x) + (destructuring-case x + ((:foo a b) + (format nil \"foo: ~S, ~S\" a b)) + ((:bar &key a b) + (format nil \"bar: ~S, ~S\" a b)) + (((:alt1 :alt2) a) + (format nil \"alt: ~S\" a)) + ((t &rest rest) + (format nil \"unknown: ~S\" rest)))) + + (dcase (list :foo 1 2)) ; => \"foo: 1, 2\" + (dcase (list :bar :a 1 :b 2)) ; => \"bar: 1, 2\" + (dcase (list :alt1 1)) ; => \"alt: 1\" + (dcase (list :alt2 2)) ; => \"alt: 2\" + (dcase (list :quux 1 2 3)) ; => \"unknown: 1, 2, 3\" + + (defun decase (x) + (destructuring-case x + ((:foo a b) + (format nil \"foo: ~S, ~S\" a b)) + ((:bar &key a b) + (format nil \"bar: ~S, ~S\" a b)) + (((:alt1 :alt2) a) + (format nil \"alt: ~S\" a)))) + + (decase (list :foo 1 2)) ; => \"foo: 1, 2\" + (decase (list :bar :a 1 :b 2)) ; => \"bar: 1, 2\" + (decase (list :alt1 1)) ; => \"alt: 1\" + (decase (list :alt2 2)) ; => \"alt: 2\" + (decase (list :quux 1 2 3)) ; =| error +" + (expand-destructuring-case keyform clauses 'case)) + +(defmacro destructuring-ccase (keyform &body clauses) + (expand-destructuring-case keyform clauses 'ccase)) + +(defmacro destructuring-ecase (keyform &body clauses) + (expand-destructuring-case keyform clauses 'ecase)) + +(dolist (name '(destructuring-ccase destructuring-ecase)) + (setf (documentation name 'function) (documentation 'destructuring-case 'function))) + + + diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/numbers.lisp b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/numbers.lisp new file mode 100644 index 0000000..1c06f71 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/numbers.lisp @@ -0,0 +1,295 @@ +(in-package :alexandria) + +(declaim (inline clamp)) +(defun clamp (number min max) + "Clamps the NUMBER into [min, max] range. Returns MIN if NUMBER is lesser then +MIN and MAX if NUMBER is greater then MAX, otherwise returns NUMBER." + (if (< number min) + min + (if (> number max) + max + number))) + +(defun gaussian-random (&optional min max) + "Returns two gaussian random double floats as the primary and secondary value, +optionally constrained by MIN and MAX. Gaussian random numbers form a standard +normal distribution around 0.0d0. + +Sufficiently positive MIN or negative MAX will cause the algorithm used to +take a very long time. If MIN is positive it should be close to zero, and +similarly if MAX is negative it should be close to zero." + (macrolet + ((valid (x) + `(<= (or min ,x) ,x (or max ,x)) )) + (labels + ((gauss () + (loop + for x1 = (- (random 2.0d0) 1.0d0) + for x2 = (- (random 2.0d0) 1.0d0) + for w = (+ (expt x1 2) (expt x2 2)) + when (< w 1.0d0) + do (let ((v (sqrt (/ (* -2.0d0 (log w)) w)))) + (return (values (* x1 v) (* x2 v)))))) + (guard (x) + (unless (valid x) + (tagbody + :retry + (multiple-value-bind (x1 x2) (gauss) + (when (valid x1) + (setf x x1) + (go :done)) + (when (valid x2) + (setf x x2) + (go :done)) + (go :retry)) + :done)) + x)) + (multiple-value-bind + (g1 g2) (gauss) + (values (guard g1) (guard g2)))))) + +(declaim (inline iota)) +(defun iota (n &key (start 0) (step 1)) + "Return a list of n numbers, starting from START (with numeric contagion +from STEP applied), each consequtive number being the sum of the previous one +and STEP. START defaults to 0 and STEP to 1. + +Examples: + + (iota 4) => (0 1 2 3) + (iota 3 :start 1 :step 1.0) => (1.0 2.0 3.0) + (iota 3 :start -1 :step -1/2) => (-1 -3/2 -2) +" + (declare (type (integer 0) n) (number start step)) + (loop ;; KLUDGE: get numeric contagion right for the first element too + for i = (+ (- (+ start step) step)) then (+ i step) + repeat n + collect i)) + +(declaim (inline map-iota)) +(defun map-iota (function n &key (start 0) (step 1)) + "Calls FUNCTION with N numbers, starting from START (with numeric contagion +from STEP applied), each consequtive number being the sum of the previous one +and STEP. START defaults to 0 and STEP to 1. Returns N. + +Examples: + + (map-iota #'print 3 :start 1 :step 1.0) => 3 + ;;; 1.0 + ;;; 2.0 + ;;; 3.0 +" + (declare (type (integer 0) n) (number start step)) + (loop ;; KLUDGE: get numeric contagion right for the first element too + for i = (+ start (- step step)) then (+ i step) + repeat n + do (funcall function i)) + n) + +(declaim (inline lerp)) +(defun lerp (v a b) + "Returns the result of linear interpolation between A and B, using the +interpolation coefficient V." + ;; The correct version is numerically stable, at the expense of an + ;; extra multiply. See (lerp 0.1 4 25) with (+ a (* v (- b a))). The + ;; unstable version can often be converted to a fast instruction on + ;; a lot of machines, though this is machine/implementation + ;; specific. As alexandria is more about correct code, than + ;; efficiency, and we're only talking about a single extra multiply, + ;; many would prefer the stable version + (+ (* (- 1.0 v) a) (* v b))) + +(declaim (inline mean)) +(defun mean (sample) + "Returns the mean of SAMPLE. SAMPLE must be a sequence of numbers." + (/ (reduce #'+ sample) (length sample))) + +(defun median (sample) + "Returns median of SAMPLE. SAMPLE must be a sequence of real numbers." + ;; Implements and uses the quick-select algorithm to find the median + ;; https://en.wikipedia.org/wiki/Quickselect + + (labels ((randint-in-range (start-int end-int) + "Returns a random integer in the specified range, inclusive" + (+ start-int (random (1+ (- end-int start-int))))) + (partition (vec start-i end-i) + "Implements the partition function, which performs a partial + sort of vec around the (randomly) chosen pivot. + Returns the index where the pivot element would be located + in a correctly-sorted array" + (if (= start-i end-i) + start-i + (let ((pivot-i (randint-in-range start-i end-i))) + (rotatef (aref vec start-i) (aref vec pivot-i)) + (let ((swap-i end-i)) + (loop for i from swap-i downto (1+ start-i) do + (when (>= (aref vec i) (aref vec start-i)) + (rotatef (aref vec i) (aref vec swap-i)) + (decf swap-i))) + (rotatef (aref vec swap-i) (aref vec start-i)) + swap-i))))) + + (let* ((vector (copy-sequence 'vector sample)) + (len (length vector)) + (mid-i (ash len -1)) + (i 0) + (j (1- len))) + + (loop for correct-pos = (partition vector i j) + while (/= correct-pos mid-i) do + (if (< correct-pos mid-i) + (setf i (1+ correct-pos)) + (setf j (1- correct-pos)))) + + (if (oddp len) + (aref vector mid-i) + (* 1/2 + (+ (aref vector mid-i) + (reduce #'max (make-array + mid-i + :displaced-to vector)))))))) + +(declaim (inline variance)) +(defun variance (sample &key (biased t)) + "Variance of SAMPLE. Returns the biased variance if BIASED is true (the default), +and the unbiased estimator of variance if BIASED is false. SAMPLE must be a +sequence of numbers." + (let ((mean (mean sample))) + (/ (reduce (lambda (a b) + (+ a (expt (- b mean) 2))) + sample + :initial-value 0) + (- (length sample) (if biased 0 1))))) + +(declaim (inline standard-deviation)) +(defun standard-deviation (sample &key (biased t)) + "Standard deviation of SAMPLE. Returns the biased standard deviation if +BIASED is true (the default), and the square root of the unbiased estimator +for variance if BIASED is false (which is not the same as the unbiased +estimator for standard deviation). SAMPLE must be a sequence of numbers." + (sqrt (variance sample :biased biased))) + +(define-modify-macro maxf (&rest numbers) max + "Modify-macro for MAX. Sets place designated by the first argument to the +maximum of its original value and NUMBERS.") + +(define-modify-macro minf (&rest numbers) min + "Modify-macro for MIN. Sets place designated by the first argument to the +minimum of its original value and NUMBERS.") + +;;;; Factorial + +;;; KLUDGE: This is really dependant on the numbers in question: for +;;; small numbers this is larger, and vice versa. Ideally instead of a +;;; constant we would have RANGE-FAST-TO-MULTIPLY-DIRECTLY-P. +(defconstant +factorial-bisection-range-limit+ 8) + +;;; KLUDGE: This is really platform dependant: ideally we would use +;;; (load-time-value (find-good-direct-multiplication-limit)) instead. +(defconstant +factorial-direct-multiplication-limit+ 13) + +(defun %multiply-range (i j) + ;; We use a a bit of cleverness here: + ;; + ;; 1. For large factorials we bisect in order to avoid expensive bignum + ;; multiplications: 1 x 2 x 3 x ... runs into bignums pretty soon, + ;; and once it does that all further multiplications will be with bignums. + ;; + ;; By instead doing the multiplication in a tree like + ;; ((1 x 2) x (3 x 4)) x ((5 x 6) x (7 x 8)) + ;; we manage to get less bignums. + ;; + ;; 2. Division isn't exactly free either, however, so we don't bisect + ;; all the way down, but multiply ranges of integers close to each + ;; other directly. + ;; + ;; For even better results it should be possible to use prime + ;; factorization magic, but Nikodemus ran out of steam. + ;; + ;; KLUDGE: We support factorials of bignums, but it seems quite + ;; unlikely anyone would ever be able to use them on a modern lisp, + ;; since the resulting numbers are unlikely to fit in memory... but + ;; it would be extremely unelegant to define FACTORIAL only on + ;; fixnums, _and_ on lisps with 16 bit fixnums this can actually be + ;; needed. + (labels ((bisect (j k) + (declare (type (integer 1 #.most-positive-fixnum) j k)) + (if (< (- k j) +factorial-bisection-range-limit+) + (multiply-range j k) + (let ((middle (+ j (truncate (- k j) 2)))) + (* (bisect j middle) + (bisect (+ middle 1) k))))) + (bisect-big (j k) + (declare (type (integer 1) j k)) + (if (= j k) + j + (let ((middle (+ j (truncate (- k j) 2)))) + (* (if (<= middle most-positive-fixnum) + (bisect j middle) + (bisect-big j middle)) + (bisect-big (+ middle 1) k))))) + (multiply-range (j k) + (declare (type (integer 1 #.most-positive-fixnum) j k)) + (do ((f k (* f m)) + (m (1- k) (1- m))) + ((< m j) f) + (declare (type (integer 0 (#.most-positive-fixnum)) m) + (type unsigned-byte f))))) + (if (and (typep i 'fixnum) (typep j 'fixnum)) + (bisect i j) + (bisect-big i j)))) + +(declaim (inline factorial)) +(defun %factorial (n) + (if (< n 2) + 1 + (%multiply-range 1 n))) + +(defun factorial (n) + "Factorial of non-negative integer N." + (check-type n (integer 0)) + (%factorial n)) + +;;;; Combinatorics + +(defun binomial-coefficient (n k) + "Binomial coefficient of N and K, also expressed as N choose K. This is the +number of K element combinations given N choises. N must be equal to or +greater then K." + (check-type n (integer 0)) + (check-type k (integer 0)) + (assert (>= n k)) + (if (or (zerop k) (= n k)) + 1 + (let ((n-k (- n k))) + ;; Swaps K and N-K if K < N-K because the algorithm + ;; below is faster for bigger K and smaller N-K + (when (< k n-k) + (rotatef k n-k)) + (if (= 1 n-k) + n + ;; General case, avoid computing the 1x...xK twice: + ;; + ;; N! 1x...xN (K+1)x...xN + ;; -------- = ---------------- = ------------, N>1 + ;; K!(N-K)! 1x...xK x (N-K)! (N-K)! + (/ (%multiply-range (+ k 1) n) + (%factorial n-k)))))) + +(defun subfactorial (n) + "Subfactorial of the non-negative integer N." + (check-type n (integer 0)) + (if (zerop n) + 1 + (do ((x 1 (1+ x)) + (a 0 (* x (+ a b))) + (b 1 a)) + ((= n x) a)))) + +(defun count-permutations (n &optional (k n)) + "Number of K element permutations for a sequence of N objects. +K defaults to N" + (check-type n (integer 0)) + (check-type k (integer 0)) + (assert (>= n k)) + (%multiply-range (1+ (- n k)) n)) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/package.lisp b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/package.lisp new file mode 100644 index 0000000..f9d2014 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/package.lisp @@ -0,0 +1,243 @@ +(defpackage :alexandria.1.0.0 + (:nicknames :alexandria) + (:use :cl) + #+sb-package-locks + (:lock t) + (:export + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;; BLESSED + ;; + ;; Binding constructs + #:if-let + #:when-let + #:when-let* + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;; REVIEW IN PROGRESS + ;; + ;; Control flow + ;; + ;; -- no clear consensus yet -- + #:cswitch + #:eswitch + #:switch + ;; -- problem free? -- + #:multiple-value-prog2 + #:nth-value-or + #:whichever + #:xor + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;; REVIEW PENDING + ;; + ;; Definitions + #:define-constant + ;; Hash tables + #:alist-hash-table + #:copy-hash-table + #:ensure-gethash + #:hash-table-alist + #:hash-table-keys + #:hash-table-plist + #:hash-table-values + #:maphash-keys + #:maphash-values + #:plist-hash-table + ;; Functions + #:compose + #:conjoin + #:curry + #:disjoin + #:ensure-function + #:ensure-functionf + #:multiple-value-compose + #:named-lambda + #:rcurry + ;; Lists + #:alist-plist + #:appendf + #:nconcf + #:reversef + #:nreversef + #:circular-list + #:circular-list-p + #:circular-tree-p + #:doplist + #:ensure-car + #:ensure-cons + #:ensure-list + #:flatten + #:lastcar + #:make-circular-list + #:map-product + #:mappend + #:nunionf + #:plist-alist + #:proper-list + #:proper-list-length + #:proper-list-p + #:remove-from-plist + #:remove-from-plistf + #:delete-from-plist + #:delete-from-plistf + #:set-equal + #:setp + #:unionf + ;; Numbers + #:binomial-coefficient + #:clamp + #:count-permutations + #:factorial + #:gaussian-random + #:iota + #:lerp + #:map-iota + #:maxf + #:mean + #:median + #:minf + #:standard-deviation + #:subfactorial + #:variance + ;; Arrays + #:array-index + #:array-length + #:copy-array + ;; Sequences + #:copy-sequence + #:deletef + #:emptyp + #:ends-with + #:ends-with-subseq + #:extremum + #:first-elt + #:last-elt + #:length= + #:map-combinations + #:map-derangements + #:map-permutations + #:proper-sequence + #:random-elt + #:removef + #:rotate + #:sequence-of-length-p + #:shuffle + #:starts-with + #:starts-with-subseq + ;; Macros + #:once-only + #:parse-body + #:parse-ordinary-lambda-list + #:with-gensyms + #:with-unique-names + ;; Symbols + #:ensure-symbol + #:format-symbol + #:make-gensym + #:make-gensym-list + #:make-keyword + ;; Strings + #:string-designator + ;; Types + #:negative-double-float + #:negative-fixnum-p + #:negative-float + #:negative-float-p + #:negative-long-float + #:negative-long-float-p + #:negative-rational + #:negative-rational-p + #:negative-real + #:negative-single-float-p + #:non-negative-double-float + #:non-negative-double-float-p + #:non-negative-fixnum + #:non-negative-fixnum-p + #:non-negative-float + #:non-negative-float-p + #:non-negative-integer-p + #:non-negative-long-float + #:non-negative-rational + #:non-negative-real-p + #:non-negative-short-float-p + #:non-negative-single-float + #:non-negative-single-float-p + #:non-positive-double-float + #:non-positive-double-float-p + #:non-positive-fixnum + #:non-positive-fixnum-p + #:non-positive-float + #:non-positive-float-p + #:non-positive-integer + #:non-positive-rational + #:non-positive-real + #:non-positive-real-p + #:non-positive-short-float + #:non-positive-short-float-p + #:non-positive-single-float-p + #:positive-double-float + #:positive-double-float-p + #:positive-fixnum + #:positive-fixnum-p + #:positive-float + #:positive-float-p + #:positive-integer + #:positive-rational + #:positive-real + #:positive-real-p + #:positive-short-float + #:positive-short-float-p + #:positive-single-float + #:positive-single-float-p + #:coercef + #:negative-double-float-p + #:negative-fixnum + #:negative-integer + #:negative-integer-p + #:negative-real-p + #:negative-short-float + #:negative-short-float-p + #:negative-single-float + #:non-negative-integer + #:non-negative-long-float-p + #:non-negative-rational-p + #:non-negative-real + #:non-negative-short-float + #:non-positive-integer-p + #:non-positive-long-float + #:non-positive-long-float-p + #:non-positive-rational-p + #:non-positive-single-float + #:of-type + #:positive-integer-p + #:positive-long-float + #:positive-long-float-p + #:positive-rational-p + #:type= + ;; Conditions + #:required-argument + #:ignore-some-conditions + #:simple-style-warning + #:simple-reader-error + #:simple-parse-error + #:simple-program-error + #:unwind-protect-case + ;; Features + #:featurep + ;; io + #:with-input-from-file + #:with-output-to-file + #:read-stream-content-into-string + #:read-file-into-string + #:write-string-into-file + #:read-stream-content-into-byte-vector + #:read-file-into-byte-vector + #:write-byte-vector-into-file + #:copy-stream + #:copy-file + ;; new additions collected at the end (subject to removal or further changes) + #:symbolicate + #:assoc-value + #:rassoc-value + #:destructuring-case + #:destructuring-ccase + #:destructuring-ecase + )) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/sequences.lisp b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/sequences.lisp new file mode 100644 index 0000000..21464f5 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/sequences.lisp @@ -0,0 +1,555 @@ +(in-package :alexandria) + +;; Make these inlinable by declaiming them INLINE here and some of them +;; NOTINLINE at the end of the file. Exclude functions that have a compiler +;; macro, because NOTINLINE is required to prevent compiler-macro expansion. +(declaim (inline copy-sequence sequence-of-length-p)) + +(defun sequence-of-length-p (sequence length) + "Return true if SEQUENCE is a sequence of length LENGTH. Signals an error if +SEQUENCE is not a sequence. Returns FALSE for circular lists." + (declare (type array-index length) + #-lispworks (inline length) + (optimize speed)) + (etypecase sequence + (null + (zerop length)) + (cons + (let ((n (1- length))) + (unless (minusp n) + (let ((tail (nthcdr n sequence))) + (and tail + (null (cdr tail))))))) + (vector + (= length (length sequence))) + (sequence + (= length (length sequence))))) + +(defun rotate-tail-to-head (sequence n) + (declare (type (integer 1) n)) + (if (listp sequence) + (let ((m (mod n (proper-list-length sequence)))) + (if (null (cdr sequence)) + sequence + (let* ((tail (last sequence (+ m 1))) + (last (cdr tail))) + (setf (cdr tail) nil) + (nconc last sequence)))) + (let* ((len (length sequence)) + (m (mod n len)) + (tail (subseq sequence (- len m)))) + (replace sequence sequence :start1 m :start2 0) + (replace sequence tail) + sequence))) + +(defun rotate-head-to-tail (sequence n) + (declare (type (integer 1) n)) + (if (listp sequence) + (let ((m (mod (1- n) (proper-list-length sequence)))) + (if (null (cdr sequence)) + sequence + (let* ((headtail (nthcdr m sequence)) + (tail (cdr headtail))) + (setf (cdr headtail) nil) + (nconc tail sequence)))) + (let* ((len (length sequence)) + (m (mod n len)) + (head (subseq sequence 0 m))) + (replace sequence sequence :start1 0 :start2 m) + (replace sequence head :start1 (- len m)) + sequence))) + +(defun rotate (sequence &optional (n 1)) + "Returns a sequence of the same type as SEQUENCE, with the elements of +SEQUENCE rotated by N: N elements are moved from the end of the sequence to +the front if N is positive, and -N elements moved from the front to the end if +N is negative. SEQUENCE must be a proper sequence. N must be an integer, +defaulting to 1. + +If absolute value of N is greater then the length of the sequence, the results +are identical to calling ROTATE with + + (* (signum n) (mod n (length sequence))). + +Note: the original sequence may be destructively altered, and result sequence may +share structure with it." + (if (plusp n) + (rotate-tail-to-head sequence n) + (if (minusp n) + (rotate-head-to-tail sequence (- n)) + sequence))) + +(defun shuffle (sequence &key (start 0) end) + "Returns a random permutation of SEQUENCE bounded by START and END. +Original sequence may be destructively modified, and (if it contains +CONS or lists themselv) share storage with the original one. +Signals an error if SEQUENCE is not a proper sequence." + (declare (type fixnum start) + (type (or fixnum null) end)) + (etypecase sequence + (list + (let* ((end (or end (proper-list-length sequence))) + (n (- end start))) + (do ((tail (nthcdr start sequence) (cdr tail))) + ((zerop n)) + (rotatef (car tail) (car (nthcdr (random n) tail))) + (decf n)))) + (vector + (let ((end (or end (length sequence)))) + (loop for i from start below end + do (rotatef (aref sequence i) + (aref sequence (+ i (random (- end i)))))))) + (sequence + (let ((end (or end (length sequence)))) + (loop for i from (- end 1) downto start + do (rotatef (elt sequence i) + (elt sequence (+ i (random (- end i))))))))) + sequence) + +(defun random-elt (sequence &key (start 0) end) + "Returns a random element from SEQUENCE bounded by START and END. Signals an +error if the SEQUENCE is not a proper non-empty sequence, or if END and START +are not proper bounding index designators for SEQUENCE." + (declare (sequence sequence) (fixnum start) (type (or fixnum null) end)) + (let* ((size (if (listp sequence) + (proper-list-length sequence) + (length sequence))) + (end2 (or end size))) + (cond ((zerop size) + (error 'type-error + :datum sequence + :expected-type `(and sequence (not (satisfies emptyp))))) + ((not (and (<= 0 start) (< start end2) (<= end2 size))) + (error 'simple-type-error + :datum (cons start end) + :expected-type `(cons (integer 0 (,end2)) + (or null (integer (,start) ,size))) + :format-control "~@<~S and ~S are not valid bounding index designators for ~ + a sequence of length ~S.~:@>" + :format-arguments (list start end size))) + (t + (let ((index (+ start (random (- end2 start))))) + (elt sequence index)))))) + +(declaim (inline remove/swapped-arguments)) +(defun remove/swapped-arguments (sequence item &rest keyword-arguments) + (apply #'remove item sequence keyword-arguments)) + +(define-modify-macro removef (item &rest keyword-arguments) + remove/swapped-arguments + "Modify-macro for REMOVE. Sets place designated by the first argument to +the result of calling REMOVE with ITEM, place, and the KEYWORD-ARGUMENTS.") + +(declaim (inline delete/swapped-arguments)) +(defun delete/swapped-arguments (sequence item &rest keyword-arguments) + (apply #'delete item sequence keyword-arguments)) + +(define-modify-macro deletef (item &rest keyword-arguments) + delete/swapped-arguments + "Modify-macro for DELETE. Sets place designated by the first argument to +the result of calling DELETE with ITEM, place, and the KEYWORD-ARGUMENTS.") + +(deftype proper-sequence () + "Type designator for proper sequences, that is proper lists and sequences +that are not lists." + `(or proper-list + (and (not list) sequence))) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (when (and (find-package '#:sequence) + (find-symbol (string '#:emptyp) '#:sequence)) + (pushnew 'sequence-emptyp *features*))) + +#-alexandria::sequence-emptyp +(defun emptyp (sequence) + "Returns true if SEQUENCE is an empty sequence. Signals an error if SEQUENCE +is not a sequence." + (etypecase sequence + (list (null sequence)) + (sequence (zerop (length sequence))))) + +#+alexandria::sequence-emptyp +(declaim (ftype (function (sequence) (values boolean &optional)) emptyp)) +#+alexandria::sequence-emptyp +(setf (symbol-function 'emptyp) (symbol-function 'sequence:emptyp)) +#+alexandria::sequence-emptyp +(define-compiler-macro emptyp (sequence) + `(sequence:emptyp ,sequence)) + +(defun length= (&rest sequences) + "Takes any number of sequences or integers in any order. Returns true iff +the length of all the sequences and the integers are equal. Hint: there's a +compiler macro that expands into more efficient code if the first argument +is a literal integer." + (declare (dynamic-extent sequences) + (inline sequence-of-length-p) + (optimize speed)) + (unless (cdr sequences) + (error "You must call LENGTH= with at least two arguments")) + ;; There's room for optimization here: multiple list arguments could be + ;; traversed in parallel. + (let* ((first (pop sequences)) + (current (if (integerp first) + first + (length first)))) + (declare (type array-index current)) + (dolist (el sequences) + (if (integerp el) + (unless (= el current) + (return-from length= nil)) + (unless (sequence-of-length-p el current) + (return-from length= nil))))) + t) + +(define-compiler-macro length= (&whole form length &rest sequences) + (cond + ((zerop (length sequences)) + form) + (t + (let ((optimizedp (integerp length))) + (with-unique-names (tmp current) + (declare (ignorable current)) + `(locally + (declare (inline sequence-of-length-p)) + (let ((,tmp) + ,@(unless optimizedp + `((,current ,length)))) + ,@(unless optimizedp + `((unless (integerp ,current) + (setf ,current (length ,current))))) + (and + ,@(loop + :for sequence :in sequences + :collect `(progn + (setf ,tmp ,sequence) + (if (integerp ,tmp) + (= ,tmp ,(if optimizedp + length + current)) + (sequence-of-length-p ,tmp ,(if optimizedp + length + current))))))))))))) + +(defun copy-sequence (type sequence) + "Returns a fresh sequence of TYPE, which has the same elements as +SEQUENCE." + (if (typep sequence type) + (copy-seq sequence) + (coerce sequence type))) + +(defun first-elt (sequence) + "Returns the first element of SEQUENCE. Signals a type-error if SEQUENCE is +not a sequence, or is an empty sequence." + ;; Can't just directly use ELT, as it is not guaranteed to signal the + ;; type-error. + (cond ((consp sequence) + (car sequence)) + ((and (typep sequence 'sequence) (not (emptyp sequence))) + (elt sequence 0)) + (t + (error 'type-error + :datum sequence + :expected-type '(and sequence (not (satisfies emptyp))))))) + +(defun (setf first-elt) (object sequence) + "Sets the first element of SEQUENCE. Signals a type-error if SEQUENCE is +not a sequence, is an empty sequence, or if OBJECT cannot be stored in SEQUENCE." + ;; Can't just directly use ELT, as it is not guaranteed to signal the + ;; type-error. + (cond ((consp sequence) + (setf (car sequence) object)) + ((and (typep sequence 'sequence) (not (emptyp sequence))) + (setf (elt sequence 0) object)) + (t + (error 'type-error + :datum sequence + :expected-type '(and sequence (not (satisfies emptyp))))))) + +(defun last-elt (sequence) + "Returns the last element of SEQUENCE. Signals a type-error if SEQUENCE is +not a proper sequence, or is an empty sequence." + ;; Can't just directly use ELT, as it is not guaranteed to signal the + ;; type-error. + (let ((len 0)) + (cond ((consp sequence) + (lastcar sequence)) + ((and (typep sequence '(and sequence (not list))) (plusp (setf len (length sequence)))) + (elt sequence (1- len))) + (t + (error 'type-error + :datum sequence + :expected-type '(and proper-sequence (not (satisfies emptyp)))))))) + +(defun (setf last-elt) (object sequence) + "Sets the last element of SEQUENCE. Signals a type-error if SEQUENCE is not a proper +sequence, is an empty sequence, or if OBJECT cannot be stored in SEQUENCE." + (let ((len 0)) + (cond ((consp sequence) + (setf (lastcar sequence) object)) + ((and (typep sequence '(and sequence (not list))) (plusp (setf len (length sequence)))) + (setf (elt sequence (1- len)) object)) + (t + (error 'type-error + :datum sequence + :expected-type '(and proper-sequence (not (satisfies emptyp)))))))) + +(defun starts-with-subseq (prefix sequence &rest args + &key + (return-suffix nil return-suffix-supplied-p) + &allow-other-keys) + "Test whether the first elements of SEQUENCE are the same (as per TEST) as the elements of PREFIX. + +If RETURN-SUFFIX is T the function returns, as a second value, a +sub-sequence or displaced array pointing to the sequence after PREFIX." + (declare (dynamic-extent args)) + (let ((sequence-length (length sequence)) + (prefix-length (length prefix))) + (when (< sequence-length prefix-length) + (return-from starts-with-subseq (values nil nil))) + (flet ((make-suffix (start) + (when return-suffix + (cond + ((not (arrayp sequence)) + (if start + (subseq sequence start) + (subseq sequence 0 0))) + ((not start) + (make-array 0 + :element-type (array-element-type sequence) + :adjustable nil)) + (t + (make-array (- sequence-length start) + :element-type (array-element-type sequence) + :displaced-to sequence + :displaced-index-offset start + :adjustable nil)))))) + (let ((mismatch (apply #'mismatch prefix sequence + (if return-suffix-supplied-p + (remove-from-plist args :return-suffix) + args)))) + (cond + ((not mismatch) + (values t (make-suffix nil))) + ((= mismatch prefix-length) + (values t (make-suffix mismatch))) + (t + (values nil nil))))))) + +(defun ends-with-subseq (suffix sequence &key (test #'eql)) + "Test whether SEQUENCE ends with SUFFIX. In other words: return true if +the last (length SUFFIX) elements of SEQUENCE are equal to SUFFIX." + (let ((sequence-length (length sequence)) + (suffix-length (length suffix))) + (when (< sequence-length suffix-length) + ;; if SEQUENCE is shorter than SUFFIX, then SEQUENCE can't end with SUFFIX. + (return-from ends-with-subseq nil)) + (loop for sequence-index from (- sequence-length suffix-length) below sequence-length + for suffix-index from 0 below suffix-length + when (not (funcall test (elt sequence sequence-index) (elt suffix suffix-index))) + do (return-from ends-with-subseq nil) + finally (return t)))) + +(defun starts-with (object sequence &key (test #'eql) (key #'identity)) + "Returns true if SEQUENCE is a sequence whose first element is EQL to OBJECT. +Returns NIL if the SEQUENCE is not a sequence or is an empty sequence." + (let ((first-elt (typecase sequence + (cons (car sequence)) + (sequence + (if (emptyp sequence) + (return-from starts-with nil) + (elt sequence 0))) + (t + (return-from starts-with nil))))) + (funcall test (funcall key first-elt) object))) + +(defun ends-with (object sequence &key (test #'eql) (key #'identity)) + "Returns true if SEQUENCE is a sequence whose last element is EQL to OBJECT. +Returns NIL if the SEQUENCE is not a sequence or is an empty sequence. Signals +an error if SEQUENCE is an improper list." + (let ((last-elt (typecase sequence + (cons + (lastcar sequence)) ; signals for improper lists + (sequence + ;; Can't use last-elt, as that signals an error + ;; for empty sequences + (let ((len (length sequence))) + (if (plusp len) + (elt sequence (1- len)) + (return-from ends-with nil)))) + (t + (return-from ends-with nil))))) + (funcall test (funcall key last-elt) object))) + +(defun map-combinations (function sequence &key (start 0) end length (copy t)) + "Calls FUNCTION with each combination of LENGTH constructable from the +elements of the subsequence of SEQUENCE delimited by START and END. START +defaults to 0, END to length of SEQUENCE, and LENGTH to the length of the +delimited subsequence. (So unless LENGTH is specified there is only a single +combination, which has the same elements as the delimited subsequence.) If +COPY is true (the default) each combination is freshly allocated. If COPY is +false all combinations are EQ to each other, in which case consequences are +unspecified if a combination is modified by FUNCTION." + (let* ((end (or end (length sequence))) + (size (- end start)) + (length (or length size)) + (combination (subseq sequence 0 length)) + (function (ensure-function function))) + (if (= length size) + (funcall function combination) + (flet ((call () + (funcall function (if copy + (copy-seq combination) + combination)))) + (etypecase sequence + ;; When dealing with lists we prefer walking back and + ;; forth instead of using indexes. + (list + (labels ((combine-list (c-tail o-tail) + (if (not c-tail) + (call) + (do ((tail o-tail (cdr tail))) + ((not tail)) + (setf (car c-tail) (car tail)) + (combine-list (cdr c-tail) (cdr tail)))))) + (combine-list combination (nthcdr start sequence)))) + (vector + (labels ((combine (count start) + (if (zerop count) + (call) + (loop for i from start below end + do (let ((j (- count 1))) + (setf (aref combination j) (aref sequence i)) + (combine j (+ i 1))))))) + (combine length start))) + (sequence + (labels ((combine (count start) + (if (zerop count) + (call) + (loop for i from start below end + do (let ((j (- count 1))) + (setf (elt combination j) (elt sequence i)) + (combine j (+ i 1))))))) + (combine length start))))))) + sequence) + +(defun map-permutations (function sequence &key (start 0) end length (copy t)) + "Calls function with each permutation of LENGTH constructable +from the subsequence of SEQUENCE delimited by START and END. START +defaults to 0, END to length of the sequence, and LENGTH to the +length of the delimited subsequence." + (let* ((end (or end (length sequence))) + (size (- end start)) + (length (or length size))) + (labels ((permute (seq n) + (let ((n-1 (- n 1))) + (if (zerop n-1) + (funcall function (if copy + (copy-seq seq) + seq)) + (loop for i from 0 upto n-1 + do (permute seq n-1) + (if (evenp n-1) + (rotatef (elt seq 0) (elt seq n-1)) + (rotatef (elt seq i) (elt seq n-1))))))) + (permute-sequence (seq) + (permute seq length))) + (if (= length size) + ;; Things are simple if we need to just permute the + ;; full START-END range. + (permute-sequence (subseq sequence start end)) + ;; Otherwise we need to generate all the combinations + ;; of LENGTH in the START-END range, and then permute + ;; a copy of the result: can't permute the combination + ;; directly, as they share structure with each other. + (let ((permutation (subseq sequence 0 length))) + (flet ((permute-combination (combination) + (permute-sequence (replace permutation combination)))) + (declare (dynamic-extent #'permute-combination)) + (map-combinations #'permute-combination sequence + :start start + :end end + :length length + :copy nil))))))) + +(defun map-derangements (function sequence &key (start 0) end (copy t)) + "Calls FUNCTION with each derangement of the subsequence of SEQUENCE denoted +by the bounding index designators START and END. Derangement is a permutation +of the sequence where no element remains in place. SEQUENCE is not modified, +but individual derangements are EQ to each other. Consequences are unspecified +if calling FUNCTION modifies either the derangement or SEQUENCE." + (let* ((end (or end (length sequence))) + (size (- end start)) + ;; We don't really care about the elements here. + (derangement (subseq sequence 0 size)) + ;; Bitvector that has 1 for elements that have been deranged. + (mask (make-array size :element-type 'bit :initial-element 0))) + (declare (dynamic-extent mask)) + ;; ad hoc algorith + (labels ((derange (place n) + ;; Perform one recursive step in deranging the + ;; sequence: PLACE is index of the original sequence + ;; to derange to another index, and N is the number of + ;; indexes not yet deranged. + (if (zerop n) + (funcall function (if copy + (copy-seq derangement) + derangement)) + ;; Itarate over the indexes I of the subsequence to + ;; derange: if I != PLACE and I has not yet been + ;; deranged by an earlier call put the element from + ;; PLACE to I, mark I as deranged, and recurse, + ;; finally removing the mark. + (loop for i from 0 below size + do + (unless (or (= place (+ i start)) (not (zerop (bit mask i)))) + (setf (elt derangement i) (elt sequence place) + (bit mask i) 1) + (derange (1+ place) (1- n)) + (setf (bit mask i) 0)))))) + (derange start size) + sequence))) + +(declaim (notinline sequence-of-length-p)) + +(defun extremum (sequence predicate &key key (start 0) end) + "Returns the element of SEQUENCE that would appear first if the subsequence +bounded by START and END was sorted using PREDICATE and KEY. + +EXTREMUM determines the relationship between two elements of SEQUENCE by using +the PREDICATE function. PREDICATE should return true if and only if the first +argument is strictly less than the second one (in some appropriate sense). Two +arguments X and Y are considered to be equal if (FUNCALL PREDICATE X Y) +and (FUNCALL PREDICATE Y X) are both false. + +The arguments to the PREDICATE function are computed from elements of SEQUENCE +using the KEY function, if supplied. If KEY is not supplied or is NIL, the +sequence element itself is used. + +If SEQUENCE is empty, NIL is returned." + (let* ((pred-fun (ensure-function predicate)) + (key-fun (unless (or (not key) (eq key 'identity) (eq key #'identity)) + (ensure-function key))) + (real-end (or end (length sequence)))) + (cond ((> real-end start) + (if key-fun + (flet ((reduce-keys (a b) + (if (funcall pred-fun + (funcall key-fun a) + (funcall key-fun b)) + a + b))) + (declare (dynamic-extent #'reduce-keys)) + (reduce #'reduce-keys sequence :start start :end real-end)) + (flet ((reduce-elts (a b) + (if (funcall pred-fun a b) + a + b))) + (declare (dynamic-extent #'reduce-elts)) + (reduce #'reduce-elts sequence :start start :end real-end)))) + ((= real-end start) + nil) + (t + (error "Invalid bounding indexes for sequence of length ~S: ~S ~S, ~S ~S" + (length sequence) + :start start + :end end))))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/strings.lisp b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/strings.lisp new file mode 100644 index 0000000..e9fd91c --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/strings.lisp @@ -0,0 +1,6 @@ +(in-package :alexandria) + +(deftype string-designator () + "A string designator type. A string designator is either a string, a symbol, +or a character." + `(or symbol string character)) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/symbols.lisp b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/symbols.lisp new file mode 100644 index 0000000..5733d3e --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/symbols.lisp @@ -0,0 +1,65 @@ +(in-package :alexandria) + +(declaim (inline ensure-symbol)) +(defun ensure-symbol (name &optional (package *package*)) + "Returns a symbol with name designated by NAME, accessible in package +designated by PACKAGE. If symbol is not already accessible in PACKAGE, it is +interned there. Returns a secondary value reflecting the status of the symbol +in the package, which matches the secondary return value of INTERN. + +Example: + + (ensure-symbol :cons :cl) => cl:cons, :external +" + (intern (string name) package)) + +(defun maybe-intern (name package) + (values + (if package + (intern name (if (eq t package) *package* package)) + (make-symbol name)))) + +(declaim (inline format-symbol)) +(defun format-symbol (package control &rest arguments) + "Constructs a string by applying ARGUMENTS to string designator CONTROL as +if by FORMAT within WITH-STANDARD-IO-SYNTAX, and then creates a symbol named +by that string. + +If PACKAGE is NIL, returns an uninterned symbol, if package is T, returns a +symbol interned in the current package, and otherwise returns a symbol +interned in the package designated by PACKAGE." + (maybe-intern (with-standard-io-syntax + (apply #'format nil (string control) arguments)) + package)) + +(defun make-keyword (name) + "Interns the string designated by NAME in the KEYWORD package." + (intern (string name) :keyword)) + +(defun make-gensym (name) + "If NAME is a non-negative integer, calls GENSYM using it. Otherwise NAME +must be a string designator, in which case calls GENSYM using the designated +string as the argument." + (gensym (if (typep name '(integer 0)) + name + (string name)))) + +(defun make-gensym-list (length &optional (x "G")) + "Returns a list of LENGTH gensyms, each generated as if with a call to MAKE-GENSYM, +using the second (optional, defaulting to \"G\") argument." + (let ((g (if (typep x '(integer 0)) x (string x)))) + (loop repeat length + collect (gensym g)))) + +(defun symbolicate (&rest things) + "Concatenate together the names of some strings and symbols, +producing a symbol in the current package." + (let* ((length (reduce #'+ things + :key (lambda (x) (length (string x))))) + (name (make-array length :element-type 'character))) + (let ((index 0)) + (dolist (thing things (values (intern name))) + (let* ((x (string thing)) + (len (length x))) + (replace name x :start1 index) + (incf index len)))))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/tests.lisp b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/tests.lisp new file mode 100644 index 0000000..b70ef04 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/tests.lisp @@ -0,0 +1,2047 @@ +(in-package :cl-user) + +(defpackage :alexandria-tests + (:use :cl :alexandria #+sbcl :sb-rt #-sbcl :rtest) + (:import-from #+sbcl :sb-rt #-sbcl :rtest + #:*compile-tests* #:*expected-failures*)) + +(in-package :alexandria-tests) + +(defun run-tests (&key ((:compiled *compile-tests*))) + (do-tests)) + +(defun hash-table-test-name (name) + ;; Workaround for Clisp calling EQL in a hash-table FASTHASH-EQL. + (hash-table-test (make-hash-table :test name))) + +;;;; Arrays + +(deftest copy-array.1 + (let* ((orig (vector 1 2 3)) + (copy (copy-array orig))) + (values (eq orig copy) (equalp orig copy))) + nil t) + +(deftest copy-array.2 + (let ((orig (make-array 1024 :fill-pointer 0))) + (vector-push-extend 1 orig) + (vector-push-extend 2 orig) + (vector-push-extend 3 orig) + (let ((copy (copy-array orig))) + (values (eq orig copy) (equalp orig copy) + (array-has-fill-pointer-p copy) + (eql (fill-pointer orig) (fill-pointer copy))))) + nil t t t) + +(deftest copy-array.3 + (let* ((orig (vector 1 2 3)) + (copy (copy-array orig))) + (typep copy 'simple-array)) + t) + +(deftest copy-array.4 + (let ((orig (make-array 21 + :adjustable t + :fill-pointer 0))) + (dotimes (n 42) + (vector-push-extend n orig)) + (let ((copy (copy-array orig + :adjustable nil + :fill-pointer nil))) + (typep copy 'simple-array))) + t) + +(deftest array-index.1 + (typep 0 'array-index) + t) + +;;;; Conditions + +(deftest unwind-protect-case.1 + (let (result) + (unwind-protect-case () + (random 10) + (:normal (push :normal result)) + (:abort (push :abort result)) + (:always (push :always result))) + result) + (:always :normal)) + +(deftest unwind-protect-case.2 + (let (result) + (unwind-protect-case () + (random 10) + (:always (push :always result)) + (:normal (push :normal result)) + (:abort (push :abort result))) + result) + (:normal :always)) + +(deftest unwind-protect-case.3 + (let (result1 result2 result3) + (ignore-errors + (unwind-protect-case () + (error "FOOF!") + (:normal (push :normal result1)) + (:abort (push :abort result1)) + (:always (push :always result1)))) + (catch 'foof + (unwind-protect-case () + (throw 'foof 42) + (:normal (push :normal result2)) + (:abort (push :abort result2)) + (:always (push :always result2)))) + (block foof + (unwind-protect-case () + (return-from foof 42) + (:normal (push :normal result3)) + (:abort (push :abort result3)) + (:always (push :always result3)))) + (values result1 result2 result3)) + (:always :abort) + (:always :abort) + (:always :abort)) + +(deftest unwind-protect-case.4 + (let (result) + (unwind-protect-case (aborted-p) + (random 42) + (:always (setq result aborted-p))) + result) + nil) + +(deftest unwind-protect-case.5 + (let (result) + (block foof + (unwind-protect-case (aborted-p) + (return-from foof) + (:always (setq result aborted-p)))) + result) + t) + +;;;; Control flow + +(deftest switch.1 + (switch (13 :test =) + (12 :oops) + (13.0 :yay)) + :yay) + +(deftest switch.2 + (switch (13) + ((+ 12 2) :oops) + ((- 13 1) :oops2) + (t :yay)) + :yay) + +(deftest eswitch.1 + (let ((x 13)) + (eswitch (x :test =) + (12 :oops) + (13.0 :yay))) + :yay) + +(deftest eswitch.2 + (let ((x 13)) + (eswitch (x :key 1+) + (11 :oops) + (14 :yay))) + :yay) + +(deftest cswitch.1 + (cswitch (13 :test =) + (12 :oops) + (13.0 :yay)) + :yay) + +(deftest cswitch.2 + (cswitch (13 :key 1-) + (12 :yay) + (13.0 :oops)) + :yay) + +(deftest multiple-value-prog2.1 + (multiple-value-prog2 + (values 1 1 1) + (values 2 20 200) + (values 3 3 3)) + 2 20 200) + +(deftest nth-value-or.1 + (multiple-value-bind (a b c) + (nth-value-or 1 + (values 1 nil 1) + (values 2 2 2)) + (= a b c 2)) + t) + +(deftest whichever.1 + (let ((x (whichever 1 2 3))) + (and (member x '(1 2 3)) t)) + t) + +(deftest whichever.2 + (let* ((a 1) + (b 2) + (c 3) + (x (whichever a b c))) + (and (member x '(1 2 3)) t)) + t) + +(deftest xor.1 + (xor nil nil 1 nil) + 1 + t) + +(deftest xor.2 + (xor nil nil 1 2) + nil + nil) + +(deftest xor.3 + (xor nil nil nil) + nil + t) + +;;;; Definitions + +(deftest define-constant.1 + (let ((name (gensym))) + (eval `(define-constant ,name "FOO" :test 'equal)) + (eval `(define-constant ,name "FOO" :test 'equal)) + (values (equal "FOO" (symbol-value name)) + (constantp name))) + t + t) + +(deftest define-constant.2 + (let ((name (gensym))) + (eval `(define-constant ,name 13)) + (eval `(define-constant ,name 13)) + (values (eql 13 (symbol-value name)) + (constantp name))) + t + t) + +;;;; Errors + +;;; TYPEP is specified to return a generalized boolean and, for +;;; example, ECL exploits this by returning the superclasses of ERROR +;;; in this case. +(defun errorp (x) + (not (null (typep x 'error)))) + +(deftest required-argument.1 + (multiple-value-bind (res err) + (ignore-errors (required-argument)) + (errorp err)) + t) + +;;;; Hash tables + +(deftest ensure-gethash.1 + (let ((table (make-hash-table)) + (x (list 1))) + (multiple-value-bind (value already-there) + (ensure-gethash x table 42) + (and (= value 42) + (not already-there) + (= 42 (gethash x table)) + (multiple-value-bind (value2 already-there2) + (ensure-gethash x table 13) + (and (= value2 42) + already-there2 + (= 42 (gethash x table))))))) + t) + +(deftest ensure-gethash.2 + (let ((table (make-hash-table)) + (count 0)) + (multiple-value-call #'values + (ensure-gethash (progn (incf count) :foo) + (progn (incf count) table) + (progn (incf count) :bar)) + (gethash :foo table) + count)) + :bar nil :bar t 3) + +(deftest copy-hash-table.1 + (let ((orig (make-hash-table :test 'eq :size 123)) + (foo "foo")) + (setf (gethash orig orig) t + (gethash foo orig) t) + (let ((eq-copy (copy-hash-table orig)) + (eql-copy (copy-hash-table orig :test 'eql)) + (equal-copy (copy-hash-table orig :test 'equal)) + (equalp-copy (copy-hash-table orig :test 'equalp))) + (list (eql (hash-table-size eq-copy) (hash-table-size orig)) + (eql (hash-table-rehash-size eq-copy) + (hash-table-rehash-size orig)) + (hash-table-count eql-copy) + (gethash orig eq-copy) + (gethash (copy-seq foo) eql-copy) + (gethash foo eql-copy) + (gethash (copy-seq foo) equal-copy) + (gethash "FOO" equal-copy) + (gethash "FOO" equalp-copy)))) + (t t 2 t nil t t nil t)) + +(deftest copy-hash-table.2 + (let ((ht (make-hash-table)) + (list (list :list (vector :A :B :C)))) + (setf (gethash 'list ht) list) + (let* ((shallow-copy (copy-hash-table ht)) + (deep1-copy (copy-hash-table ht :key 'copy-list)) + (list (gethash 'list ht)) + (shallow-list (gethash 'list shallow-copy)) + (deep1-list (gethash 'list deep1-copy))) + (list (eq ht shallow-copy) + (eq ht deep1-copy) + (eq list shallow-list) + (eq list deep1-list) ; outer list was copied. + (eq (second list) (second shallow-list)) + (eq (second list) (second deep1-list)) ; inner vector wasn't copied. + ))) + (nil nil t nil t t)) + +(deftest maphash-keys.1 + (let ((keys nil) + (table (make-hash-table))) + (declare (notinline maphash-keys)) + (dotimes (i 10) + (setf (gethash i table) t)) + (maphash-keys (lambda (k) (push k keys)) table) + (set-equal keys '(0 1 2 3 4 5 6 7 8 9))) + t) + +(deftest maphash-values.1 + (let ((vals nil) + (table (make-hash-table))) + (declare (notinline maphash-values)) + (dotimes (i 10) + (setf (gethash i table) (- i))) + (maphash-values (lambda (v) (push v vals)) table) + (set-equal vals '(0 -1 -2 -3 -4 -5 -6 -7 -8 -9))) + t) + +(deftest hash-table-keys.1 + (let ((table (make-hash-table))) + (dotimes (i 10) + (setf (gethash i table) t)) + (set-equal (hash-table-keys table) '(0 1 2 3 4 5 6 7 8 9))) + t) + +(deftest hash-table-values.1 + (let ((table (make-hash-table))) + (dotimes (i 10) + (setf (gethash (gensym) table) i)) + (set-equal (hash-table-values table) '(0 1 2 3 4 5 6 7 8 9))) + t) + +(deftest hash-table-alist.1 + (let ((table (make-hash-table))) + (dotimes (i 10) + (setf (gethash i table) (- i))) + (let ((alist (hash-table-alist table))) + (list (length alist) + (assoc 0 alist) + (assoc 3 alist) + (assoc 9 alist) + (assoc nil alist)))) + (10 (0 . 0) (3 . -3) (9 . -9) nil)) + +(deftest hash-table-plist.1 + (let ((table (make-hash-table))) + (dotimes (i 10) + (setf (gethash i table) (- i))) + (let ((plist (hash-table-plist table))) + (list (length plist) + (getf plist 0) + (getf plist 2) + (getf plist 7) + (getf plist nil)))) + (20 0 -2 -7 nil)) + +(deftest alist-hash-table.1 + (let* ((alist '((0 a) (1 b) (2 c))) + (table (alist-hash-table alist))) + (list (hash-table-count table) + (gethash 0 table) + (gethash 1 table) + (gethash 2 table) + (eq (hash-table-test-name 'eql) + (hash-table-test table)))) + (3 (a) (b) (c) t)) + +(deftest alist-hash-table.duplicate-keys + (let* ((alist '((0 a) (1 b) (0 c) (1 d) (2 e))) + (table (alist-hash-table alist))) + (list (hash-table-count table) + (gethash 0 table) + (gethash 1 table) + (gethash 2 table))) + (3 (a) (b) (e))) + +(deftest plist-hash-table.1 + (let* ((plist '(:a 1 :b 2 :c 3)) + (table (plist-hash-table plist :test 'eq))) + (list (hash-table-count table) + (gethash :a table) + (gethash :b table) + (gethash :c table) + (gethash 2 table) + (gethash nil table) + (eq (hash-table-test-name 'eq) + (hash-table-test table)))) + (3 1 2 3 nil nil t)) + +(deftest plist-hash-table.duplicate-keys + (let* ((plist '(:a 1 :b 2 :a 3 :b 4 :c 5)) + (table (plist-hash-table plist))) + (list (hash-table-count table) + (gethash :a table) + (gethash :b table) + (gethash :c table))) + (3 1 2 5)) + +;;;; Functions + +(deftest disjoin.1 + (let ((disjunction (disjoin (lambda (x) + (and (consp x) :cons)) + (lambda (x) + (and (stringp x) :string))))) + (list (funcall disjunction 'zot) + (funcall disjunction '(foo bar)) + (funcall disjunction "test"))) + (nil :cons :string)) + +(deftest disjoin.2 + (let ((disjunction (disjoin #'zerop))) + (list (funcall disjunction 0) + (funcall disjunction 1))) + (t nil)) + +(deftest conjoin.1 + (let ((conjunction (conjoin #'consp + (lambda (x) + (stringp (car x))) + (lambda (x) + (char (car x) 0))))) + (list (funcall conjunction 'zot) + (funcall conjunction '(foo)) + (funcall conjunction '("foo")))) + (nil nil #\f)) + +(deftest conjoin.2 + (let ((conjunction (conjoin #'zerop))) + (list (funcall conjunction 0) + (funcall conjunction 1))) + (t nil)) + +(deftest compose.1 + (let ((composite (compose '1+ + (lambda (x) + (* x 2)) + #'read-from-string))) + (funcall composite "1")) + 3) + +(deftest compose.2 + (let ((composite + (locally (declare (notinline compose)) + (compose '1+ + (lambda (x) + (* x 2)) + #'read-from-string)))) + (funcall composite "2")) + 5) + +(deftest compose.3 + (let ((compose-form (funcall (compiler-macro-function 'compose) + '(compose '1+ + (lambda (x) + (* x 2)) + #'read-from-string) + nil))) + (let ((fun (funcall (compile nil `(lambda () ,compose-form))))) + (funcall fun "3"))) + 7) + +(deftest compose.4 + (let ((composite (compose #'zerop))) + (list (funcall composite 0) + (funcall composite 1))) + (t nil)) + +(deftest multiple-value-compose.1 + (let ((composite (multiple-value-compose + #'truncate + (lambda (x y) + (values y x)) + (lambda (x) + (with-input-from-string (s x) + (values (read s) (read s))))))) + (multiple-value-list (funcall composite "2 7"))) + (3 1)) + +(deftest multiple-value-compose.2 + (let ((composite (locally (declare (notinline multiple-value-compose)) + (multiple-value-compose + #'truncate + (lambda (x y) + (values y x)) + (lambda (x) + (with-input-from-string (s x) + (values (read s) (read s)))))))) + (multiple-value-list (funcall composite "2 11"))) + (5 1)) + +(deftest multiple-value-compose.3 + (let ((compose-form (funcall (compiler-macro-function 'multiple-value-compose) + '(multiple-value-compose + #'truncate + (lambda (x y) + (values y x)) + (lambda (x) + (with-input-from-string (s x) + (values (read s) (read s))))) + nil))) + (let ((fun (funcall (compile nil `(lambda () ,compose-form))))) + (multiple-value-list (funcall fun "2 9")))) + (4 1)) + +(deftest multiple-value-compose.4 + (let ((composite (multiple-value-compose #'truncate))) + (multiple-value-list (funcall composite 9 2))) + (4 1)) + +(deftest curry.1 + (let ((curried (curry '+ 3))) + (funcall curried 1 5)) + 9) + +(deftest curry.2 + (let ((curried (locally (declare (notinline curry)) + (curry '* 2 3)))) + (funcall curried 7)) + 42) + +(deftest curry.3 + (let ((curried-form (funcall (compiler-macro-function 'curry) + '(curry '/ 8) + nil))) + (let ((fun (funcall (compile nil `(lambda () ,curried-form))))) + (funcall fun 2))) + 4) + +(deftest curry.4 + (let* ((x 1) + (curried (curry (progn + (incf x) + (lambda (y z) (* x y z))) + 3))) + (list (funcall curried 7) + (funcall curried 7) + x)) + (42 42 2)) + +(deftest rcurry.1 + (let ((r (rcurry '/ 2))) + (funcall r 8)) + 4) + +(deftest rcurry.2 + (let* ((x 1) + (curried (rcurry (progn + (incf x) + (lambda (y z) (* x y z))) + 3))) + (list (funcall curried 7) + (funcall curried 7) + x)) + (42 42 2)) + +(deftest named-lambda.1 + (let ((fac (named-lambda fac (x) + (if (> x 1) + (* x (fac (- x 1))) + x)))) + (funcall fac 5)) + 120) + +(deftest named-lambda.2 + (let ((fac (named-lambda fac (&key x) + (if (> x 1) + (* x (fac :x (- x 1))) + x)))) + (funcall fac :x 5)) + 120) + +;;;; Lists + +(deftest alist-plist.1 + (alist-plist '((a . 1) (b . 2) (c . 3))) + (a 1 b 2 c 3)) + +(deftest plist-alist.1 + (plist-alist '(a 1 b 2 c 3)) + ((a . 1) (b . 2) (c . 3))) + +(deftest unionf.1 + (let* ((list (list 1 2 3)) + (orig list)) + (unionf list (list 1 2 4)) + (values (equal orig (list 1 2 3)) + (eql (length list) 4) + (set-difference list (list 1 2 3 4)) + (set-difference (list 1 2 3 4) list))) + t + t + nil + nil) + +(deftest nunionf.1 + (let ((list (list 1 2 3))) + (nunionf list (list 1 2 4)) + (values (eql (length list) 4) + (set-difference (list 1 2 3 4) list) + (set-difference list (list 1 2 3 4)))) + t + nil + nil) + +(deftest appendf.1 + (let* ((list (list 1 2 3)) + (orig list)) + (appendf list '(4 5 6) '(7 8)) + (list list (eq list orig))) + ((1 2 3 4 5 6 7 8) nil)) + +(deftest nconcf.1 + (let ((list1 (list 1 2 3)) + (list2 (list 4 5 6))) + (nconcf list1 list2 (list 7 8 9)) + list1) + (1 2 3 4 5 6 7 8 9)) + +(deftest circular-list.1 + (let ((circle (circular-list 1 2 3))) + (list (first circle) + (second circle) + (third circle) + (fourth circle) + (eq circle (nthcdr 3 circle)))) + (1 2 3 1 t)) + +(deftest circular-list-p.1 + (let* ((circle (circular-list 1 2 3 4)) + (tree (list circle circle)) + (dotted (cons circle t)) + (proper (list 1 2 3 circle)) + (tailcirc (list* 1 2 3 circle))) + (list (circular-list-p circle) + (circular-list-p tree) + (circular-list-p dotted) + (circular-list-p proper) + (circular-list-p tailcirc))) + (t nil nil nil t)) + +(deftest circular-list-p.2 + (circular-list-p 'foo) + nil) + +(deftest circular-tree-p.1 + (let* ((circle (circular-list 1 2 3 4)) + (tree1 (list circle circle)) + (tree2 (let* ((level2 (list 1 nil 2)) + (level1 (list level2))) + (setf (second level2) level1) + level1)) + (dotted (cons circle t)) + (proper (list 1 2 3 circle)) + (tailcirc (list* 1 2 3 circle)) + (quite-proper (list 1 2 3)) + (quite-dotted (list 1 (cons 2 3)))) + (list (circular-tree-p circle) + (circular-tree-p tree1) + (circular-tree-p tree2) + (circular-tree-p dotted) + (circular-tree-p proper) + (circular-tree-p tailcirc) + (circular-tree-p quite-proper) + (circular-tree-p quite-dotted))) + (t t t t t t nil nil)) + +(deftest circular-tree-p.2 + (alexandria:circular-tree-p '#1=(#1#)) + t) + +(deftest proper-list-p.1 + (let ((l1 (list 1)) + (l2 (list 1 2)) + (l3 (cons 1 2)) + (l4 (list (cons 1 2) 3)) + (l5 (circular-list 1 2))) + (list (proper-list-p l1) + (proper-list-p l2) + (proper-list-p l3) + (proper-list-p l4) + (proper-list-p l5))) + (t t nil t nil)) + +(deftest proper-list-p.2 + (proper-list-p '(1 2 . 3)) + nil) + +(deftest proper-list.type.1 + (let ((l1 (list 1)) + (l2 (list 1 2)) + (l3 (cons 1 2)) + (l4 (list (cons 1 2) 3)) + (l5 (circular-list 1 2))) + (list (typep l1 'proper-list) + (typep l2 'proper-list) + (typep l3 'proper-list) + (typep l4 'proper-list) + (typep l5 'proper-list))) + (t t nil t nil)) + +(deftest proper-list-length.1 + (values + (proper-list-length nil) + (proper-list-length (list 1)) + (proper-list-length (list 2 2)) + (proper-list-length (list 3 3 3)) + (proper-list-length (list 4 4 4 4)) + (proper-list-length (list 5 5 5 5 5)) + (proper-list-length (list 6 6 6 6 6 6)) + (proper-list-length (list 7 7 7 7 7 7 7)) + (proper-list-length (list 8 8 8 8 8 8 8 8)) + (proper-list-length (list 9 9 9 9 9 9 9 9 9))) + 0 1 2 3 4 5 6 7 8 9) + +(deftest proper-list-length.2 + (flet ((plength (x) + (handler-case + (proper-list-length x) + (type-error () + :ok)))) + (values + (plength (list* 1)) + (plength (list* 2 2)) + (plength (list* 3 3 3)) + (plength (list* 4 4 4 4)) + (plength (list* 5 5 5 5 5)) + (plength (list* 6 6 6 6 6 6)) + (plength (list* 7 7 7 7 7 7 7)) + (plength (list* 8 8 8 8 8 8 8 8)) + (plength (list* 9 9 9 9 9 9 9 9 9)))) + :ok :ok :ok + :ok :ok :ok + :ok :ok :ok) + +(deftest lastcar.1 + (let ((l1 (list 1)) + (l2 (list 1 2))) + (list (lastcar l1) + (lastcar l2))) + (1 2)) + +(deftest lastcar.error.2 + (handler-case + (progn + (lastcar (circular-list 1 2 3)) + nil) + (error () + t)) + t) + +(deftest setf-lastcar.1 + (let ((l (list 1 2 3 4))) + (values (lastcar l) + (progn + (setf (lastcar l) 42) + (lastcar l)))) + 4 + 42) + +(deftest setf-lastcar.2 + (let ((l (circular-list 1 2 3))) + (multiple-value-bind (res err) + (ignore-errors (setf (lastcar l) 4)) + (typep err 'type-error))) + t) + +(deftest make-circular-list.1 + (let ((l (make-circular-list 3 :initial-element :x))) + (setf (car l) :y) + (list (eq l (nthcdr 3 l)) + (first l) + (second l) + (third l) + (fourth l))) + (t :y :x :x :y)) + +(deftest circular-list.type.1 + (let* ((l1 (list 1 2 3)) + (l2 (circular-list 1 2 3)) + (l3 (list* 1 2 3 l2))) + (list (typep l1 'circular-list) + (typep l2 'circular-list) + (typep l3 'circular-list))) + (nil t t)) + +(deftest ensure-list.1 + (let ((x (list 1)) + (y 2)) + (list (ensure-list x) + (ensure-list y))) + ((1) (2))) + +(deftest ensure-cons.1 + (let ((x (cons 1 2)) + (y nil) + (z "foo")) + (values (ensure-cons x) + (ensure-cons y) + (ensure-cons z))) + (1 . 2) + (nil) + ("foo")) + +(deftest setp.1 + (setp '(1)) + t) + +(deftest setp.2 + (setp nil) + t) + +(deftest setp.3 + (setp "foo") + nil) + +(deftest setp.4 + (setp '(1 2 3 1)) + nil) + +(deftest setp.5 + (setp '(1 2 3)) + t) + +(deftest setp.6 + (setp '(a :a)) + t) + +(deftest setp.7 + (setp '(a :a) :key 'character) + nil) + +(deftest setp.8 + (setp '(a :a) :key 'character :test (constantly nil)) + t) + +(deftest set-equal.1 + (set-equal '(1 2 3) '(3 1 2)) + t) + +(deftest set-equal.2 + (set-equal '("Xa") '("Xb") + :test (lambda (a b) (eql (char a 0) (char b 0)))) + t) + +(deftest set-equal.3 + (set-equal '(1 2) '(4 2)) + nil) + +(deftest set-equal.4 + (set-equal '(a b c) '(:a :b :c) :key 'string :test 'equal) + t) + +(deftest set-equal.5 + (set-equal '(a d c) '(:a :b :c) :key 'string :test 'equal) + nil) + +(deftest set-equal.6 + (set-equal '(a b c) '(a b c d)) + nil) + +(deftest map-product.1 + (map-product 'cons '(2 3) '(1 4)) + ((2 . 1) (2 . 4) (3 . 1) (3 . 4))) + +(deftest map-product.2 + (map-product #'cons '(2 3) '(1 4)) + ((2 . 1) (2 . 4) (3 . 1) (3 . 4))) + +(deftest flatten.1 + (flatten '((1) 2 (((3 4))) ((((5)) 6)) 7)) + (1 2 3 4 5 6 7)) + +(deftest remove-from-plist.1 + (let ((orig '(a 1 b 2 c 3 d 4))) + (list (remove-from-plist orig 'a 'c) + (remove-from-plist orig 'b 'd) + (remove-from-plist orig 'b) + (remove-from-plist orig 'a) + (remove-from-plist orig 'd 42 "zot") + (remove-from-plist orig 'a 'b 'c 'd) + (remove-from-plist orig 'a 'b 'c 'd 'x) + (equal orig '(a 1 b 2 c 3 d 4)))) + ((b 2 d 4) + (a 1 c 3) + (a 1 c 3 d 4) + (b 2 c 3 d 4) + (a 1 b 2 c 3) + nil + nil + t)) + +(deftest delete-from-plist.1 + (let ((orig '(a 1 b 2 c 3 d 4 d 5))) + (list (delete-from-plist (copy-list orig) 'a 'c) + (delete-from-plist (copy-list orig) 'b 'd) + (delete-from-plist (copy-list orig) 'b) + (delete-from-plist (copy-list orig) 'a) + (delete-from-plist (copy-list orig) 'd 42 "zot") + (delete-from-plist (copy-list orig) 'a 'b 'c 'd) + (delete-from-plist (copy-list orig) 'a 'b 'c 'd 'x) + (equal orig (delete-from-plist orig)) + (eq orig (delete-from-plist orig)))) + ((b 2 d 4 d 5) + (a 1 c 3) + (a 1 c 3 d 4 d 5) + (b 2 c 3 d 4 d 5) + (a 1 b 2 c 3) + nil + nil + t + t)) + +(deftest mappend.1 + (mappend (compose 'list '*) '(1 2 3) '(1 2 3)) + (1 4 9)) + +(deftest assoc-value.1 + (let ((key1 '(complex key)) + (key2 'simple-key) + (alist '()) + (result '())) + (push 1 (assoc-value alist key1 :test #'equal)) + (push 2 (assoc-value alist key1 :test 'equal)) + (push 42 (assoc-value alist key2)) + (push 43 (assoc-value alist key2 :test 'eq)) + (push (assoc-value alist key1 :test #'equal) result) + (push (assoc-value alist key2) result) + + (push 'very (rassoc-value alist (list 2 1) :test #'equal)) + (push (cdr (assoc '(very complex key) alist :test #'equal)) result) + result) + ((2 1) (43 42) (2 1))) + +;;;; Numbers + +(deftest clamp.1 + (list (clamp 1.5 1 2) + (clamp 2.0 1 2) + (clamp 1.0 1 2) + (clamp 3 1 2) + (clamp 0 1 2)) + (1.5 2.0 1.0 2 1)) + +(deftest gaussian-random.1 + (let ((min -0.2) + (max +0.2)) + (multiple-value-bind (g1 g2) + (gaussian-random min max) + (values (<= min g1 max) + (<= min g2 max) + (/= g1 g2) ;uh + ))) + t + t + t) + +#+sbcl +(deftest gaussian-random.2 + (handler-case + (sb-ext:with-timeout 2 + (progn + (loop + :repeat 10000 + :do (gaussian-random 0 nil)) + 'done)) + (sb-ext:timeout () + 'timed-out)) + done) + +(deftest iota.1 + (iota 3) + (0 1 2)) + +(deftest iota.2 + (iota 3 :start 0.0d0) + (0.0d0 1.0d0 2.0d0)) + +(deftest iota.3 + (iota 3 :start 2 :step 3.0) + (2.0 5.0 8.0)) + +(deftest map-iota.1 + (let (all) + (declare (notinline map-iota)) + (values (map-iota (lambda (x) (push x all)) + 3 + :start 2 + :step 1.1d0) + all)) + 3 + (4.2d0 3.1d0 2.0d0)) + +(deftest lerp.1 + (lerp 0.5 1 2) + 1.5) + +(deftest lerp.2 + (lerp 0.1 1 2) + 1.1) + +(deftest lerp.3 + (lerp 0.1 4 25) + 6.1) + +(deftest mean.1 + (mean '(1 2 3)) + 2) + +(deftest mean.2 + (mean '(1 2 3 4)) + 5/2) + +(deftest mean.3 + (mean '(1 2 10)) + 13/3) + +(deftest median.1 + (median '(100 0 99 1 98 2 97)) + 97) + +(deftest median.2 + (median '(100 0 99 1 98 2 97 96)) + 193/2) + +(deftest variance.1 + (variance (list 1 2 3)) + 2/3) + +(deftest standard-deviation.1 + (< 0 (standard-deviation (list 1 2 3)) 1) + t) + +(deftest maxf.1 + (let ((x 1)) + (maxf x 2) + x) + 2) + +(deftest maxf.2 + (let ((x 1)) + (maxf x 0) + x) + 1) + +(deftest maxf.3 + (let ((x 1) + (c 0)) + (maxf x (incf c)) + (list x c)) + (1 1)) + +(deftest maxf.4 + (let ((xv (vector 0 0 0)) + (p 0)) + (maxf (svref xv (incf p)) (incf p)) + (list p xv)) + (2 #(0 2 0))) + +(deftest minf.1 + (let ((y 1)) + (minf y 0) + y) + 0) + +(deftest minf.2 + (let ((xv (vector 10 10 10)) + (p 0)) + (minf (svref xv (incf p)) (incf p)) + (list p xv)) + (2 #(10 2 10))) + +(deftest subfactorial.1 + (mapcar #'subfactorial (iota 22)) + (1 + 0 + 1 + 2 + 9 + 44 + 265 + 1854 + 14833 + 133496 + 1334961 + 14684570 + 176214841 + 2290792932 + 32071101049 + 481066515734 + 7697064251745 + 130850092279664 + 2355301661033953 + 44750731559645106 + 895014631192902121 + 18795307255050944540)) + +;;;; Arrays + +#+nil +(deftest array-index.type) + +#+nil +(deftest copy-array) + +;;;; Sequences + +(deftest rotate.1 + (list (rotate (list 1 2 3) 0) + (rotate (list 1 2 3) 1) + (rotate (list 1 2 3) 2) + (rotate (list 1 2 3) 3) + (rotate (list 1 2 3) 4)) + ((1 2 3) + (3 1 2) + (2 3 1) + (1 2 3) + (3 1 2))) + +(deftest rotate.2 + (list (rotate (vector 1 2 3 4) 0) + (rotate (vector 1 2 3 4)) + (rotate (vector 1 2 3 4) 2) + (rotate (vector 1 2 3 4) 3) + (rotate (vector 1 2 3 4) 4) + (rotate (vector 1 2 3 4) 5)) + (#(1 2 3 4) + #(4 1 2 3) + #(3 4 1 2) + #(2 3 4 1) + #(1 2 3 4) + #(4 1 2 3))) + +(deftest rotate.3 + (list (rotate (list 1 2 3) 0) + (rotate (list 1 2 3) -1) + (rotate (list 1 2 3) -2) + (rotate (list 1 2 3) -3) + (rotate (list 1 2 3) -4)) + ((1 2 3) + (2 3 1) + (3 1 2) + (1 2 3) + (2 3 1))) + +(deftest rotate.4 + (list (rotate (vector 1 2 3 4) 0) + (rotate (vector 1 2 3 4) -1) + (rotate (vector 1 2 3 4) -2) + (rotate (vector 1 2 3 4) -3) + (rotate (vector 1 2 3 4) -4) + (rotate (vector 1 2 3 4) -5)) + (#(1 2 3 4) + #(2 3 4 1) + #(3 4 1 2) + #(4 1 2 3) + #(1 2 3 4) + #(2 3 4 1))) + +(deftest rotate.5 + (values (rotate (list 1) 17) + (rotate (list 1) -5)) + (1) + (1)) + +(deftest shuffle.1 + (let ((s (shuffle (iota 100)))) + (list (equal s (iota 100)) + (every (lambda (x) + (member x s)) + (iota 100)) + (every (lambda (x) + (typep x '(integer 0 99))) + s))) + (nil t t)) + +(deftest shuffle.2 + (let ((s (shuffle (coerce (iota 100) 'vector)))) + (list (equal s (coerce (iota 100) 'vector)) + (every (lambda (x) + (find x s)) + (iota 100)) + (every (lambda (x) + (typep x '(integer 0 99))) + s))) + (nil t t)) + +(deftest shuffle.3 + (let* ((orig (coerce (iota 21) 'vector)) + (copy (copy-seq orig))) + (shuffle copy :start 10 :end 15) + (list (every #'eql (subseq copy 0 10) (subseq orig 0 10)) + (every #'eql (subseq copy 15) (subseq orig 15)))) + (t t)) + +(deftest random-elt.1 + (let ((s1 #(1 2 3 4)) + (s2 '(1 2 3 4))) + (list (dotimes (i 1000 nil) + (unless (member (random-elt s1) s2) + (return nil)) + (when (/= (random-elt s1) (random-elt s1)) + (return t))) + (dotimes (i 1000 nil) + (unless (member (random-elt s2) s2) + (return nil)) + (when (/= (random-elt s2) (random-elt s2)) + (return t))))) + (t t)) + +(deftest removef.1 + (let* ((x '(1 2 3)) + (x* x) + (y #(1 2 3)) + (y* y)) + (removef x 1) + (removef y 3) + (list x x* y y*)) + ((2 3) + (1 2 3) + #(1 2) + #(1 2 3))) + +(deftest deletef.1 + (let* ((x (list 1 2 3)) + (x* x) + (y (vector 1 2 3))) + (deletef x 2) + (deletef y 1) + (list x x* y)) + ((1 3) + (1 3) + #(2 3))) + +(deftest map-permutations.1 + (let ((seq (list 1 2 3)) + (seen nil) + (ok t)) + (map-permutations (lambda (s) + (unless (set-equal s seq) + (setf ok nil)) + (when (member s seen :test 'equal) + (setf ok nil)) + (push s seen)) + seq + :copy t) + (values ok (length seen))) + t + 6) + +(deftest proper-sequence.type.1 + (mapcar (lambda (x) + (typep x 'proper-sequence)) + (list (list 1 2 3) + (vector 1 2 3) + #2a((1 2) (3 4)) + (circular-list 1 2 3 4))) + (t t nil nil)) + +(deftest emptyp.1 + (mapcar #'emptyp + (list (list 1) + (circular-list 1) + nil + (vector) + (vector 1))) + (nil nil t t nil)) + +(deftest sequence-of-length-p.1 + (mapcar #'sequence-of-length-p + (list nil + #() + (list 1) + (vector 1) + (list 1 2) + (vector 1 2) + (list 1 2) + (vector 1 2) + (list 1 2) + (vector 1 2)) + (list 0 + 0 + 1 + 1 + 2 + 2 + 1 + 1 + 4 + 4)) + (t t t t t t nil nil nil nil)) + +(deftest length=.1 + (mapcar #'length= + (list nil + #() + (list 1) + (vector 1) + (list 1 2) + (vector 1 2) + (list 1 2) + (vector 1 2) + (list 1 2) + (vector 1 2)) + (list 0 + 0 + 1 + 1 + 2 + 2 + 1 + 1 + 4 + 4)) + (t t t t t t nil nil nil nil)) + +(deftest length=.2 + ;; test the compiler macro + (macrolet ((x (&rest args) + (funcall + (compile nil + `(lambda () + (length= ,@args)))))) + (list (x 2 '(1 2)) + (x '(1 2) '(3 4)) + (x '(1 2) 2) + (x '(1 2) 2 '(3 4)) + (x 1 2 3))) + (t t t t nil)) + +(deftest copy-sequence.1 + (let ((l (list 1 2 3)) + (v (vector #\a #\b #\c))) + (declare (notinline copy-sequence)) + (let ((l.list (copy-sequence 'list l)) + (l.vector (copy-sequence 'vector l)) + (l.spec-v (copy-sequence '(vector fixnum) l)) + (v.vector (copy-sequence 'vector v)) + (v.list (copy-sequence 'list v)) + (v.string (copy-sequence 'string v))) + (list (member l (list l.list l.vector l.spec-v)) + (member v (list v.vector v.list v.string)) + (equal l.list l) + (equalp l.vector #(1 2 3)) + (type= (upgraded-array-element-type 'fixnum) + (array-element-type l.spec-v)) + (equalp v.vector v) + (equal v.list '(#\a #\b #\c)) + (equal "abc" v.string)))) + (nil nil t t t t t t)) + +(deftest first-elt.1 + (mapcar #'first-elt + (list (list 1 2 3) + "abc" + (vector :a :b :c))) + (1 #\a :a)) + +(deftest first-elt.error.1 + (mapcar (lambda (x) + (handler-case + (first-elt x) + (type-error () + :type-error))) + (list nil + #() + 12 + :zot)) + (:type-error + :type-error + :type-error + :type-error)) + +(deftest setf-first-elt.1 + (let ((l (list 1 2 3)) + (s (copy-seq "foobar")) + (v (vector :a :b :c))) + (setf (first-elt l) -1 + (first-elt s) #\x + (first-elt v) 'zot) + (values l s v)) + (-1 2 3) + "xoobar" + #(zot :b :c)) + +(deftest setf-first-elt.error.1 + (let ((l 'foo)) + (multiple-value-bind (res err) + (ignore-errors (setf (first-elt l) 4)) + (typep err 'type-error))) + t) + +(deftest last-elt.1 + (mapcar #'last-elt + (list (list 1 2 3) + (vector :a :b :c) + "FOOBAR" + #*001 + #*010)) + (3 :c #\R 1 0)) + +(deftest last-elt.error.1 + (mapcar (lambda (x) + (handler-case + (last-elt x) + (type-error () + :type-error))) + (list nil + #() + 12 + :zot + (circular-list 1 2 3) + (list* 1 2 3 (circular-list 4 5)))) + (:type-error + :type-error + :type-error + :type-error + :type-error + :type-error)) + +(deftest setf-last-elt.1 + (let ((l (list 1 2 3)) + (s (copy-seq "foobar")) + (b (copy-seq #*010101001))) + (setf (last-elt l) '??? + (last-elt s) #\? + (last-elt b) 0) + (values l s b)) + (1 2 ???) + "fooba?" + #*010101000) + +(deftest setf-last-elt.error.1 + (handler-case + (setf (last-elt 'foo) 13) + (type-error () + :type-error)) + :type-error) + +(deftest starts-with.1 + (list (starts-with 1 '(1 2 3)) + (starts-with 1 #(1 2 3)) + (starts-with #\x "xyz") + (starts-with 2 '(1 2 3)) + (starts-with 3 #(1 2 3)) + (starts-with 1 1) + (starts-with nil nil)) + (t t t nil nil nil nil)) + +(deftest starts-with.2 + (values (starts-with 1 '(-1 2 3) :key '-) + (starts-with "foo" '("foo" "bar") :test 'equal) + (starts-with "f" '(#\f) :key 'string :test 'equal) + (starts-with -1 '(0 1 2) :key #'1+) + (starts-with "zot" '("ZOT") :test 'equal)) + t + t + t + nil + nil) + +(deftest ends-with.1 + (list (ends-with 3 '(1 2 3)) + (ends-with 3 #(1 2 3)) + (ends-with #\z "xyz") + (ends-with 2 '(1 2 3)) + (ends-with 1 #(1 2 3)) + (ends-with 1 1) + (ends-with nil nil)) + (t t t nil nil nil nil)) + +(deftest ends-with.2 + (values (ends-with 2 '(0 13 1) :key '1+) + (ends-with "foo" (vector "bar" "foo") :test 'equal) + (ends-with "X" (vector 1 2 #\X) :key 'string :test 'equal) + (ends-with "foo" "foo" :test 'equal)) + t + t + t + nil) + +(deftest ends-with.error.1 + (handler-case + (ends-with 3 (circular-list 3 3 3 1 3 3)) + (type-error () + :type-error)) + :type-error) + +(deftest sequences.passing-improper-lists + (macrolet ((signals-error-p (form) + `(handler-case + (progn ,form nil) + (type-error (e) + t))) + (cut (fn &rest args) + (with-gensyms (arg) + (print`(lambda (,arg) + (apply ,fn (list ,@(substitute arg '_ args)))))))) + (let ((circular-list (make-circular-list 5 :initial-element :foo)) + (dotted-list (list* 'a 'b 'c 'd))) + (loop for nth from 0 + for fn in (list + (cut #'lastcar _) + (cut #'rotate _ 3) + (cut #'rotate _ -3) + (cut #'shuffle _) + (cut #'random-elt _) + (cut #'last-elt _) + (cut #'ends-with :foo _)) + nconcing + (let ((on-circular-p (signals-error-p (funcall fn circular-list))) + (on-dotted-p (signals-error-p (funcall fn dotted-list)))) + (when (or (not on-circular-p) (not on-dotted-p)) + (append + (unless on-circular-p + (let ((*print-circle* t)) + (list + (format nil + "No appropriate error signalled when passing ~S to ~Ath entry." + circular-list nth)))) + (unless on-dotted-p + (list + (format nil + "No appropriate error signalled when passing ~S to ~Ath entry." + dotted-list nth))))))))) + nil) + +;;;; IO + +(deftest read-stream-content-into-string.1 + (values (with-input-from-string (stream "foo bar") + (read-stream-content-into-string stream)) + (with-input-from-string (stream "foo bar") + (read-stream-content-into-string stream :buffer-size 1)) + (with-input-from-string (stream "foo bar") + (read-stream-content-into-string stream :buffer-size 6)) + (with-input-from-string (stream "foo bar") + (read-stream-content-into-string stream :buffer-size 7))) + "foo bar" + "foo bar" + "foo bar" + "foo bar") + +(deftest read-stream-content-into-string.2 + (handler-case + (let ((stream (make-broadcast-stream))) + (read-stream-content-into-string stream :buffer-size 0)) + (type-error () + :type-error)) + :type-error) + +#+(or) +(defvar *octets* + (map '(simple-array (unsigned-byte 8) (7)) #'char-code "foo bar")) + +#+(or) +(deftest read-stream-content-into-byte-vector.1 + (values (with-input-from-byte-vector (stream *octets*) + (read-stream-content-into-byte-vector stream)) + (with-input-from-byte-vector (stream *octets*) + (read-stream-content-into-byte-vector stream :initial-size 1)) + (with-input-from-byte-vector (stream *octets*) + (read-stream-content-into-byte-vector stream 'alexandria::%length 6)) + (with-input-from-byte-vector (stream *octets*) + (read-stream-content-into-byte-vector stream 'alexandria::%length 3))) + *octets* + *octets* + *octets* + (subseq *octets* 0 3)) + +(deftest read-stream-content-into-byte-vector.2 + (handler-case + (let ((stream (make-broadcast-stream))) + (read-stream-content-into-byte-vector stream :initial-size 0)) + (type-error () + :type-error)) + :type-error) + +;;;; Macros + +(deftest with-unique-names.1 + (let ((*gensym-counter* 0)) + (let ((syms (with-unique-names (foo bar quux) + (list foo bar quux)))) + (list (find-if #'symbol-package syms) + (equal '("FOO0" "BAR1" "QUUX2") + (mapcar #'symbol-name syms))))) + (nil t)) + +(deftest with-unique-names.2 + (let ((*gensym-counter* 0)) + (let ((syms (with-unique-names ((foo "_foo_") (bar -bar-) (quux #\q)) + (list foo bar quux)))) + (list (find-if #'symbol-package syms) + (equal '("_foo_0" "-BAR-1" "q2") + (mapcar #'symbol-name syms))))) + (nil t)) + +(deftest with-unique-names.3 + (let ((*gensym-counter* 0)) + (multiple-value-bind (res err) + (ignore-errors + (eval + '(let ((syms + (with-unique-names ((foo "_foo_") (bar -bar-) (quux 42)) + (list foo bar quux)))) + (list (find-if #'symbol-package syms) + (equal '("_foo_0" "-BAR-1" "q2") + (mapcar #'symbol-name syms)))))) + (errorp err))) + t) + +(deftest once-only.1 + (macrolet ((cons1.good (x) + (once-only (x) + `(cons ,x ,x))) + (cons1.bad (x) + `(cons ,x ,x))) + (let ((y 0)) + (list (cons1.good (incf y)) + y + (cons1.bad (incf y)) + y))) + ((1 . 1) 1 (2 . 3) 3)) + +(deftest once-only.2 + (macrolet ((cons1 (x) + (once-only ((y x)) + `(cons ,y ,y)))) + (let ((z 0)) + (list (cons1 (incf z)) + z + (cons1 (incf z))))) + ((1 . 1) 1 (2 . 2))) + +(deftest parse-body.1 + (parse-body '("doc" "body") :documentation t) + ("body") + nil + "doc") + +(deftest parse-body.2 + (parse-body '("body") :documentation t) + ("body") + nil + nil) + +(deftest parse-body.3 + (parse-body '("doc" "body")) + ("doc" "body") + nil + nil) + +(deftest parse-body.4 + (parse-body '((declare (foo)) "doc" (declare (bar)) body) :documentation t) + (body) + ((declare (foo)) (declare (bar))) + "doc") + +(deftest parse-body.5 + (parse-body '((declare (foo)) "doc" (declare (bar)) body)) + ("doc" (declare (bar)) body) + ((declare (foo))) + nil) + +(deftest parse-body.6 + (multiple-value-bind (res err) + (ignore-errors + (parse-body '("foo" "bar" "quux") + :documentation t)) + (errorp err)) + t) + +;;;; Symbols + +(deftest ensure-symbol.1 + (ensure-symbol :cons :cl) + cons + :external) + +(deftest ensure-symbol.2 + (ensure-symbol "CONS" :alexandria) + cons + :inherited) + +(deftest ensure-symbol.3 + (ensure-symbol 'foo :keyword) + :foo + :external) + +(deftest ensure-symbol.4 + (ensure-symbol #\* :alexandria) + * + :inherited) + +(deftest format-symbol.1 + (let ((s (format-symbol nil '#:x-~d 13))) + (list (symbol-package s) + (string= (string '#:x-13) (symbol-name s)))) + (nil t)) + +(deftest format-symbol.2 + (format-symbol :keyword '#:sym-~a (string :bolic)) + :sym-bolic) + +(deftest format-symbol.3 + (let ((*package* (find-package :cl))) + (format-symbol t '#:find-~a (string 'package))) + find-package) + +(deftest make-keyword.1 + (list (make-keyword 'zot) + (make-keyword "FOO") + (make-keyword #\Q)) + (:zot :foo :q)) + +(deftest make-gensym-list.1 + (let ((*gensym-counter* 0)) + (let ((syms (make-gensym-list 3 "FOO"))) + (list (find-if 'symbol-package syms) + (equal '("FOO0" "FOO1" "FOO2") + (mapcar 'symbol-name syms))))) + (nil t)) + +(deftest make-gensym-list.2 + (let ((*gensym-counter* 0)) + (let ((syms (make-gensym-list 3))) + (list (find-if 'symbol-package syms) + (equal '("G0" "G1" "G2") + (mapcar 'symbol-name syms))))) + (nil t)) + +;;;; Type-system + +(deftest of-type.1 + (locally + (declare (notinline of-type)) + (let ((f (of-type 'string))) + (list (funcall f "foo") + (funcall f 'bar)))) + (t nil)) + +(deftest type=.1 + (type= 'string 'string) + t + t) + +(deftest type=.2 + (type= 'list '(or null cons)) + t + t) + +(deftest type=.3 + (type= 'null '(and symbol list)) + t + t) + +(deftest type=.4 + (type= 'string '(satisfies emptyp)) + nil + nil) + +(deftest type=.5 + (type= 'string 'list) + nil + t) + +(macrolet + ((test (type numbers) + `(deftest ,(format-symbol t '#:cdr5.~a (string type)) + (let ((numbers ,numbers)) + (values (mapcar (of-type ',(format-symbol t '#:negative-~a (string type))) numbers) + (mapcar (of-type ',(format-symbol t '#:non-positive-~a (string type))) numbers) + (mapcar (of-type ',(format-symbol t '#:non-negative-~a (string type))) numbers) + (mapcar (of-type ',(format-symbol t '#:positive-~a (string type))) numbers))) + (t t t nil nil nil nil) + (t t t t nil nil nil) + (nil nil nil t t t t) + (nil nil nil nil t t t)))) + (test fixnum (list most-negative-fixnum -42 -1 0 1 42 most-positive-fixnum)) + (test integer (list (1- most-negative-fixnum) -42 -1 0 1 42 (1+ most-positive-fixnum))) + (test rational (list (1- most-negative-fixnum) -42/13 -1 0 1 42/13 (1+ most-positive-fixnum))) + (test real (list most-negative-long-float -42/13 -1 0 1 42/13 most-positive-long-float)) + (test float (list most-negative-short-float -42.02 -1.0 0.0 1.0 42.02 most-positive-short-float)) + (test short-float (list most-negative-short-float -42.02s0 -1.0s0 0.0s0 1.0s0 42.02s0 most-positive-short-float)) + (test single-float (list most-negative-single-float -42.02f0 -1.0f0 0.0f0 1.0f0 42.02f0 most-positive-single-float)) + (test double-float (list most-negative-double-float -42.02d0 -1.0d0 0.0d0 1.0d0 42.02d0 most-positive-double-float)) + (test long-float (list most-negative-long-float -42.02l0 -1.0l0 0.0l0 1.0l0 42.02l0 most-positive-long-float))) + +;;;; Bindings + +(declaim (notinline opaque)) +(defun opaque (x) + x) + +(deftest if-let.1 + (if-let (x (opaque :ok)) + x + :bad) + :ok) + +(deftest if-let.2 + (if-let (x (opaque nil)) + :bad + (and (not x) :ok)) + :ok) + +(deftest if-let.3 + (let ((x 1)) + (if-let ((x 2) + (y x)) + (+ x y) + :oops)) + 3) + +(deftest if-let.4 + (if-let ((x 1) + (y nil)) + :oops + (and (not y) x)) + 1) + +(deftest if-let.5 + (if-let (x) + :oops + (not x)) + t) + +(deftest if-let.error.1 + (handler-case + (eval '(if-let x + :oops + :oops)) + (type-error () + :type-error)) + :type-error) + +(deftest when-let.1 + (when-let (x (opaque :ok)) + (setf x (cons x x)) + x) + (:ok . :ok)) + +(deftest when-let.2 + (when-let ((x 1) + (y nil) + (z 3)) + :oops) + nil) + +(deftest when-let.3 + (let ((x 1)) + (when-let ((x 2) + (y x)) + (+ x y))) + 3) + +(deftest when-let.error.1 + (handler-case + (eval '(when-let x :oops)) + (type-error () + :type-error)) + :type-error) + +(deftest when-let*.1 + (let ((x 1)) + (when-let* ((x 2) + (y x)) + (+ x y))) + 4) + +(deftest when-let*.2 + (let ((y 1)) + (when-let* (x y) + (1+ x))) + 2) + +(deftest when-let*.3 + (when-let* ((x t) + (y (consp x)) + (z (error "OOPS"))) + t) + nil) + +(deftest when-let*.error.1 + (handler-case + (eval '(when-let* x :oops)) + (type-error () + :type-error)) + :type-error) + +(deftest doplist.1 + (let (keys values) + (doplist (k v '(a 1 b 2 c 3) (values t (reverse keys) (reverse values) k v)) + (push k keys) + (push v values))) + t + (a b c) + (1 2 3) + nil + nil) + +(deftest count-permutations.1 + (values (count-permutations 31 7) + (count-permutations 1 1) + (count-permutations 2 1) + (count-permutations 2 2) + (count-permutations 3 2) + (count-permutations 3 1)) + 13253058000 + 1 + 2 + 2 + 6 + 3) + +(deftest binomial-coefficient.1 + (alexandria:binomial-coefficient 1239 139) + 28794902202288970200771694600561826718847179309929858835480006683522184441358211423695124921058123706380656375919763349913245306834194782172712255592710204598527867804110129489943080460154) + +;; Exercise bignum case (at least on x86). +(deftest binomial-coefficient.2 + (alexandria:binomial-coefficient 2000000000000 20) + 430998041177272843950422879590338454856322722740402365741730748431530623813012487773080486408378680853987520854296499536311275320016878730999689934464711239072435565454954447356845336730100919970769793030177499999999900000000000) + +(deftest copy-stream.1 + (let ((data "sdkfjhsakfh weior763495ewofhsdfk sdfadlkfjhsadf woif sdlkjfhslkdfh sdklfjh")) + (values (equal data + (with-input-from-string (in data) + (with-output-to-string (out) + (alexandria:copy-stream in out)))) + (equal (subseq data 10 20) + (with-input-from-string (in data) + (with-output-to-string (out) + (alexandria:copy-stream in out :start 10 :end 20)))) + (equal (subseq data 10) + (with-input-from-string (in data) + (with-output-to-string (out) + (alexandria:copy-stream in out :start 10)))) + (equal (subseq data 0 20) + (with-input-from-string (in data) + (with-output-to-string (out) + (alexandria:copy-stream in out :end 20)))))) + t + t + t + t) + +(deftest extremum.1 + (let ((n 0)) + (dotimes (i 10) + (let ((data (shuffle (coerce (iota 10000 :start i) 'vector))) + (ok t)) + (unless (eql i (extremum data #'<)) + (setf ok nil)) + (unless (eql i (extremum (coerce data 'list) #'<)) + (setf ok nil)) + (unless (eql (+ 9999 i) (extremum data #'>)) + (setf ok nil)) + (unless (eql (+ 9999 i) (extremum (coerce data 'list) #'>)) + (setf ok nil)) + (when ok + (incf n)))) + (when (eql 10 (extremum #(100 1 10 1000) #'> :start 1 :end 3)) + (incf n)) + (when (eql -1000 (extremum #(100 1 10 -1000) #'> :key 'abs)) + (incf n)) + (when (eq nil (extremum "" (lambda (a b) (error "wtf? ~S, ~S" a b)))) + (incf n)) + n) + 13) + +(deftest starts-with-subseq.string + (starts-with-subseq "f" "foo" :return-suffix t) + t + "oo") + +(deftest starts-with-subseq.vector + (starts-with-subseq #(1) #(1 2 3) :return-suffix t) + t + #(2 3)) + +(deftest starts-with-subseq.list + (starts-with-subseq '(1) '(1 2 3) :return-suffix t) + t + (2 3)) + +(deftest starts-with-subseq.start1 + (starts-with-subseq "foo" "oop" :start1 1) + t + nil) + +(deftest starts-with-subseq.start2 + (starts-with-subseq "foo" "xfoop" :start2 1) + t + nil) + +(deftest format-symbol.print-case-bound + (let ((upper (intern "FOO-BAR")) + (lower (intern "foo-bar")) + (*print-escape* nil)) + (values + (let ((*print-case* :downcase)) + (and (eq upper (format-symbol t "~A" upper)) + (eq lower (format-symbol t "~A" lower)))) + (let ((*print-case* :upcase)) + (and (eq upper (format-symbol t "~A" upper)) + (eq lower (format-symbol t "~A" lower)))) + (let ((*print-case* :capitalize)) + (and (eq upper (format-symbol t "~A" upper)) + (eq lower (format-symbol t "~A" lower)))))) + t + t + t) + +(deftest iota.fp-start-and-complex-integer-step + (equal '(#C(0.0 0.0) #C(0.0 2.0) #C(0.0 4.0)) + (iota 3 :start 0.0 :step #C(0 2))) + t) + +(deftest parse-ordinary-lambda-list.1 + (multiple-value-bind (req opt rest keys allowp aux keyp) + (parse-ordinary-lambda-list '(a b c + &optional o1 (o2 42) (o3 42 o3-supplied?) + &key (k1) ((:key k2)) (k3 42 k3-supplied?)) + :normalize t) + (and (equal '(a b c) req) + (equal '((o1 nil nil) + (o2 42 nil) + (o3 42 o3-supplied?)) + opt) + (equal '(((:k1 k1) nil nil) + ((:key k2) nil nil) + ((:k3 k3) 42 k3-supplied?)) + keys) + (not allowp) + (not aux) + (eq t keyp))) + t) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/types.lisp b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/types.lisp new file mode 100644 index 0000000..1942d0e --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/alexandria-20191227-git/types.lisp @@ -0,0 +1,137 @@ +(in-package :alexandria) + +(deftype array-index (&optional (length (1- array-dimension-limit))) + "Type designator for an index into array of LENGTH: an integer between +0 (inclusive) and LENGTH (exclusive). LENGTH defaults to one less than +ARRAY-DIMENSION-LIMIT." + `(integer 0 (,length))) + +(deftype array-length (&optional (length (1- array-dimension-limit))) + "Type designator for a dimension of an array of LENGTH: an integer between +0 (inclusive) and LENGTH (inclusive). LENGTH defaults to one less than +ARRAY-DIMENSION-LIMIT." + `(integer 0 ,length)) + +;; This MACROLET will generate most of CDR5 (http://cdr.eurolisp.org/document/5/) +;; except the RATIO related definitions and ARRAY-INDEX. +(macrolet + ((frob (type &optional (base-type type)) + (let ((subtype-names (list)) + (predicate-names (list))) + (flet ((make-subtype-name (format-control) + (let ((result (format-symbol :alexandria format-control + (symbol-name type)))) + (push result subtype-names) + result)) + (make-predicate-name (sybtype-name) + (let ((result (format-symbol :alexandria '#:~A-p + (symbol-name sybtype-name)))) + (push result predicate-names) + result)) + (make-docstring (range-beg range-end range-type) + (let ((inf (ecase range-type (:negative "-inf") (:positive "+inf")))) + (format nil "Type specifier denoting the ~(~A~) range from ~A to ~A." + type + (if (equal range-beg ''*) inf (ensure-car range-beg)) + (if (equal range-end ''*) inf (ensure-car range-end)))))) + (let* ((negative-name (make-subtype-name '#:negative-~a)) + (non-positive-name (make-subtype-name '#:non-positive-~a)) + (non-negative-name (make-subtype-name '#:non-negative-~a)) + (positive-name (make-subtype-name '#:positive-~a)) + (negative-p-name (make-predicate-name negative-name)) + (non-positive-p-name (make-predicate-name non-positive-name)) + (non-negative-p-name (make-predicate-name non-negative-name)) + (positive-p-name (make-predicate-name positive-name)) + (negative-extremum) + (positive-extremum) + (below-zero) + (above-zero) + (zero)) + (setf (values negative-extremum below-zero + above-zero positive-extremum zero) + (ecase type + (fixnum (values 'most-negative-fixnum -1 1 'most-positive-fixnum 0)) + (integer (values ''* -1 1 ''* 0)) + (rational (values ''* '(0) '(0) ''* 0)) + (real (values ''* '(0) '(0) ''* 0)) + (float (values ''* '(0.0E0) '(0.0E0) ''* 0.0E0)) + (short-float (values ''* '(0.0S0) '(0.0S0) ''* 0.0S0)) + (single-float (values ''* '(0.0F0) '(0.0F0) ''* 0.0F0)) + (double-float (values ''* '(0.0D0) '(0.0D0) ''* 0.0D0)) + (long-float (values ''* '(0.0L0) '(0.0L0) ''* 0.0L0)))) + `(progn + (deftype ,negative-name () + ,(make-docstring negative-extremum below-zero :negative) + `(,',base-type ,,negative-extremum ,',below-zero)) + + (deftype ,non-positive-name () + ,(make-docstring negative-extremum zero :negative) + `(,',base-type ,,negative-extremum ,',zero)) + + (deftype ,non-negative-name () + ,(make-docstring zero positive-extremum :positive) + `(,',base-type ,',zero ,,positive-extremum)) + + (deftype ,positive-name () + ,(make-docstring above-zero positive-extremum :positive) + `(,',base-type ,',above-zero ,,positive-extremum)) + + (declaim (inline ,@predicate-names)) + + (defun ,negative-p-name (n) + (and (typep n ',type) + (< n ,zero))) + + (defun ,non-positive-p-name (n) + (and (typep n ',type) + (<= n ,zero))) + + (defun ,non-negative-p-name (n) + (and (typep n ',type) + (<= ,zero n))) + + (defun ,positive-p-name (n) + (and (typep n ',type) + (< ,zero n))))))))) + (frob fixnum integer) + (frob integer) + (frob rational) + (frob real) + (frob float) + (frob short-float) + (frob single-float) + (frob double-float) + (frob long-float)) + +(defun of-type (type) + "Returns a function of one argument, which returns true when its argument is +of TYPE." + (lambda (thing) (typep thing type))) + +(define-compiler-macro of-type (&whole form type &environment env) + ;; This can yeild a big benefit, but no point inlining the function + ;; all over the place if TYPE is not constant. + (if (constantp type env) + (with-gensyms (thing) + `(lambda (,thing) + (typep ,thing ,type))) + form)) + +(declaim (inline type=)) +(defun type= (type1 type2) + "Returns a primary value of T is TYPE1 and TYPE2 are the same type, +and a secondary value that is true is the type equality could be reliably +determined: primary value of NIL and secondary value of T indicates that the +types are not equivalent." + (multiple-value-bind (sub ok) (subtypep type1 type2) + (cond ((and ok sub) + (subtypep type2 type1)) + (ok + (values nil ok)) + (t + (multiple-value-bind (sub ok) (subtypep type2 type1) + (declare (ignore sub)) + (values nil ok)))))) + +(define-modify-macro coercef (type-spec) coerce + "Modify-macro for COERCE.") diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/.gitref b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/.gitref new file mode 100644 index 0000000..f879a62 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/.gitref @@ -0,0 +1 @@ +c1f15e2bd02fabe7bb468b05fe311cd9a932f14f \ No newline at end of file diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/.travis.yml b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/.travis.yml new file mode 100644 index 0000000..f02735e --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/.travis.yml @@ -0,0 +1,41 @@ +language: emacs + +env: + # we test emacs23 with sbcl only + - "CHECK_TARGET=check LISP=sbcl EMACS=emacs23" + - "CHECK_TARGET=check-fancy LISP=sbcl EMACS=emacs23" + + # for emacs24, use more combinations + - "CHECK_TARGET=check LISP=sbcl EMACS=emacs24" + #- "CHECK_TARGET=check LISP=cmucl EMACS=emacs24" + - "CHECK_TARGET=check LISP=ccl EMACS=emacs24" + - "CHECK_TARGET=check-fancy LISP=sbcl EMACS=emacs24" + #- "CHECK_TARGET=check-fancy LISP=cmucl EMACS=emacs24" + - "CHECK_TARGET=check-fancy LISP=ccl EMACS=emacs24" + + # also, for emacs24/sbcl test some more contribs in isolation + - "CHECK_TARGET=check-repl LISP=sbcl EMACS=emacs24" + - "CHECK_TARGET=check-indentation LISP=sbcl EMACS=emacs24" + +install: + - curl https://raw.githubusercontent.com/luismbo/cl-travis/master/install.sh | bash + - if [ "$EMACS" = "emacs23" ]; then + sudo apt-get -qq update && + sudo apt-get -qq -f install && + sudo apt-get -qq install emacs23-nox; + fi + - if [ "$EMACS" = "emacs24" ]; then + sudo add-apt-repository -y ppa:cassou/emacs && + sudo apt-get -qq update && + sudo apt-get -qq -f install && + sudo apt-get -qq install emacs24-nox; + fi + +script: + - make LISP=$LISP EMACS=$EMACS $CHECK_TARGET + +notifications: + email: + recipients: + - slime-cvs@common-lisp.net + # on_success: always # for testing diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/CONTRIBUTING.md b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/CONTRIBUTING.md new file mode 100644 index 0000000..6bf01dc --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/CONTRIBUTING.md @@ -0,0 +1,153 @@ +# The SLIME Hacker's Handbook + +## Lisp code file structure + +The Lisp code is organised into these files: + +* `swank-backend.lisp`: Definition of the interface to non-portable +features. Stand-alone. + +* `swank-.lisp`: Backend implementation for a specific +Common Lisp system. Uses swank-backend.lisp. + +* `swank.lisp`: The top-level server program, built from the other +components. Uses swank-backend.lisp as an interface to the actual +backends. + +* `slime.el`: The Superior Lisp Inferior Mode for Emacs, i.e. the +Emacs frontend that the user actually interacts with and that connects +to the SWANK server to send expressions to, and retrieve information +from the running Common Lisp system. + +* `contrib/*.lisp`: Lisp related code for add-ons to SLIME that are +maintained by their respective authors. Consult contrib/README for +more information. + +## Test Suite + +The Makefile includes a `check` target to run the ERT-based test +suite. This can give a pretty good sanity-check for your changes + +Some backends do not pass the full test suite because of missing +features. In these cases the test suite is still useful to ensure that +changes don't introduce new errors. CMUCL historically passes the full +test suite so it makes a good sanity check for fundamental changes +(e.g. to the protocol). + +Running the test suite, adding new cases, and increasing the number of +cases that backends support are all very good for karma. + + +## Source code layout + +We use a special source file layout to take advantage of some fancy +Emacs features: outline-mode and "narrowing". + +### Outline structure + +Our source files have a hierarchical structure using comments like +these: + +```el +;;;; Heading +;;;;; Subheading +... etc +``` + +We do this as a nice way to structure the program. We try to keep each +(sub)section small enough to fit in your head: typically around 50-200 +lines of code each. Each section usually begins with a brief +introduction, followed by its highest-level functions, followed by +their subroutines. This is a pleasing shape for a source file to have. + +Of course the comments mean something to Emacs too. One handy usage is +to bring up a hyperlinked "table of contents" for the source file +using this command: + +```el +(defun show-outline-structure () + "Show the outline-mode structure of the current buffer." + (interactive) + (occur (concat "^" outline-regexp))) +``` + +Another is to use `outline-minor-mode` to fold away certain parts of +the buffer. See the `Outline Mode` section of the Emacs manual for +details about that. + +### Pagebreak characters (^L) + +We partition source files into chunks using pagebreak characters. Each +chunk is a substantial piece of code that can be considered in +isolation, that could perhaps be a separate source file if we were +fanatical about small source files (rather than big ones!) + +The page breaks usually go in the same place as top-level outline-mode +headings, but they don't have to. They're flexible. + +In the old days, when `slime.el` was less than 100 pages long, these +page breaks were helpful when printing it out to read. Now they're +useful for something else: narrowing. + +You can use `C-x n p` (`narrow-to-page`) to "zoom in" on a +pagebreak-delimited section of the file as if it were a separate +buffer in itself. You can then use `C-x n w` (`widen`) to "zoom out" and +see the whole file again. This is tremendously helpful for focusing +your attention on one part of the program as if it were its own file. + +(This file contains some page break characters. If you're reading in +Emacs you can press `C-x n p` to narrow to this page, and then later +`C-x n w` to make the whole buffer visible again.) + + +## Coding style + +We like the fact that each function in SLIME will fit on a single +screen (80x20), and would like to preserve this property! Beyond that +we're not dogmatic :-) + +In early discussions we all made happy noises about the advice in +Norvig and Pitman's +[Tutorial on Good Lisp Programming Style](http://www.norvig.com/luv-slides.ps). + +For Emacs Lisp, we try to follow the _Tips and Conventions_ in +Appendix D of the GNU Emacs Lisp Reference Manual (see Info file +`elisp`, node `Tips`). + +We use Emacs conventions for docstrings: the first line should be a +complete sentence to make the output of `apropos` look good. We also +use imperative verbs. + +Now that XEmacs support is gone, rewrites using packages in GNU +Emacs's core get extra karma. + +Customization variables complicate testing and therefore we only add +new ones after careful consideration. Adding new customization +variables is bad for karma. + +We generally neither use nor recommend eval-after-load. + +The biggest problem with SLIME's code base is feature creep. Keep in +mind that the Right Thing isn't always the Smart Thing. If you can't +find an elegant solution to a problem then you're probably solving the +wrong problem. It's often a good idea to simplify the problem and to +ignore rarely needed cases. + +_Remember that to rewrite a program better is the sincerest form of +code appreciation. When you can see a way to rewrite a part of SLIME +better, please do so!_ + + + +## Pull requests + +* Read [how to properly contribute to open source projects on Github][1]. +* Use a topic branch to easily amend a pull request later, if necessary. +* Open a [pull request][2] that relates to *only* one subject with a + clear title and description in grammatically correct, complete + sentences. +* Write [good commit messages][3]. + +[1]: http://gun.io/blog/how-to-github-fork-branch-and-pull-request +[2]: https://help.github.com/articles/using-pull-requests +[3]: http://chris.beams.io/posts/git-commit/ diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/Makefile b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/Makefile new file mode 100644 index 0000000..ed63e6f --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/Makefile @@ -0,0 +1,113 @@ +### Makefile for SLIME +# +# This file is in the public domain. + +# Variables +# +EMACS=emacs +LISP=sbcl + +LOAD_PATH=-L . + +ELFILES := slime.el slime-autoloads.el slime-tests.el $(wildcard lib/*.el) +ELCFILES := $(ELFILES:.el=.elc) + +default: compile contrib-compile + +all: compile + +help: + @printf "\ +Main targets\n\ +all -- see compile\n\ +compile -- compile .el files\n\ +check -- run tests in batch mode\n\ +clean -- delete generated files\n\ +doc-help -- print help about doc targets\n\ +help-vars -- print info about variables\n\ +help -- print this message\n" + +help-vars: + @printf "\ +Main make variables:\n\ +EMACS -- program to start Emacs ($(EMACS))\n\ +LISP -- program to start Lisp ($(LISP))\n\ +SELECTOR -- selector for ERT tests ($(SELECTOR))\n" + +# Compilation +# +slime.elc: slime.el lib/hyperspec.elc + +%.elc: %.el + $(EMACS) -Q $(LOAD_PATH) --batch -f batch-byte-compile $< + +compile: $(ELCFILES) + +# Automated tests +# +SELECTOR=t + +check: compile + $(EMACS) -Q --batch $(LOAD_PATH) \ + --eval "(require 'slime-tests)" \ + --eval "(slime-setup)" \ + --eval "(setq inferior-lisp-program \"$(LISP)\")" \ + --eval '(slime-batch-test (quote $(SELECTOR)))' + +# run tests interactively +# +# FIXME: Not terribly useful until bugs in ert-run-tests-interactively +# are fixed. +test: compile + $(EMACS) -Q -nw $(LOAD_PATH) \ + --eval "(require 'slime-tests)" \ + --eval "(slime-setup)" \ + --eval "(setq inferior-lisp-program \"$(LISP)\")" \ + --eval '(slime-batch-test (quote $(SELECTOR)))' + +compile-swank: + echo '(load "swank-loader.lisp")' '(swank-loader:init :setup nil)' \ + | $(LISP) + +run-swank: + { echo \ + '(load "swank-loader.lisp")' \ + '(swank-loader:init)' \ + '(swank:create-server)' \ + && cat; } \ + | $(LISP) + +elpa-slime: + echo "Not implemented yet: elpa-slime target" && exit 255 + +elpa: elpa-slime contrib-elpa + +# Cleanup +# +FASLREGEX = .*\.\(fasl\|ufasl\|sse2f\|lx32fsl\|abcl\|fas\|lib\|trace\)$$ + +clean-fasls: + find . -regex '$(FASLREGEX)' -exec rm -v {} \; + [ ! -d ~/.slime/fasl ] || rm -rf ~/.slime/fasl + +clean: clean-fasls + find . -iname '*.elc' -exec rm {} \; + + +# Contrib stuff. Should probably also go to contrib/ +# +MAKECONTRIB=$(MAKE) -C contrib EMACS="$(EMACS)" LISP="$(LISP)" +contrib-check-% check-%: + $(MAKECONTRIB) $(@:contrib-%=%) +contrib-elpa: + $(MAKECONTRIB) elpa-all +contrib-compile: + $(MAKECONTRIB) compile + +# Doc +# +doc-%: + $(MAKE) -C doc $(@:doc-%=%) +doc: doc-help + +.PHONY: clean elpa compile check doc dist diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/NEWS b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/NEWS new file mode 100644 index 0000000..9f24e38 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/NEWS @@ -0,0 +1,609 @@ +* SLIME News -*- mode: outline; coding: utf-8 -*- +* 2.24 (May 2019) +*** Minor improvements. + +* 2.23 (December 2018) +*** Improved compatiblity with different versions of Emacs, SBCL, Clasp, Allegro. +*** Bug fixes + +* 2.22 (July 2018) +*** Improved compatiblity with Emacs 26 + +* 2.21 (June 2018) +*** Improved compatiblity with Emacs 26 +*** Mezzano support + +* 2.20 (August 2017) +** Core +*** More secure handling of ~/.slime-secret +** SBCL backend +*** Compatiblity with the latest SBCL and older SBCL. +** ECL backend +*** Numerous enhancements + +* 2.19 (February 2017) +** Core +*** Function `create-server` now accepts optional `interface` argument. +Swank will bind the PORT on this interface. By default, interface is 127.0.0.1. +This argument can be used, for example, to bind swank on IPv6 interface "::1". +** SBCL backend +*** Now swank can be bound to IPv6 interface and can work on IPv6-only machines. +*** Compatiblity with the latest SBCL + +* 2.18 (May 2016) +*** Mostly bug fixes and compatibility with newer implementations + +* 2.17 (February 2016) +** Contribs +*** New contrib, slime-macrostep, for more advanced in-place macroexpansion. +*** New contrib, slime-quicklisp. + +* 2.16 (January 2016) +*** Auto-completion now supports package-local nicknames on SBCL and ABCL. +*** Bug fixes and updates for newer implementations. + +* 2.15 (August 2015) +** Core +*** Completions are now displayed with `completion-at-point'. +The new variable `slime-completion-at-point-functions' should now be +used to customize completion. The old variable +`slime-complete-symbol-function' still works, but it is considered +obsolete and will be removed eventually. + +** SBCL backend +*** M-. can locate forms within PROGN/MACROLET/etc. Needs SBCL 1.2.15 + +* 2.14 (June 2015) +** Core +*** Rationals are displayed in the echo area as floats too +*** Some of SLDB's faces now have MORE COLOR +*** Clicking with mouse-1 within inspector does things +As do mouse-6 and mouse-7. (Thanks to Attila Lendvai.) + +** slime-c-p-c (Compound Prefix Completion) +*** Now takes a better guess at symbol case (issue #233) + +** slime-fancy +*** slime-mdot-fu is now enabled by default + +** SBCL backend +*** Now able to jump to ir1-translators, declaims and alien types +*** Various updates supporting SBCL 1.2.12 + +** ABCL backend +*** Fixed inspection of frame-locals in the debugger +(Thanks to Mark Evenson.) + +* 2.13 (March 2015) + +** Core +*** slime-cycle-connections has been deprecated +It has been replaced by slime-next-connection and +slime-prev-connection. A shortcut for the latter has been added to +slime-selector. + +** slime-mdot-fu +The slime-mdot-fu contrib has been brought back to life. (Thanks to Charles +Zhang. Issues #8, #231 and #232.) + +** slime-typeout-frame +The slime-typeout-frame contrib has been restored. (Issue #221.) + +** SBCL backend +*** Fixed xrefs coming from C-c C-c +Issue #227. + +** CMUCL, SBCL and SCL backends +*** Better support for custom readtables +Functionality that depends on SWANK's source-path-parser, such as +`slime-find-definition', now works properly in face of custom +readtables by honoring SWANK:*READTABLE-ALIST*. (Thanks to Gábor +Melis. PR #244.) + +** Kawa backend +*** Updated for Kawa version 2.0 + +* 2.12 (January 2015) + +** Core +A couple of regressions introduced in version 2.10 were fixed. + +*** slime-compile-buffer (C-c C-k) no longer tries to save every buffer +*** slime-autodoc-mode doesn't spam the minibuffer anymore + +** SWANK +*** CREATE-SERVER provides interactive restarts when port is taken +Thanks to Adlai Chandrasekhar. (PR #204.) + +** slime-fuzzy +New variable *FUZZY-DUPLICATE-SYMBOL-FILTER* allows customization of +how symbols accessible from multiple packages should be +canonicalized. Defaults to :NEAREST-PACKAGE, a departure from the +previous default behaviour which is still available using +:HOME-PACKAGE. The new behaviour expands "ui:e-l" to +"uiop:ensure-list" rather than "uiop/utility:ensure-list". Consult the +manual for other options and other details. + +Thanks to Ivan Shvedunov. (PR #205.) + +* 2.11 (December 2014) + +** MELPA is now an officially supported installation method +Various bugs involving installation and upgrading via package.el were +fixed. See the README for more details. (Issues #125, #195, #208.) + +** Core +*** Compilation via the xref buffer now works again + +** slime-repl / slime-presentations +Only text to the left of the cursor should limit the scope of history +navigation. Fixed a long-standing bug that violated this when +slime-presentations was enabled. (Thanks to Ivan Shvedunov. PR #207.) + +** slime-package-fu +Now handles strings as symbol designators, is mindful of trailing +whitespace and properly handles an :export clause immediately +following the package name. (Thanks to Leo Liu. PR #145.) + +** slime-indentation +The edge case handling described in slime-cl-indent.el:958 have been +has been restored. + +** Allegro CL backend +Support for mlisp was restored. It had been broken by the previous +release. (Reported by Alexandre Rademaker. Issue #209.) + +** New experimental SWANK backend for MLWorks + +** SWANK +swank-listener-hooks was restored. (Thanks to Ivan Shvedunov. PR #210.) + +* 2.10.1 (October 2014) + +*** The SWANK-BACKEND nickname has been added to the SWANK/BACKEND package +This should ease the migration of external projects that depend on the +SWANK-BACKEND package. However, note that SWANK/BACKEND (as well as +the other SWANK/* packages) are internal packages. Please refer to +Conium for a project that purports to +offer a stable API for debugger- and compiler-related tasks in Common +Lisp. + +* 2.10 (October 2014) + +** Core +*** The SWANK-BACKEND package has been renamed to SWANK/BACKEND +Furthermore, implementations of the SWANK-BACKEND interface have +individual packages such as SWANK/SBCL, SWANK/CCL, etc. Other packages +such as SWANK-RPC, SWANK-GRAY have likewise had their hyphens turned +into slashes. + +*** slime-compile-file is now aware of compilation-ask-about-save +When set to nil, SLIME will save modified buffers without asking. +compilation-save-buffers-predicate can be used to customize which +buffers should be automatically saved. + +** slime-repl +*** Clearing REPL output no longer deletes the prompt (issue #183) + +** slime-autodoc +This contrib has been rewritten. Please report any regressions you may +find. + +** ABCL backend +*** Inspecting CLOS objects works properly again +*** SLDB frame arguments have become inspectable + +** SBCL backend +*** Source locations involving the #. reader macro +The aforementioned mechanism was adapted to recent changes in the +internals of the SBCL reader. + +*** Breakage involving recent versions of SBCL on Windows was fixed (issue #192) +We no longer assume SB-SYS:ENABLE-INTERRUPT exists on Windows SBCL. + +** MKCL backend +New backend for ManKai Common Lisp. + +** CMUCL backend +*** Support for versions prior to 20c has been removed + +** MIT Scheme backend +*** Updated and now requires MIT Scheme 9.2 + +* 2.9 (August 2014) + +** Core +*** Various display-related bugfixes + +** CMUCL +*** M-. now works on condition classes + +* 2.8 (July 2014) + +** Core + +*** Inspector fixes and improvements for SBCL. + +** Contribs +*** Kawa backend supports Kawa 1.14. + +* 2.7 (June 2014) + +** Core +*** SWANK now tries harder to send double-floats to Emacs + +** Allegro CL Backend +*** Added implementation for FUNCTION-NAME and FIND-SOURCE-LOCATION interfaces +Notably, this means that pressing "." in the SLIME inspector now works +on Allegro CL. (Thanks to Gábor Melis.) + +* 2.6 (May 2014) + +** Core + +*** *print-readably* bound to nil when displaying condition messages + +*** Issue #144: Removed nicknames and short package names +The STD nickname for SWANK-TRACE-DIALOG was removed. MONITOR was +renamed to SWANK-MONITOR and its nickname MON removed. + +*** Issues #135, #154: slime-to-lisp-filename used more pervasively +Now used for the both the port-file and loader file when announced +from Emacs to the lisp backend. Allows a user-written +`slime-to-lisp-filename-function' that supports Cygwin lisps with +non-Cygwin Emacsen or vice-versa. See #135 for an example of such a +function. + +*** Issue #155: Stale SLDB buffers are now properly removed +Indirect exits from an SLDB buffer that was not selected in a window +would leave a stale buffer behind, leading to an inconsistent state +and unexpected errors. + +** Contribs + +*** Issue #139: Restored "copy to REPL" for slime-presentations +`slime-copy-presentation-at-point-to-repl' will copy a presentation to +the REPL, place it at point, and _not_ set *, ** and ***. This +behaviour restored after refactorings of "copy to REPL" behaviour of +previous versions. + +*** Issue #140: Improvements in the "copy to REPL" behaviour +With or without the slime-presentations contrib, M-RET will +copy/return values to REPL from both Inspector and SLDB buffers, +setting *, ** and *** . If the slime-presentations contrib is enabled, +the returned part will be an interactive presentation. The protocol +for copying down parts to REPL has been reworked to not assume a CL +backend . + +*** Now supports more CLHS references: :type, :system-class, :ansi-cl + +*** Issue #133: Fixed links to the SBCL manual + +** Backend improvements + +*** SBCL + +**** `slime-set-default-directory' now calls chdir +This propagates its effects to subprocesses. + +* 2.5 (April 2014) + +** Backend improvements + +*** Clozure CL + +**** `slime-set-default-directory' now calls chdir +This propagates its effects to subprocesses. + +*** Allegro CL + +**** swank-compile-string no longer binds *default-pathname-defaults* +This was inconsistent with the behaviour of other backends and caused +strange issues with SYS:TEMPORARY-DIRECTORY. + +**** Improved source file recording +Whenever possible interactive definition compilation is mapped to the +actual source file rather than the buffer name to avoid breakage when +the the buffer name changes or is closed. + +** SLIME Trace Dialog + +*** (Un)Tracing a definition automatically updates the trace status + +** slime-repl + +*** Inspecting * in REPL no longer inspects ** (issue #137) + +** slime-autodoc + +*** Multiline arglists in `slime-autodoc' no longer imply a newline (issue #7) + +** Core Bugfixes + +*** SWANK port file name defined in more portable fashion +Bug reported by Mirko Vukovic on slime-devel. + +*** inferior-lisp-program can now hold paths with spaces (issue #116) + +* 2.4 (March 2014) + +** New contrib SLIME Trace Dialog included in `slime-fancy' +Interactive interface to tracing functions and methods. See manual for +details. + +** New contrib `slime-fancy-trace', included in `slime-fancy' +If your implementation allows it, trace complex method signatures, +labels, etc... + +** New options in `slime-cl-indent.el' used by the `slime-indentation' contrib +New variables are `lisp-loop-body-forms-indentation' and +`lisp-loop-body-forms-indentation'. + +** New command `sldb-copy-down-to-repl' bound to M-RET in debugger +Copies the frame variable under point to the REPL, much as +`slime-inspector-copy-down-to-repl' does. + +** New command `slime-delete-package' + +** UTF8 encoding +SLIME now uses only UTF8 to encode strings on the wire. Customization +variables like `slime-net-coding-system' or `swank:*coding-system*' are +now useless. + +** Setup recipe +In preparation for a more decentralized approach to SLIME contribs, +the setup recipe has been slightly changed, hopefully in a backwards +compatible way. Calling `slime-setup' is no longer required. Instead, +the `slime-contribs' variable can be customized with a list of +contribs to be loaded when `M-x slime' is first executed. See section +`8.1 Loading Contrib Packages' of the SLIME Manual for more details. + +** Bugfixes and stability improvements since the move to Github + +*** Issue #9: new REPL output respectes existing REPL results or presentations. + +*** Issue #17: TAB no longer freezes the REPL in "read-mode" + +*** Issue #42: compiles on Emacs 24 + +*** Issue #43: `just-one-space' no longer breaks REPL + +*** Issue #34: "Error in timer" error when starting slime on emacs24 + +*** Printing conditions is now a bit safer in the debugger (git:bafeb86) + +*** Fix undo behavior in the REPL (git:af354d7) +Previously, undo would obliterate previous prompts. + +*** Fix REPL type-ahead behaviour when presentations active (git:38a1826) +Input typed before your lisp responds is appended to the result when it arrives. + +*** Fix package and dir synch when no process buffer (git:dc88935) +Sometimes process buffer has been killed, but connection is still active. + +*** M-p on any part of the REPL buffer no longer errors (git:dc88935) + +*** slime-presentations can be enabled in inspector (git:647c3c3, 2f57b34) +Set `slime-inspector-insert-ispec-function' to +`slime-presentation-inspector-insert-ispec' to use them. + +*** M-. on a presentation on the REPL now longer errors +This happened when `slime-presentations' was enabled, either by itself +or by `slime-fancy'. + +*** M-. on the first position of a *slime-apropos* buffer no longer fails. +This happened with the `slime-fancy-inspector.el' contrib. + +*** RET on no part in *inspector* buffer no longer errors + +*** slime-repsentations properly recognized when at very beginning of buffer +Fix by Attila Lendvai + +*** Avoid loading `swank-asdf.lisp' if there's a good chance it will break SWANK +`swank-asdf.lisp' aborts the connection if it finds an old ASDF version. + +*** In ABCL, `slime-describe-function' now works for both macros and functions. + +** SLIME builds on Travis CI +See https://travis-ci.org/slime/slime for the build status and history. + +** Testing framework refactored to use ERT +`def-slime-test' creates regular ERT tests. `define-slime-ert-test' is +a lighter convenience macro which automatically sets some tags for the +new tests. + +** Top-level Makefile +For hackers or users using the latest version, there is now a +top-level Makefile. Use "make help" to learn about targets. + +** Moved to Github +SLIME now lives in Github. The documentation and the README.md file +were updated. HACKING was renamed to CONTRIBUTING.md and updated with +Github specific instructions. + +** Bugfixes and stability improvements +Since the last release and before move to Github, many bugfixes and +other changes were commited, too many to list here. See Changelog for +details. + +* 2.3 (October 2011) + +** REPL no longer loaded by default +SLIME has a REPL which communicates exclusively over SLIME's socket. +This REPL is no longer loaded by default. The default REPL is now the +one by the Lisp implementation in the *inferior-lisp* buffer. The +simplest way to enable the old REPL is: + + (slime-setup '(slime-repl)) + +** Precise source tracking in Clozure CL +Recent versions of the CCL compiler support source-location tracking. +This makes the sldb-show-source command much more useful and M-. works +better too. + +** Environment variables for Lisp process +slime-lisp-implementations can be used to specify a list of strings to +augment the process environment of the Lisp process. E.g.: + + (sbcl-cvs + ("/home/me/sbcl-cvs/src/runtime/sbcl" + "--core" "/home/me/sbcl-cvs/output/sbcl.core") + :env ("SBCL_HOME=/home/me/sbcl-cvs/contrib/")) + +* 2.1 + +** Removed Features +Some of the more esoteric features, like presentations or fuzzy +completion, are no longer enabled by default. A new directory +"contrib/" contains the code for these packages. To use them, you +must make some changes to your ~/.emacs. For details see, section +"Contributed Packages" in the manual. + +** Stepper +Juho Snellman implemented stepping commands for SBCL. + +** Completions +SLIME can now complete keywords and character names (like #\newline). + +* 2.0 (April 2006) + +** In-place macro expansion +Marco Baringer wrote a new minor mode to incrementally expand macros. + +** Improved arglist display +SLIME now recognizes `make-instance' calls and displays the correct +arglist if the classname is present. Similarly, for `defmethod' forms +SLIME displays the arguments of the generic function. + +** Persistent REPL history +SLIME now saves the command history from REPL buffers in a file and +reloads it for newly created REPL buffers. + +** Scieneer Common Lisp +Douglas Crosher added support for Scieneer Common Lisp. + +** SBCL +Various improvements to make SLIME work well with current SBCL versions. + +** Corman Common Lisp +Espen Wiborg added support for Corman Common Lisp. + +** Presentations +A new feature which associates objects in Lisp with their textual +represetation in Emacs. The text is clickable and operations on the +associated object can be invoked from a pop-up menu. + +** Security +SLIME has now a simple authentication mechanism: if the file +~/.slime-secret exists we verify that Emacs and Lisp can access it. +Since both parties have access to the same file system, we assume that +we can trust each other. + +* 1.2 (March 2005) + +** New inspector +The lisp side now returns a specially formated list of "things" to +format which are then passed to emacs and rendered in the inspector +buffer. Things can be either text, recursivly inspectable values, or +functions to call. The new inspector has much better support CLOS +objects and methods. + +** Unicode +It's now possible to send non-ascii characters to Emacs, if the +communication channel is configured properly. See the variable +`slime-net-coding-system'. + +** Arglist lookup while debugging +Previously, arglist lookup was disabled while debugging. This +restriction was removed. + +** Extended tracing command +It's now possible to trace individual a single methods or all methods +of a generic function. Also tracing can be restricted to situations +in which the traced function is called from a specific function. + +** M-x slime-browse-classes +A simple class browser was added. + +** FASL files +The fasl files for different Lisp/OS/hardware combinations are now +placed in different directories. + +** Many other small improvements and bugfixes + +* 1.0 (September 2004) + +** slime-interrupt +The default key binding for slime-interrupt is now C-c C-b. + +** sldb-inspect-condition +In SLDB 'C' is now bound to sldb-inspect-condition. + +** More Menus +SLDB and the REPL have now pull-down menus. + +** Global debugger hook. +A new configurable *global-debugger* to control whether +swank-debugger-hook should be installed globally is available. True by +default. + +** When you call sldb-eval-in-frame with a prefix argument, the result is +now inserted in the REPL buffer. + +** Compile function +For Allegro M-. works now for functions compiled with C-c C-c. + +** slime-edit-definition +Better support for Allegro: works now for different type of +definitions not only. So M-. now works for e.g. classes in Allegro. + +** SBCL 0.8.13 +SBCL 0.8.12 is no longer supported. Support for 0.8.12 was broken for +for some time now. + +* 1.0 beta (August 2004) + +** autodoc global variables +The slime-autodoc-mode will now automatically show the value of a +global variable at point. + +** Customize group +The customize group is expanded and better-organised. + +** slime-interactive-eval +Interactive-eval commands now print their results to the REPL when +given a prefix argument. + +** slime-conservative-indentation +New Elisp variable. Non-nil means that we exclude def* and with-* from +indentation-learning. The default is t. + +** (slime-setup) +New function to streamline setup in ~/.emacs + +** Modeline package +The package name in the modeline is now updated on an idle timer. The +message should now be more meaningful when moving around in files +containing multiple IN-PACKAGE forms. + +** XREF bugfix +The XREF commands did not find symbols in the right package. + +** REPL prompt +The package name in the REPL's prompt is now abbreviated to the last +`.'-delimited token, e.g. MY.COMPANY.PACKAGE would be PACKAGE. This +can be disabled by setting SWANK::*AUTO-ABBREVIATE-DOTTED-PACKAGES* to +NIL. + +** CMUCL source cache +The source cache is now populated on `first-change-hook'. This makes +M-. work accurately in more file modification scenarios. + +** SBCL compiler errors +Detect compiler errors and make some noise. Previously certain +problems (e.g. reader-errors) could slip by quietly. + +* 1.0 alpha (June 2004) + +The first preview release of SLIME. + diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/PROBLEMS b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/PROBLEMS new file mode 100644 index 0000000..704f435 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/PROBLEMS @@ -0,0 +1,94 @@ +Known problems with SLIME -*- outline -*- + +* Common to all backends + +** Caution: network security + +The `M-x slime' command has Lisp listen on a TCP socket and wait for +Emacs to connect, which typically takes on the order of one second. If +someone else were to connect to this socket then they could use the +SLIME protocol to control the Lisp process. + +The listen socket is bound on the loopback interface in all Lisps that +support this. This way remote hosts are unable to connect. + +** READ-CHAR-NO-HANG is broken + +READ-CHAR-NO-HANG doesn't work properly for slime-input-streams. Due +to the way we request input from Emacs it's not possible to repeatedly +poll for input. To get any input you have to call READ-CHAR (or a +function which calls READ-CHAR). + +* Backend-specific problems + +** CMUCL + +The default communication style :SIGIO is reportedly unreliable with +certain libraries (like libSDL) and certain platforms (like Solaris on +Sparc). It generally works very well on x86 so it remains the default. + +** SBCL + +The latest released version of SBCL at the time of packaging should +work. Older or newer SBCLs may or may not work. Do not use +multithreading with unpatched 2.4 Linux kernels. There are also +problems with kernel versions 2.6.5 - 2.6.10. + +The (v)iew-source command in the debugger can only locate exact source +forms for code compiled at (debug 2) or higher. The default level is +lower and SBCL itself is compiled at a lower setting. Thus only +defun-granularity is available with default policies. + +** LispWorks + +On Windows, SLIME hangs when calling foreign functions or certain +other functions. The reason for this problem is unknown. + +We only support latin1 encoding. (Unicode wouldn't be hard to add.) + +** Allegro CL + +Interrupting Allegro with C-c C-b can be slow. This is caused by the +a relatively large process-quantum: 2 seconds by default. Allegro +responds much faster if mp:*default-process-quantum* is set to 0.1. + +** CLISP + +We require version 2.49 or higher. We also require socket support, so +you may have to start CLISP with "clisp -K full". + +Under Windows, interrupting (with C-c C-b) doesn't work. Emacs sends +a SIGINT signal, but the signal is either ignored or CLISP exits +immediately. + +On Windows, CLISP may refuse to parse filenames like +"C:\\DOCUME~1\\johndoe\\LOCALS~1\\Temp\\slime.1424" when we actually +mean C:\Documents and Settings\johndoe\Local Settings\slime.1424. As +a workaround, you could set slime-to-lisp-filename-function to some +function that returns a string that is accepted by CLISP. + +Function arguments and local variables aren't displayed properly in +the backtrace. Changes to CLISP's C code are needed to fix this +problem. Interpreted code is usually easer to debug. + +M-. (find-definition) only works if the fasl file is in the same +directory as the source file. + +The arglist doesn't include the proper names only "fake symbols" like +`arg1'. + +** Armed Bear Common Lisp + +The ABCL support is still new and experimental. + +** Corman Common Lisp + +We require version 2.51 or higher, with several patches (available at +http://www.grumblesmurf.org/lisp/corman-patches). + +The only communication style currently supported is NIL. + +Interrupting (with C-c C-b) doesn't work. + +The tracing, stepping and XREF commands are not implemented along with +some debugger functionality. diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/README.md b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/README.md new file mode 100644 index 0000000..7ef8cd3 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/README.md @@ -0,0 +1,78 @@ +[![Build Status](https://img.shields.io/travis/slime/slime/master.svg)](https://travis-ci.org/slime/slime) [![MELPA](http://melpa.org/packages/slime-badge.svg?)](http://melpa.org/#/slime) [![MELPA Stable](http://stable.melpa.org/packages/slime-badge.svg?)](http://stable.melpa.org/#/slime) + +Overview +-------- + +SLIME is the Superior Lisp Interaction Mode for Emacs. + +SLIME extends Emacs with support for interactive programming in Common +Lisp. The features are centered around slime-mode, an Emacs minor-mode that +complements the standard lisp-mode. While lisp-mode supports editing Lisp +source files, slime-mode adds support for interacting with a running Common +Lisp process for compilation, debugging, documentation lookup, and so on. + +For much more information, consult [the manual][1]. + + +Quick setup instructions +------------------------ + + 1. [Set up the MELPA repository][2], if you haven't already, and install + SLIME using `M-x package-install RET slime RET`. + + 2. Add the following lines to your `~/.emacs` file, filling in in + the appropriate filenames: + + ```el + ;; Set your lisp system and, optionally, some contribs + (setq inferior-lisp-program "/opt/sbcl/bin/sbcl") + (setq slime-contribs '(slime-fancy)) + ``` + + 3. Use `M-x slime` to fire up and connect to an inferior Lisp. SLIME will + now automatically be available in your Lisp source buffers. + +If you'd like to contribute to SLIME, you will want to instead follow +the manual's instructions on [how to install SLIME via Git][7]. + + +Contribs +-------- + +SLIME comes with additional contributed packages or "contribs". +Contribs can be selected via the `slime-contribs` list. + +The most-often used contrib is `slime-fancy`, which primarily installs a +popular set of other contributed packages. It includes a better REPL, and +many more nice features. + + +License +------- + +SLIME is free software. All files, unless explicitly stated otherwise, are +public domain. + + +Contact +------- + +If you have problems, first have a look at the list of +[known issues and workarounds][6]. + +Questions and comments are best directed to the mailing list at +`slime-devel@common-lisp.net`, but you have to [subscribe][3] first. The +mailing list archive is also available on [Gmane][4]. + +See the [CONTRIBUTING.md][5] file for instructions on how to contribute. + + + + +[1]: http://common-lisp.net/project/slime/doc/html/ +[2]: http://melpa.org/#/getting-started +[3]: http://www.common-lisp.net/project/slime/#mailinglist +[4]: http://news.gmane.org/gmane.lisp.slime.devel +[5]: https://github.com/slime/slime/blob/master/CONTRIBUTING.md +[6]: https://github.com/slime/slime/issues?labels=workaround&state=closed +[7]: http://common-lisp.net/project/slime/doc/html/Installation.html#Installing-from-Git diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/Makefile b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/Makefile new file mode 100644 index 0000000..27dcd80 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/Makefile @@ -0,0 +1,92 @@ +### Makefile for contribs +# +# This file is in the public domain. + +EMACS=emacs +LISP=sbcl + +LOAD_PATH=-L . -L .. +CONTRIBS = $(patsubst slime-%.el,%,$(wildcard slime-*.el)) +CONTRIB_TESTS = $(patsubst test/slime-%-tests.el,%,$(wildcard test/slime-*.el)) +SLIME_VERSION=$(shell grep "Version:" ../slime.el | grep -E -o "[0-9.]+$$") + +ELFILES := $(shell find . -type f -iname "*.el") +ELCFILES := $(patsubst %.el,%.elc,$(ELFILES)) + +%.elc: %.el + $(EMACS) -Q $(LOAD_PATH) --batch -f batch-byte-compile $< + +compile: $(ELCFILES) + $(EMACS) -Q --batch $(LOAD_PATH) \ + --eval "(batch-byte-recompile-directory 0)" . + +# ELPA builds for contribs +# +$(CONTRIBS:%=elpa-%): CONTRIB=$(@:elpa-%=%) +$(CONTRIBS:%=elpa-%): CONTRIB_EL=$(CONTRIB:%=slime-%.el) +$(CONTRIBS:%=elpa-%): CONTRIB_CL=$(CONTRIB:%=swank-%.lisp) +$(CONTRIBS:%=elpa-%): CONTRIB_VERSION=$(shell ( \ + grep "Version:" $(CONTRIB_EL) \ + || echo $(SLIME_VERSION) \ + ) | grep -E -o "[0-9.]+$$" ) +$(CONTRIBS:%=elpa-%): PACKAGE=$(CONTRIB:%=slime-%-$(CONTRIB_VERSION)) +$(CONTRIBS:%=elpa-%): PACKAGE_EL=$(CONTRIB:%=slime-%-pkg.el) +$(CONTRIBS:%=elpa-%): ELPA_DIR=elpa/$(PACKAGE) +$(CONTRIBS:%=elpa-%): compile + elpa_dir=$(ELPA_DIR) + mkdir -p $$elpa_dir; \ + emacs --batch $(CONTRIB_EL) \ + --eval "(require 'cl-lib)" \ + --eval "(search-forward \"define-slime-contrib\")" \ + --eval "(up-list -1)" \ + --eval "(pp \ + (pcase (read (point-marker)) \ + (\`(define-slime-contrib ,name ,docstring . ,rest) \ + \`(define-package ,name \"$(CONTRIB_VERSION)\" \ + ,docstring \ + ,(cons '(slime \"$(SLIME_VERSION)\") \ + (cl-loop for form in rest \ + when (eq :slime-dependencies (car form)) \ + append (cl-loop for contrib in (cdr form) \ + if (atom contrib) \ + collect \ + \`(,contrib \"$(SLIME_VERSION)\") \ + else \ + collect contrib))))))))" > \ + $$elpa_dir/$(PACKAGE_EL); \ + cp $(CONTRIB_EL) $$elpa_dir; \ + [ -r $(CONTRIB_CL) ] && cp $(CONTRIB_CL) $$elpa_dir; \ + ls $$elpa_dir + cd elpa && tar cvf $(PACKAGE).tar $(PACKAGE) + rm -rf $(ELPA_DIR) + +elpa-all: $(CONTRIBS:%=elpa-%) + +$(CONTRIB_TESTS:%=check-%): CONTRIB_NAME=$(patsubst check-%,slime-%,$@) +$(CONTRIB_TESTS:%=check-%): SELECTOR=(quote (tag contrib)) +$(CONTRIB_TESTS:%=check-%): compile + $(EMACS) -Q --batch $(LOAD_PATH) -L test \ + --eval "(require (quote slime))" \ + --eval "(slime-setup (quote ($(CONTRIB_NAME))))" \ + --eval "(require \ + (intern \ + (format \"%s-tests\" (quote $(CONTRIB_NAME)))))" \ + --eval '(setq inferior-lisp-program "$(LISP)")' \ + --eval "(slime-batch-test $(SELECTOR))" + +check-all: $(CONTRIB_TESTS:%=check-%) + +check-fancy: compile + $(EMACS) -Q --batch $(LOAD_PATH) -L test \ + --eval "(setq debug-on-error t)" \ + --eval "(require (quote slime))" \ + --eval "(slime-setup (quote (slime-fancy)))" \ + --eval "(mapc (lambda (sym) \ + (require \ + (intern (format \"%s-tests\" sym)) \ + nil t)) \ + (slime-contrib-all-dependencies \ + (quote slime-fancy)))" \ + --eval '(setq inferior-lisp-program "$(LISP)")' \ + --eval '(slime-batch-test (quote (tag contrib)))' + diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/README.md b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/README.md new file mode 100644 index 0000000..94fd02f --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/README.md @@ -0,0 +1,14 @@ +This directory contains source code which may be useful to some Slime +users. `*.el` files are Emacs Lisp source and `*.lisp` files contain +Common Lisp source code. If not otherwise stated in the file itself, +the files are placed in the Public Domain. + +The components in this directory are more or less detached from the +rest of Slime. They are essentially "add-ons". But Slime can also be +used without them. The code is maintained by the respective authors. + +See the top level README.md for how to use packages in this directory. + +Finally, the contrib `slime-fancy` is specially noteworthy, as it +represents a meta-contrib that'll load a bunch of commonly used +contribs. Look into `slime-fancy.el` to find out which. diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/bridge.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/bridge.el new file mode 100644 index 0000000..5bf8779 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/bridge.el @@ -0,0 +1,472 @@ +;;; -*-Emacs-Lisp-*- +;;;%Header +;;; Bridge process filter, V1.0 +;;; Copyright (C) 1991 Chris McConnell, ccm@cs.cmu.edu +;;; +;;; Send mail to ilisp@cons.org if you have problems. +;;; +;;; Send mail to majordomo@cons.org if you want to be on the +;;; ilisp mailing list. + +;;; This file is part of GNU Emacs. + +;;; GNU Emacs is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY. No author or distributor +;;; accepts responsibility to anyone for the consequences of using it +;;; or for whether it serves any particular purpose or works at all, +;;; unless he says so in writing. Refer to the GNU Emacs General Public +;;; License for full details. + +;;; Everyone is granted permission to copy, modify and redistribute +;;; GNU Emacs, but only under the conditions described in the +;;; GNU Emacs General Public License. A copy of this license is +;;; supposed to have been given to you along with GNU Emacs so you +;;; can know your rights and responsibilities. It should be in a +;;; file named COPYING. Among other things, the copyright notice +;;; and this notice must be preserved on all copies. + +;;; Send any bugs or comments. Thanks to Todd Kaufmann for rewriting +;;; the process filter for continuous handlers. + +;;; USAGE: M-x install-bridge will add a process output filter to the +;;; current buffer. Any output that the process does between +;;; bridge-start-regexp and bridge-end-regexp will be bundled up and +;;; passed to the first handler on bridge-handlers that matches the +;;; output using string-match. If bridge-prompt-regexp shows up +;;; before bridge-end-regexp, the bridge will be cancelled. If no +;;; handler matches the output, the first symbol in the output is +;;; assumed to be a buffer name and the rest of the output will be +;;; sent to that buffer's process. This can be used to communicate +;;; between processes or to set up two way interactions between Emacs +;;; and an inferior process. + +;;; You can write handlers that process the output in special ways. +;;; See bridge-send-handler for the default handler. The command +;;; hand-bridge is useful for testing. Keep in mind that all +;;; variables are buffer local. + +;;; YOUR .EMACS FILE: +;;; +;;; ;;; Set up load path to include bridge +;;; (setq load-path (cons "/bridge-directory/" load-path)) +;;; (autoload 'install-bridge "bridge" "Install a process bridge." t) +;;; (setq bridge-hook +;;; '(lambda () +;;; ;; Example options +;;; (setq bridge-source-insert nil) ;Don't insert in source buffer +;;; (setq bridge-destination-insert nil) ;Don't insert in dest buffer +;;; ;; Handle copy-it messages yourself +;;; (setq bridge-handlers +;;; '(("copy-it" . my-copy-handler))))) + +;;; EXAMPLE: +;;; # This pipes stdin to the named buffer in a Unix shell +;;; alias devgnu '(echo -n "\!* "; cat -; echo -n "")' +;;; +;;; ls | devgnu *scratch* + +(eval-when-compile + (require 'cl)) + +;;;%Parameters +(defvar bridge-hook nil + "Hook called when a bridge is installed by install-hook.") + +(defvar bridge-start-regexp "" + "*Regular expression to match the start of a process bridge in +process output. It should be followed by a buffer name, the data to +be sent and a bridge-end-regexp.") + +(defvar bridge-end-regexp "" + "*Regular expression to match the end of a process bridge in process +output.") + +(defvar bridge-prompt-regexp nil + "*Regular expression for detecting a prompt. If there is a +comint-prompt-regexp, it will be initialized to that. A prompt before +a bridge-end-regexp will stop the process bridge.") + +(defvar bridge-handlers nil + "Alist of (regexp . handler) for handling process output delimited +by bridge-start-regexp and bridge-end-regexp. The first entry on the +list whose regexp matches the output will be called on the process and +the delimited output.") + +(defvar bridge-source-insert t + "*T to insert bridge input in the source buffer minus delimiters.") + +(defvar bridge-destination-insert t + "*T for bridge-send-handler to insert bridge input into the +destination buffer minus delimiters.") + +(defvar bridge-chunk-size 512 + "*Long inputs send to comint processes are broken up into chunks of +this size. If your process is choking on big inputs, try lowering the +value.") + +;;;%Internal variables +(defvar bridge-old-filter nil + "Old filter for a bridged process buffer.") + +(defvar bridge-string nil + "The current output in the process bridge.") + +(defvar bridge-in-progress nil + "The current handler function, if any, that bridge passes strings on to, +or nil if none.") + +(defvar bridge-leftovers nil + "Because of chunking you might get an incomplete bridge signal - start but the end is in the next packet. Save the overhanging text here.") + +(defvar bridge-send-to-buffer nil + "The buffer that the default bridge-handler (bridge-send-handler) is +currently sending to, or nil if it hasn't started yet. Your handler +function can use this variable also.") + +(defvar bridge-last-failure () + "Last thing that broke the bridge handler. First item is function call +(eval'able); last item is error condition which resulted. This is provided +to help handler-writers in their debugging.") + +(defvar bridge-insert-function nil + "If non-nil use this instead of `bridge-insert'") + +;;;%Utilities +(defun bridge-insert (output &optional _dummy) + "Insert process OUTPUT into the current buffer." + (if bridge-insert-function + (funcall bridge-insert-function output) + (if output + (let* ((buffer (current-buffer)) + (process (get-buffer-process buffer)) + (mark (process-mark process)) + (window (selected-window)) + (at-end nil)) + (if (eq (window-buffer window) buffer) + (setq at-end (= (point) mark)) + (setq window (get-buffer-window buffer))) + (save-excursion + (goto-char mark) + (insert output) + (set-marker mark (point))) + (if window + (progn + (if at-end (goto-char mark)) + (if (not (pos-visible-in-window-p (point) window)) + (let ((original (selected-window))) + (save-excursion + (select-window window) + (recenter '(center)) + (select-window original)))))))))) + +;;; +;(defun bridge-send-string (process string) +; "Send PROCESS the contents of STRING as input. +;This is equivalent to process-send-string, except that long input strings +;are broken up into chunks of size comint-input-chunk-size. Processes +;are given a chance to output between chunks. This can help prevent processes +;from hanging when you send them long inputs on some OS's." +; (let* ((len (length string)) +; (i (min len bridge-chunk-size))) +; (process-send-string process (substring string 0 i)) +; (while (< i len) +; (let ((next-i (+ i bridge-chunk-size))) +; (accept-process-output) +; (process-send-string process (substring string i (min len next-i))) +; (setq i next-i))))) + +;;; +(defun bridge-call-handler (handler proc string) + "Funcall HANDLER on PROC, STRING carefully. Error is caught if happens, +and user is signaled. State is put in bridge-last-failure. Returns t if +handler executed without error." + (let ((inhibit-quit nil) + (failed nil)) + (condition-case err + (funcall handler proc string) + (error + (ding) + (setq failed t) + (message "bridge-handler \"%s\" failed %s (see bridge-last-failure)" + handler err) + (setq bridge-last-failure + `((funcall ',handler ',proc ,string) + "Caused: " + ,err)))) + (not failed))) + +;;;%Handlers +(defun bridge-send-handler (process input) + "Send PROCESS INPUT to the buffer name found at the start of the +input. The input after the buffer name is sent to the buffer's +process if it has one. If bridge-destination-insert is T, the input +will be inserted into the buffer. If it does not have a process, it +will be inserted at the end of the buffer." + (if (null input) + (setq bridge-send-to-buffer nil) ; end of bridge + (let (buffer-and-start buffer-name dest to) + ;; if this is first time, get the buffer out of the first line + (cond ((not bridge-send-to-buffer) + (setq buffer-and-start (read-from-string input) + buffer-name (format "%s" (car (read-from-string input))) + dest (get-buffer buffer-name) + to (get-buffer-process dest) + input (substring input (cdr buffer-and-start))) + (setq bridge-send-to-buffer dest)) + (t + (setq buffer-name bridge-send-to-buffer + dest (get-buffer buffer-name) + to (get-buffer-process dest) + ))) + (if dest + (let ((buffer (current-buffer))) + (if bridge-destination-insert + (unwind-protect + (progn + (set-buffer dest) + (if to + (bridge-insert process input) + (goto-char (point-max)) + (insert input))) + (set-buffer buffer))) + (if to + ;; (bridge-send-string to input) + (process-send-string to input) + )) + (error "%s is not a buffer" buffer-name))))) + +;;;%Filter +(defun bridge-filter (process output) + "Given PROCESS and some OUTPUT, check for the presence of +bridge-start-regexp. Everything prior to this will be passed to the +normal filter function or inserted in the buffer if it is nil. The +output up to bridge-end-regexp will be sent to the first handler on +bridge-handlers that matches the string. If no handlers match, the +input will be sent to bridge-send-handler. If bridge-prompt-regexp is +encountered before the bridge-end-regexp, the bridge will be cancelled." + (let ((inhibit-quit t) + (match-data (match-data)) + (buffer (current-buffer)) + (process-buffer (process-buffer process)) + (case-fold-search t) + (start 0) (end 0) + function + b-start b-start-end b-end) + (set-buffer process-buffer) ;; access locals + + ;; Handle bridge messages that straddle a packet by prepending + ;; them to this packet. + + (when bridge-leftovers + (setq output (concat bridge-leftovers output)) + (setq bridge-leftovers nil)) + + (setq function bridge-in-progress) + + ;; How it works: + ;; + ;; start, end delimit the part of string we are interested in; + ;; initially both 0; after an iteration we move them to next string. + + ;; b-start, b-end delimit part of string to bridge (possibly whole string); + ;; this will be string between corresponding regexps. + + ;; There are two main cases when we come into loop: + + ;; bridge in progress + ;;0 setq b-start = start + ;;1 setq b-end (or end-pattern end) + ;;4 process string + ;;5 remove handler if end found + + ;; no bridge in progress + ;;0 setq b-start if see start-pattern + ;;1 setq b-end if bstart to (or end-pattern end) + ;;2 send (substring start b-start) to normal place + ;;3 find handler (in b-start, b-end) if not set + ;;4 process string + ;;5 remove handler if end found + + ;; equivalent sections have the same numbers here; + ;; we fold them together in this code. + + (block bridge-filter + (unwind-protect + (while (< end (length output)) + + ;;0 setq b-start if find + (setq b-start + (cond (bridge-in-progress + (setq b-start-end start) + start) + ((string-match bridge-start-regexp output start) + (setq b-start-end (match-end 0)) + (match-beginning 0)) + (t nil))) + ;;1 setq b-end + (setq b-end + (if b-start + (let ((end-seen (string-match bridge-end-regexp + output b-start-end))) + (if end-seen (setq end (match-end 0))) + + end-seen))) + + ;; Detect and save partial bridge messages + (when (and b-start b-start-end (not b-end)) + (setq bridge-leftovers (substring output b-start)) + ) + + (if (and b-start (not b-end)) + (setq end b-start) + (if (not b-end) + (setq end (length output)))) + + ;;1.5 - if see prompt before end, remove current + (if (and b-start b-end) + (let ((prompt (string-match bridge-prompt-regexp + output b-start-end))) + (if (and prompt (<= (match-end 0) b-end)) + (setq b-start nil ; b-start-end start + b-end start + end (match-end 0) + bridge-in-progress nil + )))) + + ;;2 send (substring start b-start) to old filter, if any + (when (not (equal start (or b-start end))) ; don't bother on empty string + (let ((pass-on (substring output start (or b-start end)))) + (if bridge-old-filter + (let ((old bridge-old-filter)) + (store-match-data match-data) + (funcall old process pass-on) + ;; if filter changed, re-install ourselves + (let ((new (process-filter process))) + (if (not (eq new 'bridge-filter)) + (progn (setq bridge-old-filter new) + (set-process-filter process 'bridge-filter))))) + (set-buffer process-buffer) + (bridge-insert pass-on)))) + + (if (and b-start-end (not b-end)) + (return-from bridge-filter t) ; when last bit has prematurely ending message, exit early. + (progn + ;;3 find handler (in b-start, b-end) if none current + (if (and b-start (not bridge-in-progress)) + (let ((handlers bridge-handlers)) + (while (and handlers (not function)) + (let* ((handler (car handlers)) + (m (string-match (car handler) output b-start-end))) + (if (and m (< m b-end)) + (setq function (cdr handler)) + (setq handlers (cdr handlers))))) + ;; Set default handler if none + (if (null function) + (setq function 'bridge-send-handler)) + (setq bridge-in-progress function))) + ;;4 process strin + (if function + (let ((ok t)) + (if (/= b-start-end b-end) + (let ((send (substring output b-start-end b-end))) + ;; also, insert the stuff in buffer between + ;; iff bridge-source-insert. + (if bridge-source-insert (bridge-insert send)) + ;; call handler on string + (setq ok (bridge-call-handler function process send)))) + ;;5 remove handler if end found + ;; if function removed then tell it that's all + (if (or (not ok) (/= b-end end)) ;; saw end before end-of-string + (progn + (bridge-call-handler function process nil) + ;; have to remove function too for next time around + (setq function nil + bridge-in-progress nil) + )) + )) + + ;; continue looping, in case there's more string + (setq start end)) + )) + ;; protected forms: restore buffer, match-data + (set-buffer buffer) + (store-match-data match-data) + )))) + + +;;;%Interface +(defun install-bridge () + "Set up a process bridge in the current buffer." + (interactive) + (if (not (get-buffer-process (current-buffer))) + (error "%s does not have a process" (buffer-name (current-buffer))) + (make-local-variable 'bridge-start-regexp) + (make-local-variable 'bridge-end-regexp) + (make-local-variable 'bridge-prompt-regexp) + (make-local-variable 'bridge-handlers) + (make-local-variable 'bridge-source-insert) + (make-local-variable 'bridge-destination-insert) + (make-local-variable 'bridge-chunk-size) + (make-local-variable 'bridge-old-filter) + (make-local-variable 'bridge-string) + (make-local-variable 'bridge-in-progress) + (make-local-variable 'bridge-send-to-buffer) + (make-local-variable 'bridge-leftovers) + (setq bridge-string nil bridge-in-progress nil + bridge-send-to-buffer nil) + (if (boundp 'comint-prompt-regexp) + (setq bridge-prompt-regexp comint-prompt-regexp)) + (let ((process (get-buffer-process (current-buffer)))) + (if process + (if (not (eq (process-filter process) 'bridge-filter)) + (progn + (setq bridge-old-filter (process-filter process)) + (set-process-filter process 'bridge-filter))) + (error "%s does not have a process" + (buffer-name (current-buffer))))) + (run-hooks 'bridge-hook) + (message "Process bridge is installed"))) + +;;; +(defun reset-bridge () + "Must be called from the process's buffer. Removes any active bridge." + (interactive) + ;; for when things get wedged + (if bridge-in-progress + (unwind-protect + (funcall bridge-in-progress (get-buffer-process + (current-buffer)) + nil) + (setq bridge-in-progress nil)) + (message "No bridge in progress."))) + +;;; +(defun remove-bridge () + "Remove bridge from the current buffer." + (interactive) + (let ((process (get-buffer-process (current-buffer)))) + (if (or (not process) (not (eq (process-filter process) 'bridge-filter))) + (error "%s has no bridge" (buffer-name (current-buffer))) + ;; remove any bridge-in-progress + (reset-bridge) + (set-process-filter process bridge-old-filter) + (funcall bridge-old-filter process bridge-string) + (message "Process bridge is removed.")))) + +;;;% Utility for testing +(defun hand-bridge (start end) + "With point at bridge-start, sends bridge-start + string + +bridge-end to bridge-filter. With prefix, use current region to send." + (interactive "r") + (let ((p0 (if current-prefix-arg (min start end) + (if (looking-at bridge-start-regexp) (point) + (error "Not looking at bridge-start-regexp")))) + (p1 (if current-prefix-arg (max start end) + (if (re-search-forward bridge-end-regexp nil t) + (point) (error "Didn't see bridge-end-regexp"))))) + + (bridge-filter (get-buffer-process (current-buffer)) + (buffer-substring-no-properties p0 p1)) + )) + +(provide 'bridge) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/inferior-slime.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/inferior-slime.el new file mode 100644 index 0000000..b176098 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/inferior-slime.el @@ -0,0 +1,133 @@ +;;; inferior-slime.el --- Minor mode with Slime keys for comint buffers +;; +;; Author: Luke Gorrie +;; License: GNU GPL (same license as Emacs) +;; +;;; Installation: +;; +;; Add something like this to your .emacs: +;; +;; (add-to-list 'load-path "") +;; (add-hook 'slime-load-hook (lambda () (require 'inferior-slime))) +;; (add-hook 'inferior-lisp-mode-hook (lambda () (inferior-slime-mode 1))) +(require 'slime) +(require 'cl-lib) + +(define-minor-mode inferior-slime-mode + "\\\ +Inferior SLIME mode: The Inferior Superior Lisp Mode for Emacs. + +This mode is intended for use with `inferior-lisp-mode'. It provides a +subset of the bindings from `slime-mode'. + +\\{inferior-slime-mode-map}" + :keymap + ;; Fake binding to coax `define-minor-mode' to create the keymap + '((" " 'undefined)) + + (slime-setup-completion) + (setq-local tab-always-indent 'complete)) + +(defun inferior-slime-return () + "Handle the return key in the inferior-lisp buffer. +The current input should only be sent if a whole expression has been +entered, i.e. the parenthesis are matched. + +A prefix argument disables this behaviour." + (interactive) + (if (or current-prefix-arg (inferior-slime-input-complete-p)) + (comint-send-input) + (insert "\n") + (inferior-slime-indent-line))) + +(defun inferior-slime-indent-line () + "Indent the current line, ignoring everything before the prompt." + (interactive) + (save-restriction + (let ((indent-start + (save-excursion + (goto-char (process-mark (get-buffer-process (current-buffer)))) + (let ((inhibit-field-text-motion t)) + (beginning-of-line 1)) + (point)))) + (narrow-to-region indent-start (point-max))) + (lisp-indent-line))) + +(defun inferior-slime-input-complete-p () + "Return true if the input is complete in the inferior lisp buffer." + (slime-input-complete-p (process-mark (get-buffer-process (current-buffer))) + (point-max))) + +(defun inferior-slime-closing-return () + "Send the current expression to Lisp after closing any open lists." + (interactive) + (goto-char (point-max)) + (save-restriction + (narrow-to-region (process-mark (get-buffer-process (current-buffer))) + (point-max)) + (while (ignore-errors (save-excursion (backward-up-list 1) t)) + (insert ")"))) + (comint-send-input)) + +(defun inferior-slime-change-directory (directory) + "Set default-directory in the *inferior-lisp* buffer to DIRECTORY." + (let* ((proc (slime-process)) + (buffer (and proc (process-buffer proc)))) + (when buffer + (with-current-buffer buffer + (cd-absolute directory))))) + +(defun inferior-slime-init-keymap () + (let ((map inferior-slime-mode-map)) + (set-keymap-parent map slime-parent-map) + (slime-define-keys map + ([return] 'inferior-slime-return) + ([(control return)] 'inferior-slime-closing-return) + ([(meta control ?m)] 'inferior-slime-closing-return) + ;;("\t" 'slime-indent-and-complete-symbol) + (" " 'slime-space)))) + +(inferior-slime-init-keymap) + +(defun inferior-slime-hook-function () + (inferior-slime-mode 1)) + +(defun inferior-slime-switch-to-repl-buffer () + (switch-to-buffer (process-buffer (slime-inferior-process)))) + +(defun inferior-slime-show-transcript (string) + (remove-hook 'comint-output-filter-functions + 'inferior-slime-show-transcript t) + (with-current-buffer (process-buffer (slime-inferior-process)) + (let ((window (display-buffer (current-buffer) t))) + (set-window-point window (point-max))))) + +(defun inferior-slime-start-transcript () + (let ((proc (slime-inferior-process))) + (when proc + (with-current-buffer (process-buffer proc) + (add-hook 'comint-output-filter-functions + 'inferior-slime-show-transcript + nil t))))) + +(defun inferior-slime-stop-transcript () + (let ((proc (slime-inferior-process))) + (when proc + (with-current-buffer (process-buffer (slime-inferior-process)) + (run-with-timer 0.2 nil + (lambda (buffer) + (with-current-buffer buffer + (remove-hook 'comint-output-filter-functions + 'inferior-slime-show-transcript t))) + (current-buffer)))))) + +(defun inferior-slime-init () + (add-hook 'slime-inferior-process-start-hook 'inferior-slime-hook-function) + (add-hook 'slime-change-directory-hooks 'inferior-slime-change-directory) + (add-hook 'slime-transcript-start-hook 'inferior-slime-start-transcript) + (add-hook 'slime-transcript-stop-hook 'inferior-slime-stop-transcript) + (def-slime-selector-method ?r + "SLIME Read-Eval-Print-Loop." + (process-buffer (slime-inferior-process)))) + +(provide 'inferior-slime) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-asdf.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-asdf.el new file mode 100644 index 0000000..fa4b176 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-asdf.el @@ -0,0 +1,313 @@ +(require 'slime) +(require 'cl-lib) +(require 'grep) + +(define-slime-contrib slime-asdf + "ASDF support." + (:authors "Daniel Barlow " + "Marco Baringer " + "Edi Weitz " + "Stas Boukarev " + "Tobias C Rittweiler ") + (:license "GPL") + (:slime-dependencies slime-repl) + (:swank-dependencies swank-asdf) + (:on-load + (add-to-list 'slime-edit-uses-xrefs :depends-on t) + (define-key slime-who-map [?d] 'slime-who-depends-on))) + +;;; NOTE: `system-name' is a predefined variable in Emacs. Try to +;;; avoid it as local variable name. + +;;; Utilities + +(defgroup slime-asdf nil + "ASDF support for Slime." + :prefix "slime-asdf-" + :group 'slime) + +(defvar slime-system-history nil + "History list for ASDF system names.") + +(defun slime-read-system-name (&optional prompt + default-value + determine-default-accurately) + "Read a system name from the minibuffer, prompting with PROMPT. +If no `default-value' is given, one is tried to be determined: if +`determine-default-accurately' is true, by an RPC request which +grovels through all defined systems; if it's not true, by looking +in the directory of the current buffer." + (let* ((completion-ignore-case nil) + (prompt (or prompt "System")) + (system-names (slime-eval `(swank:list-asdf-systems))) + (default-value + (or default-value + (if determine-default-accurately + (slime-determine-asdf-system (buffer-file-name) + (slime-current-package)) + (slime-find-asd-file (or default-directory + (buffer-file-name)) + system-names)))) + (prompt (concat prompt (if default-value + (format " (default `%s'): " default-value) + ": ")))) + (completing-read prompt (slime-bogus-completion-alist system-names) + nil nil nil + 'slime-system-history default-value))) + + + +(defun slime-find-asd-file (directory system-names) + "Tries to find an ASDF system definition file in the +`directory' and returns it if it's in `system-names'." + (let ((asd-files + (directory-files (file-name-directory directory) nil "\.asd$"))) + (cl-loop for system in asd-files + for candidate = (file-name-sans-extension system) + when (cl-find candidate system-names :test #'string-equal) + do (cl-return candidate)))) + +(defun slime-determine-asdf-system (filename buffer-package) + "Try to determine the asdf system that `filename' belongs to." + (slime-eval + `(swank:asdf-determine-system ,(and filename + (slime-to-lisp-filename filename)) + ,buffer-package))) + +(defun slime-who-depends-on-rpc (system) + (slime-eval `(swank:who-depends-on ,system))) + +(defcustom slime-asdf-collect-notes t + "Collect and display notes produced by the compiler. + +See also `slime-highlight-compiler-notes' and +`slime-compilation-finished-hook'." + :group 'slime-asdf) + +(defun slime-asdf-operation-finished-function (system) + (if slime-asdf-collect-notes + #'slime-compilation-finished + (slime-curry (lambda (system result) + (let (slime-highlight-compiler-notes + slime-compilation-finished-hook) + (slime-compilation-finished result))) + system))) + +(defun slime-oos (system operation &rest keyword-args) + "Operate On System." + (slime-save-some-lisp-buffers) + (slime-display-output-buffer) + (message "Performing ASDF %S%s on system %S" + operation (if keyword-args (format " %S" keyword-args) "") + system) + (slime-repl-shortcut-eval-async + `(swank:operate-on-system-for-emacs ,system ',operation ,@keyword-args) + (slime-asdf-operation-finished-function system))) + + +;;; Interactive functions + +(defun slime-load-system (&optional system) + "Compile and load an ASDF system. + +Default system name is taken from first file matching *.asd in current +buffer's working directory" + (interactive (list (slime-read-system-name))) + (slime-oos system 'load-op)) + +(defun slime-open-system (name &optional load interactive) + "Open all files in an ASDF system." + (interactive (list (slime-read-system-name) nil t)) + (when (or load + (and interactive + (not (slime-eval `(swank:asdf-system-loaded-p ,name))) + (y-or-n-p "Load it? "))) + (slime-load-system name)) + (slime-eval-async + `(swank:asdf-system-files ,name) + (lambda (files) + (when files + (let ((files (mapcar 'slime-from-lisp-filename + (nreverse files)))) + (find-file-other-window (car files)) + (mapc 'find-file (cdr files))))))) + +(defun slime-browse-system (name) + "Browse files in an ASDF system using Dired." + (interactive (list (slime-read-system-name))) + (slime-eval-async `(swank:asdf-system-directory ,name) + (lambda (directory) + (when directory + (dired (slime-from-lisp-filename directory)))))) + +(if (fboundp 'rgrep) + (defun slime-rgrep-system (sys-name regexp) + "Run `rgrep' on the base directory of an ASDF system." + (interactive (progn (grep-compute-defaults) + (list (slime-read-system-name nil nil t) + (grep-read-regexp)))) + (rgrep regexp "*.lisp" + (slime-from-lisp-filename + (slime-eval `(swank:asdf-system-directory ,sys-name))))) + (defun slime-rgrep-system () + (interactive) + (error "This command is only supported on GNU Emacs >21.x."))) + +(if (boundp 'multi-isearch-next-buffer-function) + (defun slime-isearch-system (sys-name) + "Run `isearch-forward' on the files of an ASDF system." + (interactive (list (slime-read-system-name nil nil t))) + (let* ((files (mapcar 'slime-from-lisp-filename + (slime-eval `(swank:asdf-system-files ,sys-name)))) + (multi-isearch-next-buffer-function + (lexical-let* + ((buffers-forward (mapcar #'find-file-noselect files)) + (buffers-backward (reverse buffers-forward))) + #'(lambda (current-buffer wrap) + ;; Contrarily to the docstring of + ;; `multi-isearch-next-buffer-function', the first + ;; arg is not necessarily a buffer. Report sent + ;; upstream. (2009-11-17) + (setq current-buffer (or current-buffer (current-buffer))) + (let* ((buffers (if isearch-forward + buffers-forward + buffers-backward))) + (if wrap + (car buffers) + (second (memq current-buffer buffers)))))))) + (isearch-forward))) + (defun slime-isearch-system () + (interactive) + (error "This command is only supported on GNU Emacs >23.1.x."))) + +(defun slime-read-query-replace-args (format-string &rest format-args) + (let* ((minibuffer-setup-hook (slime-minibuffer-setup-hook)) + (minibuffer-local-map slime-minibuffer-map) + (common (query-replace-read-args (apply #'format format-string + format-args) + t t))) + (list (nth 0 common) (nth 1 common) (nth 2 common)))) + +(defun slime-query-replace-system (name from to &optional delimited) + "Run `query-replace' on an ASDF system." + (interactive (let ((system (slime-read-system-name nil nil t))) + (cons system (slime-read-query-replace-args + "Query replace throughout `%s'" system)))) + (condition-case c + ;; `tags-query-replace' actually uses `query-replace-regexp' + ;; internally. + (tags-query-replace (regexp-quote from) to delimited + '(mapcar 'slime-from-lisp-filename + (slime-eval `(swank:asdf-system-files ,name)))) + (error + ;; Kludge: `tags-query-replace' does not actually return but + ;; signals an unnamed error with the below error + ;; message. (<=23.1.2, at least.) + (unless (string-equal (error-message-string c) "All files processed") + (signal (car c) (cdr c))) ; resignal + t))) + +(defun slime-query-replace-system-and-dependents + (name from to &optional delimited) + "Run `query-replace' on an ASDF system and all the systems +depending on it." + (interactive (let ((system (slime-read-system-name nil nil t))) + (cons system (slime-read-query-replace-args + "Query replace throughout `%s'+dependencies" + system)))) + (slime-query-replace-system name from to delimited) + (dolist (dep (slime-who-depends-on-rpc name)) + (when (y-or-n-p (format "Descend into system `%s'? " dep)) + (slime-query-replace-system dep from to delimited)))) + +(defun slime-delete-system-fasls (name) + "Delete FASLs produced by compiling a system." + (interactive (list (slime-read-system-name))) + (slime-repl-shortcut-eval-async + `(swank:delete-system-fasls ,name) + 'message)) + +(defun slime-reload-system (system) + "Reload an ASDF system without reloading its dependencies." + (interactive (list (slime-read-system-name))) + (slime-save-some-lisp-buffers) + (slime-display-output-buffer) + (message "Performing ASDF LOAD-OP on system %S" system) + (slime-repl-shortcut-eval-async + `(swank:reload-system ,system) + (slime-asdf-operation-finished-function system))) + +(defun slime-who-depends-on (system-name) + (interactive (list (slime-read-system-name))) + (slime-xref :depends-on system-name)) + +(defun slime-save-system (system) + "Save files belonging to an ASDF system." + (interactive (list (slime-read-system-name))) + (slime-eval-async + `(swank:asdf-system-files ,system) + (lambda (files) + (dolist (file files) + (let ((buffer (get-file-buffer (slime-from-lisp-filename file)))) + (when buffer + (with-current-buffer buffer + (save-buffer buffer))))) + (message "Done.")))) + + +;;; REPL shortcuts + +(defslime-repl-shortcut slime-repl-load/force-system ("force-load-system") + (:handler (lambda () + (interactive) + (slime-oos (slime-read-system-name) 'load-op :force t))) + (:one-liner "Recompile and load an ASDF system.")) + +(defslime-repl-shortcut slime-repl-load-system ("load-system") + (:handler (lambda () + (interactive) + (slime-oos (slime-read-system-name) 'load-op))) + (:one-liner "Compile (as needed) and load an ASDF system.")) + +(defslime-repl-shortcut slime-repl-test/force-system ("force-test-system") + (:handler (lambda () + (interactive) + (slime-oos (slime-read-system-name) 'test-op :force t))) + (:one-liner "Recompile and test an ASDF system.")) + +(defslime-repl-shortcut slime-repl-test-system ("test-system") + (:handler (lambda () + (interactive) + (slime-oos (slime-read-system-name) 'test-op))) + (:one-liner "Compile (as needed) and test an ASDF system.")) + +(defslime-repl-shortcut slime-repl-compile-system ("compile-system") + (:handler (lambda () + (interactive) + (slime-oos (slime-read-system-name) 'compile-op))) + (:one-liner "Compile (but not load) an ASDF system.")) + +(defslime-repl-shortcut slime-repl-compile/force-system + ("force-compile-system") + (:handler (lambda () + (interactive) + (slime-oos (slime-read-system-name) 'compile-op :force t))) + (:one-liner "Recompile (but not completely load) an ASDF system.")) + +(defslime-repl-shortcut slime-repl-open-system ("open-system") + (:handler 'slime-open-system) + (:one-liner "Open all files in an ASDF system.")) + +(defslime-repl-shortcut slime-repl-browse-system ("browse-system") + (:handler 'slime-browse-system) + (:one-liner "Browse files in an ASDF system using Dired.")) + +(defslime-repl-shortcut slime-repl-delete-system-fasls ("delete-system-fasls") + (:handler 'slime-delete-system-fasls) + (:one-liner "Delete FASLs of an ASDF system.")) + +(defslime-repl-shortcut slime-repl-reload-system ("reload-system") + (:handler 'slime-reload-system) + (:one-liner "Recompile and load an ASDF system.")) + +(provide 'slime-asdf) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-autodoc.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-autodoc.el new file mode 100644 index 0000000..1ea629e --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-autodoc.el @@ -0,0 +1,216 @@ +(require 'slime) +(require 'eldoc) +(require 'cl-lib) +(require 'slime-parse) + +(define-slime-contrib slime-autodoc + "Show fancy arglist in echo area." + (:license "GPL") + (:authors "Luke Gorrie " + "Lawrence Mitchell " + "Matthias Koeppe " + "Tobias C. Rittweiler ") + (:slime-dependencies slime-parse) + (:swank-dependencies swank-arglists) + (:on-load (slime-autodoc--enable)) + (:on-unload (slime-autodoc--disable))) + +(defcustom slime-autodoc-accuracy-depth 10 + "Number of paren levels that autodoc takes into account for + context-sensitive arglist display (local functions. etc)" + :type 'integer + :group 'slime-ui) + +;;;###autoload +(defcustom slime-autodoc-mode-string (purecopy " adoc") + "String to display in mode line when Autodoc Mode is enabled; nil for none." + :type '(choice string (const :tag "None" nil)) + :group 'slime-ui) + + + +(defun slime-arglist (name) + "Show the argument list for NAME." + (interactive (list (slime-read-symbol-name "Arglist of: " t))) + (let ((arglist (slime-retrieve-arglist name))) + (if (eq arglist :not-available) + (error "Arglist not available") + (message "%s" (slime-autodoc--fontify arglist))))) + +;; used also in slime-c-p-c.el. +(defun slime-retrieve-arglist (name) + (let ((name (cl-etypecase name + (string name) + (symbol (symbol-name name))))) + (car (slime-eval `(swank:autodoc '(,name ,slime-cursor-marker)))))) + +(defun slime-autodoc-manually () + "Like autodoc informtion forcing multiline display." + (interactive) + (let ((doc (slime-autodoc t))) + (cond (doc (eldoc-message doc)) + (t (eldoc-message nil))))) + +;; Must call eldoc-add-command otherwise (eldoc-display-message-p) +;; returns nil and eldoc clears the echo area instead. +(eldoc-add-command 'slime-autodoc-manually) + +(defun slime-autodoc-space (n) + "Like `slime-space' but nicer." + (interactive "p") + (self-insert-command n) + (let ((doc (slime-autodoc))) + (when doc + (eldoc-message doc)))) + +(eldoc-add-command 'slime-autodoc-space) + + +;;;; Autodoc cache + +(defvar slime-autodoc--cache-last-context nil) +(defvar slime-autodoc--cache-last-autodoc nil) + +(defun slime-autodoc--cache-get (context) + "Return the cached autodoc documentation for `context', or nil." + (and (equal context slime-autodoc--cache-last-context) + slime-autodoc--cache-last-autodoc)) + +(defun slime-autodoc--cache-put (context autodoc) + "Update the autodoc cache for CONTEXT with AUTODOC." + (setq slime-autodoc--cache-last-context context) + (setq slime-autodoc--cache-last-autodoc autodoc)) + + +;;;; Formatting autodoc + +(defsubst slime-autodoc--canonicalize-whitespace (string) + (replace-regexp-in-string "[ \n\t]+" " " string)) + +(defun slime-autodoc--format (doc multilinep) + (let ((doc (slime-autodoc--fontify doc))) + (cond (multilinep doc) + (t (slime-oneliner (slime-autodoc--canonicalize-whitespace doc)))))) + +(defun slime-autodoc--fontify (string) + "Fontify STRING as `font-lock-mode' does in Lisp mode." + (with-current-buffer (get-buffer-create (slime-buffer-name :fontify 'hidden)) + (erase-buffer) + (unless (eq major-mode 'lisp-mode) + ;; Just calling (lisp-mode) will turn slime-mode on in that buffer, + ;; which may interfere with this function + (setq major-mode 'lisp-mode) + (lisp-mode-variables t)) + (insert string) + (let ((font-lock-verbose nil)) + (font-lock-fontify-buffer)) + (goto-char (point-min)) + (when (re-search-forward "===> \\(\\(.\\|\n\\)*\\) <===" nil t) + (let ((highlight (match-string 1))) + ;; Can't use (replace-match highlight) here -- broken in Emacs 21 + (delete-region (match-beginning 0) (match-end 0)) + (slime-insert-propertized '(face eldoc-highlight-function-argument) highlight))) + (buffer-substring (point-min) (point-max)))) + +(define-obsolete-function-alias 'slime-fontify-string + 'slime-autodoc--fontify + "SLIME 2.10") + + +;;;; Autodocs (automatic context-sensitive help) + +(defun slime-autodoc (&optional force-multiline) + "Returns the cached arglist information as string, or nil. +If it's not in the cache, the cache will be updated asynchronously." + (save-excursion + (save-match-data + (let ((context (slime-autodoc--parse-context))) + (when context + (let* ((cached (slime-autodoc--cache-get context)) + (multilinep (or force-multiline + eldoc-echo-area-use-multiline-p))) + (cond (cached (slime-autodoc--format cached multilinep)) + (t + (when (slime-background-activities-enabled-p) + (slime-autodoc--async context multilinep)) + nil)))))))) + +;; Return the context around point that can be passed to +;; swank:autodoc. nil is returned if nothing reasonable could be +;; found. +(defun slime-autodoc--parse-context () + (and (slime-autodoc--parsing-safe-p) + (let ((levels slime-autodoc-accuracy-depth)) + (slime-parse-form-upto-point levels)))) + +(defun slime-autodoc--parsing-safe-p () + (cond ((fboundp 'slime-repl-inside-string-or-comment-p) + (not (slime-repl-inside-string-or-comment-p))) + (t + (not (slime-inside-string-or-comment-p))))) + +(defun slime-autodoc--async (context multilinep) + (slime-eval-async + `(swank:autodoc ',context ;; FIXME: misuse of quote + :print-right-margin ,(window-width (minibuffer-window))) + (slime-curry #'slime-autodoc--async% context multilinep))) + +(defun slime-autodoc--async% (context multilinep doc) + (cl-destructuring-bind (doc &optional cache-p) doc + (unless (eq doc :not-available) + (when cache-p + (slime-autodoc--cache-put context doc)) + ;; Now that we've got our information, + ;; get it to the user ASAP. + (when (eldoc-display-message-p) + (eldoc-message (slime-autodoc--format doc multilinep)))))) + + +;;; Minor mode definition + +;; Compute the prefix for slime-doc-map, usually this is C-c C-d. +(defun slime-autodoc--doc-map-prefix () + (concat + (car (rassoc '(slime-prefix-map) slime-parent-bindings)) + (car (rassoc '(slime-doc-map) slime-prefix-bindings)))) + +(define-minor-mode slime-autodoc-mode + "Toggle echo area display of Lisp objects at point." + :lighter slime-autodoc-mode-string + :keymap (let ((prefix (slime-autodoc--doc-map-prefix))) + `((,(concat prefix "A") . slime-autodoc-manually) + (,(concat prefix (kbd "C-A")) . slime-autodoc-manually) + (,(kbd "SPC") . slime-autodoc-space))) + (set (make-local-variable 'eldoc-documentation-function) 'slime-autodoc) + (set (make-local-variable 'eldoc-minor-mode-string) nil) + (setq slime-autodoc-mode (eldoc-mode arg)) + (when (called-interactively-p 'interactive) + (message "Slime autodoc mode %s." + (if slime-autodoc-mode "enabled" "disabled")))) + + +;;; Noise to enable/disable slime-autodoc-mode + +(defun slime-autodoc--on () (slime-autodoc-mode 1)) +(defun slime-autodoc--off () (slime-autodoc-mode 0)) + +(defvar slime-autodoc--relevant-hooks + '(slime-mode-hook slime-repl-mode-hook sldb-mode-hook)) + +(defun slime-autodoc--enable () + (dolist (h slime-autodoc--relevant-hooks) + (add-hook h 'slime-autodoc--on)) + (dolist (b (buffer-list)) + (with-current-buffer b + (when slime-mode + (slime-autodoc--on))))) + +(defun slime-autodoc--disable () + (dolist (h slime-autodoc--relevant-hooks) + (remove-hook h 'slime-autodoc--on)) + (dolist (b (buffer-list)) + (with-current-buffer b + (when slime-autodoc-mode + (slime-autodoc--off))))) + +(provide 'slime-autodoc) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-banner.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-banner.el new file mode 100644 index 0000000..f4eb8c4 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-banner.el @@ -0,0 +1,35 @@ +(require 'slime) +(require 'slime-repl) + +(define-slime-contrib slime-banner + "Persistent header line and startup animation." + (:authors "Helmut Eller " + "Luke Gorrie ") + (:license "GPL") + (:on-load (setq slime-repl-banner-function 'slime-startup-message)) + (:on-unload (setq slime-repl-banner-function 'slime-repl-insert-banner))) + +(defcustom slime-startup-animation (fboundp 'animate-string) + "Enable the startup animation." + :type '(choice (const :tag "Enable" t) (const :tag "Disable" nil)) + :group 'slime-ui) + +(defcustom slime-header-line-p (boundp 'header-line-format) + "If non-nil, display a header line in Slime buffers." + :type 'boolean + :group 'slime-repl) + +(defun slime-startup-message () + (when slime-header-line-p + (setq header-line-format + (format "%s Port: %s Pid: %s" + (slime-lisp-implementation-type) + (slime-connection-port (slime-connection)) + (slime-pid)))) + (when (zerop (buffer-size)) + (let ((welcome (concat "; SLIME " slime-version))) + (if slime-startup-animation + (animate-string welcome 0 0) + (insert welcome))))) + +(provide 'slime-banner) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-buffer-streams.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-buffer-streams.el new file mode 100644 index 0000000..2fa700d --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-buffer-streams.el @@ -0,0 +1,36 @@ +(eval-and-compile + (require 'slime)) + +(define-slime-contrib slime-buffer-streams + "Lisp streams that output to an emacs buffer" + (:authors "Ed Langley ") + (:license "GPL") + (:swank-dependencies swank-buffer-streams)) + +(defslimefun slime-make-buffer-stream-target (thread name) + (message "making target %s" name) + (slime-buffer-streams--get-target-marker name) + `(:stream-target-created ,thread ,name)) + +(defun slime-buffer-streams--get-target-name (target) + (format "*slime-target %s*" target)) + +(defvar-local slime-buffer-stream-target nil) + +;; TODO: tell backend that the buffer has been closed, so it can close +;; the stream +(defun slime-buffer-streams--cleanup-markers () + (when slime-buffer-stream-target + (message "Removing target: %s" slime-buffer-stream-target) + (remhash slime-buffer-stream-target slime-output-target-to-marker))) + +(defun slime-buffer-streams--get-target-marker (target) + (or (gethash target slime-output-target-to-marker) + (with-current-buffer + (generate-new-buffer (slime-buffer-streams--get-target-name target)) + (setq slime-buffer-stream-target target) + (add-hook 'kill-buffer-hook 'slime-buffer-streams--cleanup-markers) + (setf (gethash target slime-output-target-to-marker) + (point-marker))))) + +(provide 'slime-buffer-streams) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-c-p-c.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-c-p-c.el new file mode 100644 index 0000000..22a267b --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-c-p-c.el @@ -0,0 +1,305 @@ +(require 'slime) +(require 'cl-lib) + +(defvar slime-c-p-c-init-undo-stack nil) + +(define-slime-contrib slime-c-p-c + "ILISP style Compound Prefix Completion." + (:authors "Luke Gorrie " + "Edi Weitz " + "Matthias Koeppe " + "Tobias C. Rittweiler ") + (:license "GPL") + (:slime-dependencies slime-parse slime-editing-commands slime-autodoc) + (:swank-dependencies swank-c-p-c) + (:on-load + (push + `(progn + (remove-hook 'slime-completion-at-point-functions + #'slime-c-p-c-completion-at-point) + (remove-hook 'slime-connected-hook 'slime-c-p-c-on-connect) + ,@(when (featurep 'slime-repl) + `((define-key slime-mode-map "\C-c\C-s" + ',(lookup-key slime-mode-map "\C-c\C-s")) + (define-key slime-repl-mode-map "\C-c\C-s" + ',(lookup-key slime-repl-mode-map "\C-c\C-s"))))) + slime-c-p-c-init-undo-stack) + (add-hook 'slime-completion-at-point-functions + #'slime-c-p-c-completion-at-point) + (define-key slime-mode-map "\C-c\C-s" 'slime-complete-form) + (when (featurep 'slime-repl) + (define-key slime-repl-mode-map "\C-c\C-s" 'slime-complete-form))) + (:on-unload + (while slime-c-p-c-init-undo-stack + (eval (pop slime-c-p-c-init-undo-stack))))) + +(defcustom slime-c-p-c-unambiguous-prefix-p t + "If true, set point after the unambigous prefix. +If false, move point to the end of the inserted text." + :type 'boolean + :group 'slime-ui) + +(defcustom slime-complete-symbol*-fancy nil + "Use information from argument lists for DWIM'ish symbol completion." + :group 'slime-mode + :type 'boolean) + + +;; FIXME: this is the old code to display completions. Remove it once +;; `slime-complete-symbol*' and `slime-fuzzy-complete-symbol' can be +;; used together with `completion-at-point'. + +(defvar slime-completions-buffer-name "*Completions*") + +;; FIXME: can probably use quit-window instead +(make-variable-buffer-local + (defvar slime-complete-saved-window-configuration nil + "Window configuration before we show the *Completions* buffer. +This is buffer local in the buffer where the completion is +performed.")) + +(make-variable-buffer-local + (defvar slime-completions-window nil + "The window displaying *Completions* after saving window configuration. +If this window is no longer active or displaying the completions +buffer then we can ignore `slime-complete-saved-window-configuration'.")) + +(defun slime-complete-maybe-save-window-configuration () + "Maybe save the current window configuration. +Return true if the configuration was saved." + (unless (or slime-complete-saved-window-configuration + (get-buffer-window slime-completions-buffer-name)) + (setq slime-complete-saved-window-configuration + (current-window-configuration)) + t)) + +(defun slime-complete-delay-restoration () + (add-hook 'pre-command-hook + 'slime-complete-maybe-restore-window-configuration + 'append + 'local)) + +(defun slime-complete-forget-window-configuration () + (setq slime-complete-saved-window-configuration nil) + (setq slime-completions-window nil)) + +(defun slime-complete-restore-window-configuration () + "Restore the window config if available." + (remove-hook 'pre-command-hook + 'slime-complete-maybe-restore-window-configuration) + (when (and slime-complete-saved-window-configuration + (slime-completion-window-active-p)) + (save-excursion (set-window-configuration + slime-complete-saved-window-configuration)) + (setq slime-complete-saved-window-configuration nil) + (when (buffer-live-p slime-completions-buffer-name) + (kill-buffer slime-completions-buffer-name)))) + +(defun slime-complete-maybe-restore-window-configuration () + "Restore the window configuration, if the following command +terminates a current completion." + (remove-hook 'pre-command-hook + 'slime-complete-maybe-restore-window-configuration) + (condition-case err + (cond ((cl-find last-command-event "()\"'`,# \r\n:") + (slime-complete-restore-window-configuration)) + ((not (slime-completion-window-active-p)) + (slime-complete-forget-window-configuration)) + (t + (slime-complete-delay-restoration))) + (error + ;; Because this is called on the pre-command-hook, we mustn't let + ;; errors propagate. + (message "Error in slime-complete-restore-window-configuration: %S" + err)))) + +(defun slime-completion-window-active-p () + "Is the completion window currently active?" + (and (window-live-p slime-completions-window) + (equal (buffer-name (window-buffer slime-completions-window)) + slime-completions-buffer-name))) + +(defun slime-display-completion-list (completions start end) + (let ((savedp (slime-complete-maybe-save-window-configuration))) + (with-output-to-temp-buffer slime-completions-buffer-name + (display-completion-list completions) + (with-current-buffer standard-output + (setq completion-base-position (list start end)) + (set-syntax-table lisp-mode-syntax-table))) + (when savedp + (setq slime-completions-window + (get-buffer-window slime-completions-buffer-name))))) + +(defun slime-display-or-scroll-completions (completions start end) + (cond ((and (eq last-command this-command) + (slime-completion-window-active-p)) + (slime-scroll-completions)) + (t + (slime-display-completion-list completions start end))) + (slime-complete-delay-restoration)) + +(defun slime-scroll-completions () + (let ((window slime-completions-window)) + (with-current-buffer (window-buffer window) + (if (pos-visible-in-window-p (point-max) window) + (set-window-start window (point-min)) + (save-selected-window + (select-window window) + (scroll-up)))))) + +(defun slime-minibuffer-respecting-message (format &rest format-args) + "Display TEXT as a message, without hiding any minibuffer contents." + (let ((text (format " [%s]" (apply #'format format format-args)))) + (if (minibuffer-window-active-p (minibuffer-window)) + (minibuffer-message text) + (message "%s" text)))) + +(defun slime-maybe-complete-as-filename () + "If point is at a string starting with \", complete it as filename. + Return nil if point is not at filename." + (when (save-excursion (re-search-backward "\"[^ \t\n]+\\=" + (max (point-min) + (- (point) 1000)) t)) + (let ((comint-completion-addsuffix '("/" . "\""))) + (comint-replace-by-expanded-filename) + t))) + + +(defun slime-complete-symbol* () + "Expand abbreviations and complete the symbol at point." + ;; NB: It is only the name part of the symbol that we actually want + ;; to complete -- the package prefix, if given, is just context. + (or (slime-maybe-complete-as-filename) + (slime-expand-abbreviations-and-complete))) + +(defun slime-c-p-c-completion-at-point () + #'slime-complete-symbol*) + +;; FIXME: factorize +(defun slime-expand-abbreviations-and-complete () + (let* ((end (move-marker (make-marker) (slime-symbol-end-pos))) + (beg (move-marker (make-marker) (slime-symbol-start-pos))) + (prefix (buffer-substring-no-properties beg end)) + (completion-result (slime-contextual-completions beg end)) + (completion-set (cl-first completion-result)) + (completed-prefix (cl-second completion-result))) + (if (null completion-set) + (progn (slime-minibuffer-respecting-message + "Can't find completion for \"%s\"" prefix) + (ding) + (slime-complete-restore-window-configuration)) + ;; some XEmacs issue makes this distinction necessary + (cond ((> (length completed-prefix) (- end beg)) + (goto-char end) + (insert-and-inherit completed-prefix) + (delete-region beg end) + (goto-char (+ beg (length completed-prefix)))) + (t nil)) + (cond ((and (member completed-prefix completion-set) + (slime-length= completion-set 1)) + (slime-minibuffer-respecting-message "Sole completion") + (when slime-complete-symbol*-fancy + (slime-complete-symbol*-fancy-bit)) + (slime-complete-restore-window-configuration)) + ;; Incomplete + (t + (when (member completed-prefix completion-set) + (slime-minibuffer-respecting-message + "Complete but not unique")) + (when slime-c-p-c-unambiguous-prefix-p + (let ((unambiguous-completion-length + (cl-loop for c in completion-set + minimizing (or (cl-mismatch completed-prefix c) + (length completed-prefix))))) + (goto-char (+ beg unambiguous-completion-length)))) + (slime-display-or-scroll-completions completion-set + beg + (max (point) end))))))) + +(defun slime-complete-symbol*-fancy-bit () + "Do fancy tricks after completing a symbol. +\(Insert a space or close-paren based on arglist information.)" + (let ((arglist (slime-retrieve-arglist (slime-symbol-at-point)))) + (unless (eq arglist :not-available) + (let ((args + ;; Don't intern these symbols + (let ((obarray (make-vector 10 0))) + (cdr (read arglist)))) + (function-call-position-p + (save-excursion + (backward-sexp) + (equal (char-before) ?\()))) + (when function-call-position-p + (if (null args) + (execute-kbd-macro ")") + (execute-kbd-macro " ") + (when (and (slime-background-activities-enabled-p) + (not (minibuffer-window-active-p (minibuffer-window)))) + (slime-echo-arglist)))))))) + +(cl-defun slime-contextual-completions (beg end) + "Return a list of completions of the token from BEG to END in the +current buffer." + (let ((token (buffer-substring-no-properties beg end))) + (cond + ((and (< beg (point-max)) + (string= (buffer-substring-no-properties beg (1+ beg)) ":")) + ;; Contextual keyword completion + (let ((completions + (slime-completions-for-keyword token + (save-excursion + (goto-char beg) + (slime-parse-form-upto-point))))) + (when (cl-first completions) + (cl-return-from slime-contextual-completions completions)) + ;; If no matching keyword was found, do regular symbol + ;; completion. + )) + ((and (>= (length token) 2) + (string= (cl-subseq token 0 2) "#\\")) + ;; Character name completion + (cl-return-from slime-contextual-completions + (slime-completions-for-character token)))) + ;; Regular symbol completion + (slime-completions token))) + +(defun slime-completions (prefix) + (slime-eval `(swank:completions ,prefix ',(slime-current-package)))) + +(defun slime-completions-for-keyword (prefix buffer-form) + (slime-eval `(swank:completions-for-keyword ,prefix ',buffer-form))) + +(defun slime-completions-for-character (prefix) + (cl-labels ((append-char-syntax (string) (concat "#\\" string))) + (let ((result (slime-eval `(swank:completions-for-character + ,(cl-subseq prefix 2))))) + (when (car result) + (list (mapcar #'append-char-syntax (car result)) + (append-char-syntax (cadr result))))))) + + +;;; Complete form + +(defun slime-complete-form () + "Complete the form at point. +This is a superset of the functionality of `slime-insert-arglist'." + (interactive) + ;; Find the (possibly incomplete) form around point. + (let ((buffer-form (slime-parse-form-upto-point))) + (let ((result (slime-eval `(swank:complete-form ',buffer-form)))) + (if (eq result :not-available) + (error "Could not generate completion for the form `%s'" buffer-form) + (progn + (just-one-space (if (looking-back "\\s(" (1- (point))) + 0 + 1)) + (save-excursion + (insert result) + (let ((slime-close-parens-limit 1)) + (slime-close-all-parens-in-sexp))) + (save-excursion + (backward-up-list 1) + (indent-sexp))))))) + +(provide 'slime-c-p-c) + diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-cl-indent.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-cl-indent.el new file mode 100644 index 0000000..96ebb58 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-cl-indent.el @@ -0,0 +1,1821 @@ +;;; slime-cl-indent.el --- enhanced lisp-indent mode + +;; Copyright (C) 1987, 2000-2011 Free Software Foundation, Inc. + +;; Author: Richard Mlynarik +;; Created: July 1987 +;; Maintainer: FSF +;; Keywords: lisp, tools +;; Package: emacs + +;; This file is forked from cl-indent.el, which is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Commentary: + +;; This package supplies a single entry point, common-lisp-indent-function, +;; which performs indentation in the preferred style for Common Lisp code. +;; To enable it: +;; +;; (setq lisp-indent-function 'common-lisp-indent-function) +;; +;; This file is substantially patched from original cl-indent.el, +;; which is in Emacs proper. It does not require SLIME, but is instead +;; required by one of it's contribs, `slime-indentation'. +;; +;; Before making modifications to this file, consider adding them to +;; Emacs's own `cl-indent' and refactoring this file to be an +;; extension of Emacs's. + +;;; Code: + +(require 'slime) ; only for its cl-lib loading smartness +(require 'cl-lib) +(eval-when-compile (require 'cl)) + +(defgroup lisp-indent nil + "Indentation in Lisp." + :group 'lisp) + +(defcustom lisp-indent-maximum-backtracking 6 + "Maximum depth to backtrack out from a sublist for structured indentation. +If this variable is 0, no backtracking will occur and forms such as `flet' +may not be correctly indented if this value is less than 4." + :type 'integer + :group 'lisp-indent) + +(defcustom lisp-tag-indentation 1 + "Indentation of tags relative to containing list. +This variable is used by the function `lisp-indent-tagbody'." + :type 'integer + :group 'lisp-indent) + +(defcustom lisp-tag-body-indentation 3 + "Indentation of non-tagged lines relative to containing list. +This variable is used by the function `lisp-indent-tagbody' to indent normal +lines (lines without tags). +The indentation is relative to the indentation of the parenthesis enclosing +the special form. If the value is t, the body of tags will be indented +as a block at the same indentation as the first s-expression following +the tag. In this case, any forms before the first tag are indented +by `lisp-body-indent'." + :type 'integer + :group 'lisp-indent) + +(defcustom lisp-backquote-indentation t + "Whether or not to indent backquoted lists as code. +If nil, indent backquoted lists as data, i.e., like quoted lists." + :type 'boolean + :group 'lisp-indent) + +(defcustom lisp-loop-indent-subclauses t + "Whether or not to indent loop subclauses." + :type 'boolean + :group 'lisp-indent) + +(defcustom lisp-simple-loop-indentation 2 + "Indentation of forms in simple loop forms." + :type 'integer + :group 'lisp-indent) + +(defcustom lisp-loop-clauses-indentation 2 + "Indentation of loop clauses if `loop' is immediately followed by a newline." + :type 'integer + :group 'lisp-indent) + +(defcustom lisp-loop-indent-body-forms-relative-to-loop-start nil + "When true, indent loop body clauses relative to the open paren of the loop +form, instead of the keyword position." + :type 'boolean + :group 'lisp-indent) + +(defcustom lisp-loop-body-forms-indentation 3 + "Indentation of loop body clauses." + :type 'integer + :group 'lisp-indent) + +(defcustom lisp-loop-indent-forms-like-keywords nil + "Whether or not to indent loop subforms just like +loop keywords. Only matters when `lisp-loop-indent-subclauses' +is nil." + :type 'boolean + :group 'lisp-indent) + +(defcustom lisp-align-keywords-in-calls t + "Whether to align keyword arguments vertically or not. +If t (the default), keywords in contexts where no other +indentation rule takes precedence are aligned like this: + +\(make-instance 'foo :bar t + :quux 42) + +If nil, they are indented like any other function +call arguments: + +\(make-instance 'foo :bar t + :quux 42)" + :type 'boolean + :group 'lisp-indent) + +(defcustom lisp-lambda-list-indentation t + "Whether to indent lambda-lists specially. Defaults to t. Setting this to +nil makes `lisp-lambda-list-keyword-alignment', +`lisp-lambda-list-keyword-parameter-alignment', and +`lisp-lambda-list-keyword-parameter-indentation' meaningless, causing +lambda-lists to be indented as if they were data: + +\(defun example (a b &optional o1 o2 + o3 o4 + &rest r + &key k1 k2 + k3 k4) + #|...|#)" + :type 'boolean + :group 'lisp-indent) + +(defcustom lisp-lambda-list-keyword-alignment nil + "Whether to vertically align lambda-list keywords together. +If nil (the default), keyworded lambda-list parts are aligned +with the initial mandatory arguments, like this: + +\(defun foo (arg1 arg2 &rest rest + &key key1 key2) + #|...|#) + +If non-nil, alignment is done with the first keyword +\(or falls back to the previous case), as in: + +\(defun foo (arg1 arg2 &rest rest + &key key1 key2) + #|...|#)" + :type 'boolean + :group 'lisp-indent) + +(defcustom lisp-lambda-list-keyword-parameter-indentation 2 + "Indentation of lambda list keyword parameters. +See `lisp-lambda-list-keyword-parameter-alignment' +for more information." + :type 'integer + :group 'lisp-indent) + +(defcustom lisp-lambda-list-keyword-parameter-alignment nil + "Whether to vertically align lambda-list keyword parameters together. +If nil (the default), the parameters are aligned +with their corresponding keyword, plus the value of +`lisp-lambda-list-keyword-parameter-indentation', like this: + +\(defun foo (arg1 arg2 &key key1 key2 + key3 key4) + #|...|#) + +If non-nil, alignment is done with the first parameter +\(or falls back to the previous case), as in: + +\(defun foo (arg1 arg2 &key key1 key2 + key3 key4) + #|...|#)" + :type 'boolean + :group 'lisp-indent) + + +(defvar lisp-indent-defun-method '(4 &lambda &body) + "Defun-like indentation method. +This applies when the value of the `common-lisp-indent-function' property +is set to `defun'.") + + +;;;; Named styles. +;;;; +;;;; -*- common-lisp-style: foo -*- +;;;; +;;;; sets the style for the buffer. +;;;; +;;;; A Common Lisp style is a list of the form: +;;;; +;;;; (NAME INHERIT VARIABLES INDENTATION HOOK DOCSTRING) +;;;; +;;;; where NAME is a symbol naming the style, INHERIT is the name of the style +;;;; it inherits from, VARIABLES is an alist specifying buffer local variables +;;;; for the style, and INDENTATION is an alist specifying non-standard +;;;; indentations for Common Lisp symbols. HOOK is a function to call when +;;;; activating the style. DOCSTRING is the documentation for the style. +;;;; +;;;; Convenience accessors `common-lisp-style-name', &co exist. +;;;; +;;;; `common-lisp-style' stores the name of the current style. +;;;; +;;;; `common-lisp-style-default' stores the name of the style to use when none +;;;; has been specified. +;;;; +;;;; `common-lisp-active-style' stores a cons of the list specifying the +;;;; current style, and a hash-table containing all indentation methods of +;;;; that style and any styles it inherits from. Whenever we're indenting, we +;;;; check that this is up to date, and recompute when necessary. +;;;; +;;;; Just setting the buffer local common-lisp-style will be enough to have +;;;; the style take effect. `common-lisp-set-style' can also be called +;;;; explicitly, however, and offers name completion, etc. + +;;; Convenience accessors +(defun common-lisp-style-name (style) (first style)) +(defun common-lisp-style-inherits (style) (second style)) +(defun common-lisp-style-variables (style) (third style)) +(defun common-lisp-style-indentation (style) (fourth style)) +(defun common-lisp-style-hook (style) (fifth style)) +(defun common-lisp-style-docstring (style) (sixth style)) + +(defun common-lisp-make-style (stylename inherits variables indentation hook + documentation) + (list stylename inherits variables indentation hook documentation)) + +(defvar common-lisp-style nil) + +;;; `define-common-lisp-style' updates the docstring of +;;; `common-lisp-style', using this as the base. +(put 'common-lisp-style 'common-lisp-style-base-doc + "Name of the Common Lisp indentation style used in the current buffer. +Set this by giving eg. + + ;; -*- common-lisp-style: sbcl -*- + +in the first line of the file, or by calling `common-lisp-set-style'. If +buffer has no style specified, but `common-lisp-style-default' is set, that +style is used instead. Use `define-common-lisp-style' to define new styles.") + +(make-variable-buffer-local 'common-lisp-style) +(set-default 'common-lisp-style nil) + +;;; `lisp-mode' kills all buffer-local variables. Setting the +;;; `permanent-local' property allows us to retain the style. +(put 'common-lisp-style 'permanent-local t) + +;;; Mark as safe when the style doesn't evaluate arbitrary code. +(put 'common-lisp-style 'safe-local-variable 'common-lisp-safe-style-p) + +;;; Common Lisp indentation style specifications. +(defvar common-lisp-styles (make-hash-table :test 'equal)) + +(defun common-lisp-delete-style (stylename) + (remhash stylename common-lisp-styles)) + +(defun common-lisp-find-style (stylename) + (let ((name (if (symbolp stylename) + (symbol-name stylename) + stylename))) + (or (gethash name common-lisp-styles) + (error "Unknown Common Lisp style: %s" name)))) + +(defun common-lisp-safe-style-p (stylename) + "True for known Common Lisp style without an :EVAL option. +Ie. styles that will not evaluate arbitrary code on activation." + (let* ((style (ignore-errors (common-lisp-find-style stylename))) + (base (common-lisp-style-inherits style))) + (and style + (not (common-lisp-style-hook style)) + (or (not base) + (common-lisp-safe-style-p base))))) + +(defun common-lisp-add-style (stylename inherits variables indentation hooks + documentation) + ;; Invalidate indentation methods cached in common-lisp-active-style. + (maphash (lambda (k v) + (puthash k (cl-copy-list v) common-lisp-styles)) + common-lisp-styles) + ;; Add/Redefine the specified style. + (puthash stylename + (common-lisp-make-style stylename inherits variables indentation + hooks documentation) + common-lisp-styles) + ;; Frob `common-lisp-style' docstring. + (let ((doc (get 'common-lisp-style 'common-lisp-style-base-doc)) + (all nil)) + (setq doc (concat doc "\n\nAvailable styles are:\n")) + (maphash (lambda (name style) + (push (list name (common-lisp-style-docstring style)) all)) + common-lisp-styles) + (dolist (info (sort all (lambda (a b) (string< (car a) (car b))))) + (let ((style-name (first info)) + (style-doc (second info))) + (if style-doc + (setq doc (concat doc + "\n " style-name "\n" + " " style-doc "\n")) + (setq doc (concat doc + "\n " style-name " (undocumented)\n"))))) + (put 'common-lisp-style 'variable-documentation doc)) + stylename) + +;;; Activate STYLENAME, adding its indentation methods to METHODS -- and +;;; recurse on style inherited from. +(defun common-lisp-activate-style (stylename methods) + (let* ((style (common-lisp-find-style stylename)) + (basename (common-lisp-style-inherits style))) + ;; Recurse on parent. + (when basename + (common-lisp-activate-style basename methods)) + ;; Copy methods + (dolist (spec (common-lisp-style-indentation style)) + (puthash (first spec) (second spec) methods)) + ;; Bind variables. + (dolist (var (common-lisp-style-variables style)) + (set (make-local-variable (first var)) (second var))) + ;; Run hook. + (let ((hook (common-lisp-style-hook style))) + (when hook + (funcall hook))))) + +;;; When a style is being used, `common-lisp-active-style' holds a cons +;;; +;;; (STYLE . METHODS) +;;; +;;; where STYLE is the list specifying the currently active style, and +;;; METHODS is the table of indentation methods -- including inherited +;;; ones -- for it. `common-lisp-active-style-methods' is reponsible +;;; for keeping this up to date. +(make-variable-buffer-local (defvar common-lisp-active-style nil)) + +;;; Makes sure common-lisp-active-style corresponds to common-lisp-style, and +;;; pick up redefinitions, etc. Returns the method table for the currently +;;; active style. +(defun common-lisp-active-style-methods () + (let* ((name common-lisp-style) + (style (when name (common-lisp-find-style name)))) + (if (eq style (car common-lisp-active-style)) + (cdr common-lisp-active-style) + (when style + (let ((methods (make-hash-table :test 'equal))) + (common-lisp-activate-style name methods) + (setq common-lisp-active-style (cons style methods)) + methods))))) + +(defvar common-lisp-set-style-history nil) + +(defun common-lisp-style-names () + (let (names) + (maphash (lambda (k v) + (push (cons k v) names)) + common-lisp-styles) + names)) + +(defun common-lisp-set-style (stylename) + "Set current buffer to use the Common Lisp style STYLENAME. +STYLENAME, a string, must be an existing Common Lisp style. Styles +are added (and updated) using `define-common-lisp-style'. + +The buffer-local variable `common-lisp-style' will get set to STYLENAME. + +A Common Lisp style is composed of local variables, indentation +specifications, and may also contain arbitrary elisp code to run upon +activation." + (interactive + (list (let ((completion-ignore-case t) + (prompt "Specify Common Lisp indentation style: ")) + (completing-read prompt + (common-lisp-style-names) nil t nil + 'common-lisp-set-style-history)))) + (setq common-lisp-style (common-lisp-style-name + (common-lisp-find-style stylename)) + common-lisp-active-style nil) + ;; Actually activates the style. + (common-lisp-active-style-methods) + stylename) + +(defmacro define-common-lisp-style (name documentation &rest options) + "Define a Common Lisp indentation style. + +NAME is the name of the style. + +DOCUMENTATION is the docstring for the style, automatically added to the +docstring of `common-lisp-style'. + +OPTIONS are: + + (:variables (name value) ...) + + Specifying the buffer local variables associated with the style. + + (:indentation (symbol spec) ...) + + Specifying custom indentations associated with the style. SPEC is + a normal `common-lisp-indent-function' indentation specification. + + (:inherit style) + + Inherit variables and indentations from another Common Lisp style. + + (:eval form ...) + + Lisp code to evaluate when activating the style. This can be used to + eg. activate other modes. It is possible that over the lifetime of + a buffer same style gets activated multiple times, so code in :eval + option should cope with that. +" + (when (consp documentation) + (setq options (cons documentation options) + documentation nil)) + `(common-lisp-add-style ,name + ',(cadr (assoc :inherit options)) + ',(cdr (assoc :variables options)) + ',(cdr (assoc :indentation options)) + ,(when (assoc :eval options) + `(lambda () + ,@(cdr (assoc :eval options)))) + ,documentation)) + +(define-common-lisp-style "basic-common" + (:variables + (lisp-indent-maximum-backtracking 6) + (lisp-tag-indentation 1) + (lisp-tag-body-indentation 3) + (lisp-backquote-indentation t) + (lisp-loop-indent-subclauses t) + (lisp-loop-indent-forms-like-keywords nil) + (lisp-simple-loop-indentation 2) + (lisp-align-keywords-in-calls t) + (lisp-lambda-list-indentation t) + (lisp-lambda-list-keyword-alignment nil) + (lisp-lambda-list-keyword-parameter-indentation 2) + (lisp-lambda-list-keyword-parameter-alignment nil) + (lisp-indent-defun-method (4 &lambda &body)) + (lisp-loop-clauses-indentation 2) + (lisp-loop-indent-body-forms-relative-to-loop-start nil) + (lisp-loop-body-forms-indentation 3))) + +(define-common-lisp-style "basic-emacs25" + "This style adds a workaround needed for Emacs 25" + (:inherit "basic-common") + (:variables + ;; Without these (;;foo would get a space inserted between + ;; ( and ; by indent-sexp. + (comment-indent-function (lambda () nil)))) + +(define-common-lisp-style "basic-emacs26" + "This style is the same as basic-common. It doesn't need or + want the workaround used in Emacs 25. In Emacs 26, that + workaround introduces a weird behavior where a single + semicolon breaks the mode and causes the cursor to move to the + start of the line after every character inserted." + (:inherit "basic-common")) + +(if (>= emacs-major-version 26) + (define-common-lisp-style "basic" + "This style merely gives all identation variables their default values, + making it easy to create new styles that are proof against user + customizations. It also adjusts comment indentation from default. + All other predefined modes inherit from basic." + (:inherit "basic-emacs26")) + (define-common-lisp-style "basic" + "This style merely gives all identation variables their default values, + making it easy to create new styles that are proof against user + customizations. It also adjusts comment indentation from default. + All other predefined modes inherit from basic." + (:inherit "basic-emacs25"))) + +(define-common-lisp-style "classic" + "This style of indentation emulates the most striking features of 1995 + vintage cl-indent.el once included as part of Slime: IF indented by two + spaces, and CASE clause bodies indentented more deeply than the keys." + (:inherit "basic") + (:variables + (lisp-lambda-list-keyword-parameter-indentation 0)) + (:indentation + (case (4 &rest (&whole 2 &rest 3))) + (if (4 2 2)))) + +(define-common-lisp-style "modern" + "A good general purpose style. Turns on lambda-list keyword and keyword + parameter alignment, and turns subclause aware loop indentation off. + (Loop indentation so because simpler style is more prevalent in existing + sources, not because it is necessarily preferred.)" + (:inherit "basic") + (:variables + (lisp-lambda-list-keyword-alignment t) + (lisp-lambda-list-keyword-parameter-alignment t) + (lisp-lambda-list-keyword-parameter-indentation 0) + (lisp-loop-indent-subclauses nil))) + +(define-common-lisp-style "sbcl" + "Style used in SBCL sources. A good if somewhat intrusive general purpose + style based on the \"modern\" style. Adds indentation for a few SBCL + specific constructs, sets indentation to use spaces instead of tabs, + fill-column to 78, and activates whitespace-mode to show tabs and trailing + whitespace." + (:inherit "modern") + (:eval + (whitespace-mode 1)) + (:variables + (whitespace-style (tabs trailing)) + (indent-tabs-mode nil) + (comment-fill-column nil) + (fill-column 78)) + (:indentation + (def!constant (as defconstant)) + (def!macro (as defmacro)) + (def!method (as defmethod)) + (def!struct (as defstruct)) + (def!type (as deftype)) + (defmacro-mundanely (as defmacro)) + (define-source-transform (as defun)) + (!def-type-translator (as defun)) + (!def-debug-command (as defun)))) + +(defcustom common-lisp-style-default nil + "Name of the Common Lisp indentation style to use in lisp-mode buffers if +none has been specified." + :type `(choice (const :tag "None" nil) + ,@(mapcar (lambda (spec) + `(const :tag ,(car spec) ,(car spec))) + (common-lisp-style-names)) + (string :tag "Other")) + :group 'lisp-indent) + +;;; If style is being used, that's a sufficient invitation to snag +;;; the indentation function. +(defun common-lisp-lisp-mode-hook () + (let ((style (or common-lisp-style common-lisp-style-default))) + (when style + (set (make-local-variable 'lisp-indent-function) + 'common-lisp-indent-function) + (common-lisp-set-style style)))) +(add-hook 'lisp-mode-hook 'common-lisp-lisp-mode-hook) + + +;;;; The indentation specs are stored at three levels. In order of priority: +;;;; +;;;; 1. Indentation as set by current style, from the indentation table +;;;; in the current style. +;;;; +;;;; 2. Globally set indentation, from the `common-lisp-indent-function' +;;;; property of the symbol. +;;;; +;;;; 3. Per-package indentation derived by the system. A live Common Lisp +;;;; system may (via Slime, eg.) add indentation specs to +;;;; common-lisp-system-indentation, where they are associated with +;;;; the package of the symbol. Then we run some lossy heuristics and +;;;; find something that looks promising. +;;;; +;;;; FIXME: for non-system packages the derived indentation should probably +;;;; take precedence. + +;;; This maps symbols into lists of (INDENT . PACKAGES) where INDENT is +;;; an indentation spec, and PACKAGES are the names of packages where this +;;; applies. +;;; +;;; We never add stuff here by ourselves: this is for things like Slime to +;;; fill. +(defvar common-lisp-system-indentation (make-hash-table :test 'equal)) + +(defun common-lisp-guess-current-package () + (let (pkg) + (save-excursion + (ignore-errors + (when (let ((case-fold-search t)) + (search-backward "(in-package ")) + (re-search-forward "[ :\"]+") + (let ((start (point))) + (re-search-forward "[\":)]") + (setf pkg (upcase (buffer-substring-no-properties + start (1- (point))))))))) + pkg)) + +(defvar common-lisp-current-package-function 'common-lisp-guess-current-package + "Used to derive the package name to use for indentation at a +given point. Defaults to `common-lisp-guess-current-package'.") + +(defun common-lisp-symbol-package (string) + (if (and (stringp string) (string-match ":" string)) + (let ((p (match-beginning 0))) + (if (eql 0 p) + "KEYWORD" + (upcase (substring string 0 p)))) + (funcall common-lisp-current-package-function))) + +(defun common-lisp-get-indentation (name &optional full) + "Retrieves the indentation information for NAME." + (let ((method + (or + ;; From style + (when common-lisp-style + (gethash name (common-lisp-active-style-methods))) + ;; From global settings. + (get name 'common-lisp-indent-function) + ;; From system derived information. + (let ((system-info (gethash name common-lisp-system-indentation))) + (if (not (cdr system-info)) + (caar system-info) + (let ((guess nil) + (guess-n 0) + (package (common-lisp-symbol-package full))) + (dolist (info system-info guess) + (let* ((pkgs (cdr info)) + (n (length pkgs))) + (cond ((member package pkgs) + ;; This is it. + (return (car info))) + ((> n guess-n) + ;; If we can't find the real thing, go with the one + ;; accessible in most packages. + (setf guess (car info) + guess-n n))))))))))) + (if (and (consp method) (eq 'as (car method))) + (common-lisp-get-indentation (cadr method)) + method))) + +;;;; LOOP indentation, the simple version + +(defun common-lisp-loop-type (loop-start) + "Returns the type of the loop form at LOOP-START. +Possible types are SIMPLE, SIMPLE/SPLIT, EXTENDED, and EXTENDED/SPLIT. */SPLIT +refers to extended loops whose body does not start on the same line as the +opening parenthesis of the loop." + (let (comment-split) + (condition-case () + (save-excursion + (goto-char loop-start) + (let ((line (line-number-at-pos)) + (maybe-split t)) + (forward-char 1) + (forward-sexp 1) + (save-excursion + (when (looking-at "\\s-*\\\n*;") + (search-forward ";") + (backward-char 1) + (if (= line (line-number-at-pos)) + (setq maybe-split nil) + (setq comment-split t)))) + (forward-sexp 1) + (backward-sexp 1) + (if (eql (char-after) ?\() + (if (or (not maybe-split) (= line (line-number-at-pos))) + 'simple + 'simple/split) + (if (or (not maybe-split) (= line (line-number-at-pos))) + 'extended + 'extended/split)))) + (error + (if comment-split + 'simple/split + 'simple))))) + +(defun common-lisp-trailing-comment () + (ignore-errors + ;; If we had a trailing comment just before this, find it. + (save-excursion + (backward-sexp) + (forward-sexp) + (when (looking-at "\\s-*;") + (search-forward ";") + (1- (current-column)))))) + +;;;###autoload +(defun common-lisp-indent-function (indent-point state) + "Function to indent the arguments of a Lisp function call. +This is suitable for use as the value of the variable +`lisp-indent-function'. INDENT-POINT is the point at which the +indentation function is called, and STATE is the +`parse-partial-sexp' state at that position. Browse the +`lisp-indent' customize group for options affecting the behavior +of this function. + +If the indentation point is in a call to a Lisp function, that +function's common-lisp-indent-function property specifies how +this function should indent it. Possible values for this +property are: + +* defun, meaning indent according to `lisp-indent-defun-method'; + i.e., like (4 &lambda &body), as explained below. + +* any other symbol, meaning a function to call. The function should + take the arguments: PATH STATE INDENT-POINT SEXP-COLUMN NORMAL-INDENT. + PATH is a list of integers describing the position of point in terms of + list-structure with respect to the containing lists. For example, in + ((a b c (d foo) f) g), foo has a path of (0 3 1). In other words, + to reach foo take the 0th element of the outermost list, then + the 3rd element of the next list, and finally the 1st element. + STATE and INDENT-POINT are as in the arguments to + `common-lisp-indent-function'. SEXP-COLUMN is the column of + the open parenthesis of the innermost containing list. + NORMAL-INDENT is the column the indentation point was + originally in. This function should behave like `lisp-indent-259'. + +* an integer N, meaning indent the first N arguments like + function arguments, and any further arguments like a body. + This is equivalent to (4 4 ... &body). + +* a list starting with `as' specifies an indirection: indentation is done as + if the form being indented had started with the second element of the list. + +* any other list. The list element in position M specifies how to indent the + Mth function argument. If there are fewer elements than function arguments, + the last list element applies to all remaining arguments. The accepted list + elements are: + + * nil, meaning the default indentation. + + * an integer, specifying an explicit indentation. + + * &lambda. Indent the argument (which may be a list) by 4. + + * &rest. When used, this must be the penultimate element. The + element after this one applies to all remaining arguments. + + * &body. This is equivalent to &rest lisp-body-indent, i.e., indent + all remaining elements by `lisp-body-indent'. + + * &whole. This must be followed by nil, an integer, or a + function symbol. This indentation is applied to the + associated argument, and as a base indent for all remaining + arguments. For example, an integer P means indent this + argument by P, and all remaining arguments by P, plus the + value specified by their associated list element. + + * a symbol. A function to call, with the 6 arguments specified above. + + * a list, with elements as described above. This applies when the + associated function argument is itself a list. Each element of the list + specifies how to indent the associated argument. + +For example, the function `case' has an indent property +\(4 &rest (&whole 2 &rest 1)), meaning: + * indent the first argument by 4. + * arguments after the first should be lists, and there may be any number + of them. The first list element has an offset of 2, all the rest + have an offset of 2+1=3." + (common-lisp-indent-function-1 indent-point state)) + +;;; XEmacs doesn't have looking-back, so we define a simple one. Faster to +;;; boot, and sufficient for our needs. +(defun common-lisp-looking-back (string) + (let ((len (length string))) + (dotimes (i len t) + (unless (eql (elt string (- len i 1)) (char-before (- (point) i))) + (return nil))))) + +(defvar common-lisp-feature-expr-regexp "#!?\\(+\\|-\\)") + +;;; Semi-feature-expression aware keyword check. +(defun common-lisp-looking-at-keyword () + (or (looking-at ":") + (and (looking-at common-lisp-feature-expr-regexp) + (save-excursion + (forward-sexp) + (skip-chars-forward " \t\n") + (common-lisp-looking-at-keyword))))) + +;;; Semi-feature-expression aware backwards movement for keyword +;;; argument pairs. +(defun common-lisp-backward-keyword-argument () + (ignore-errors + (backward-sexp 2) + (when (looking-at common-lisp-feature-expr-regexp) + (cond ((ignore-errors + (save-excursion + (backward-sexp 2) + (looking-at common-lisp-feature-expr-regexp))) + (common-lisp-backward-keyword-argument)) + ((ignore-errors + (save-excursion + (backward-sexp 1) + (looking-at ":"))) + (backward-sexp)))) + t)) + +(defun common-lisp-indent-function-1 (indent-point state) + ;; If we're looking at a splice, move to the first comma. + (when (or (common-lisp-looking-back ",") (common-lisp-looking-back ",@")) + (when (re-search-backward "[^,@'],") + (forward-char 1))) + (let ((normal-indent (current-column))) + ;; Walk up list levels until we see something + ;; which does special things with subforms. + (let ((depth 0) + ;; Path describes the position of point in terms of + ;; list-structure with respect to containing lists. + ;; `foo' has a path of (0 3 1) in `((a b c (d foo) f) g)'. + (path ()) + ;; set non-nil when somebody works out the indentation to use + calculated + ;; If non-nil, this is an indentation to use + ;; if nothing else specifies it more firmly. + tentative-calculated + (last-point indent-point) + ;; the position of the open-paren of the innermost containing list + (containing-form-start (common-lisp-indent-parse-state-start state)) + ;; the column of the above + sexp-column) + ;; Move to start of innermost containing list + (goto-char containing-form-start) + (setq sexp-column (current-column)) + + ;; Look over successively less-deep containing forms + (while (and (not calculated) + (< depth lisp-indent-maximum-backtracking)) + (let ((containing-sexp (point))) + (forward-char 1) + (parse-partial-sexp (point) indent-point 1 t) + ;; Move to the car of the relevant containing form + (let (tem full function method tentative-defun) + (if (not (looking-at "\\sw\\|\\s_")) + ;; This form doesn't seem to start with a symbol + (setq function nil method nil full nil) + (setq tem (point)) + (forward-sexp 1) + (setq full (downcase (buffer-substring-no-properties + tem (point))) + function full) + (goto-char tem) + (setq tem (intern-soft function) + method (common-lisp-get-indentation tem)) + (cond ((and (null method) + (string-match ":[^:]+" function)) + ;; The pleblisp package feature + (setq function (substring function + (1+ (match-beginning 0))) + method (common-lisp-get-indentation + (intern-soft function) full))) + ((and (null method)) + ;; backwards compatibility + (setq method (common-lisp-get-indentation tem))))) + (let ((n 0)) + ;; How far into the containing form is the current form? + (if (< (point) indent-point) + (while (condition-case () + (progn + (forward-sexp 1) + (if (>= (point) indent-point) + nil + (parse-partial-sexp (point) + indent-point 1 t) + (setq n (1+ n)) + t)) + (error nil)))) + (setq path (cons n path))) + + ;; Guess. + (when (and (not method) function (null (cdr path))) + ;; (package prefix was stripped off above) + (cond ((and (string-match "\\`def" function) + (not (string-match "\\`default" function)) + (not (string-match "\\`definition" function)) + (not (string-match "\\`definer" function))) + (setq tentative-defun t)) + ((string-match + (eval-when-compile + (concat "\\`\\(" + (regexp-opt '("with" "without" "do")) + "\\)-")) + function) + (setq method '(&lambda &body))))) + + ;; #+ and #- cleverness. + (save-excursion + (goto-char indent-point) + (backward-sexp) + (let ((indent (current-column))) + (when (or (looking-at common-lisp-feature-expr-regexp) + (ignore-errors + (backward-sexp) + (when (looking-at + common-lisp-feature-expr-regexp) + (setq indent (current-column)) + (let ((line (line-number-at-pos))) + (while + (ignore-errors + (backward-sexp 2) + (and + (= line (line-number-at-pos)) + (looking-at + common-lisp-feature-expr-regexp))) + (setq indent (current-column)))) + t))) + (setq calculated (list indent containing-form-start))))) + + (cond ((and (or (eq (char-after (1- containing-sexp)) ?\') + (and (not lisp-backquote-indentation) + (eq (char-after (1- containing-sexp)) ?\`))) + (not (eq (char-after (- containing-sexp 2)) ?\#))) + ;; No indentation for "'(...)" elements + (setq calculated (1+ sexp-column))) + ((eq (char-after (1- containing-sexp)) ?\#) + ;; "#(...)" + (setq calculated (1+ sexp-column))) + ((null method) + ;; If this looks like a call to a `def...' form, + ;; think about indenting it as one, but do it + ;; tentatively for cases like + ;; (flet ((defunp () + ;; nil))) + ;; Set both normal-indent and tentative-calculated. + ;; The latter ensures this value gets used + ;; if there are no relevant containing constructs. + ;; The former ensures this value gets used + ;; if there is a relevant containing construct + ;; but we are nested within the structure levels + ;; that it specifies indentation for. + (if tentative-defun + (setq tentative-calculated + (common-lisp-indent-call-method + function lisp-indent-defun-method + path state indent-point + sexp-column normal-indent) + normal-indent tentative-calculated) + (when lisp-align-keywords-in-calls + ;; No method so far. If we're looking at a keyword, + ;; align with the first keyword in this expression. + ;; This gives a reasonable indentation to most things + ;; with keyword arguments. + (save-excursion + (goto-char indent-point) + (back-to-indentation) + (when (common-lisp-looking-at-keyword) + (while (common-lisp-backward-keyword-argument) + (when (common-lisp-looking-at-keyword) + (setq calculated + (list (current-column) + containing-form-start))))))))) + ((integerp method) + ;; convenient top-level hack. + ;; (also compatible with lisp-indent-function) + ;; The number specifies how many `distinguished' + ;; forms there are before the body starts + ;; Equivalent to (4 4 ... &body) + (setq calculated (cond ((cdr path) + normal-indent) + ((<= (car path) method) + ;; `distinguished' form + (list (+ sexp-column 4) + containing-form-start)) + ((= (car path) (1+ method)) + ;; first body form. + (+ sexp-column lisp-body-indent)) + (t + ;; other body form + normal-indent)))) + (t + (setq calculated + (common-lisp-indent-call-method + function method path state indent-point + sexp-column normal-indent))))) + (goto-char containing-sexp) + (setq last-point containing-sexp) + (unless calculated + (condition-case () + (progn (backward-up-list 1) + (setq depth (1+ depth))) + (error + (setq depth lisp-indent-maximum-backtracking)))))) + + (or calculated tentative-calculated + ;; Fallback. + ;; + ;; Instead of punting directly to calculate-lisp-indent we + ;; handle a few of cases it doesn't deal with: + ;; + ;; A: (foo ( + ;; bar zot + ;; quux)) + ;; + ;; would align QUUX with ZOT. + ;; + ;; B: + ;; (foo (or x + ;; y) t + ;; z) + ;; + ;; would align the Z with Y. + ;; + ;; C: + ;; (foo ;; Comment + ;; (bar) + ;; ;; Comment 2 + ;; (quux)) + ;; + ;; would indent BAR and QUUX by one. + (ignore-errors + (save-excursion + (goto-char indent-point) + (back-to-indentation) + (let ((p (point))) + (goto-char containing-form-start) + (down-list) + (let ((one (current-column))) + (skip-chars-forward " \t") + (if (or (eolp) (looking-at ";")) + ;; A. + (list one containing-form-start) + (forward-sexp 2) + (backward-sexp) + (if (/= p (point)) + ;; B. + (list (current-column) containing-form-start) + (backward-sexp) + (forward-sexp) + (let ((tmp (+ (current-column) 1))) + (skip-chars-forward " \t") + (if (looking-at ";") + ;; C. + (list tmp containing-form-start))))))))))))) + + +(defun common-lisp-indent-call-method (function method path state indent-point + sexp-column normal-indent) + (let ((lisp-indent-error-function function)) + (if (symbolp method) + (funcall method + path state indent-point + sexp-column normal-indent) + (lisp-indent-259 method path state indent-point + sexp-column normal-indent)))) + +;; Dynamically bound in common-lisp-indent-call-method. +(defvar lisp-indent-error-function) + +(defun lisp-indent-report-bad-format (m) + (error "%s has a badly-formed %s property: %s" + ;; Love those free variable references!! + lisp-indent-error-function 'common-lisp-indent-function m)) + + +;; Lambda-list indentation is now done in LISP-INDENT-LAMBDA-LIST. +;; See also `lisp-lambda-list-keyword-alignment', +;; `lisp-lambda-list-keyword-parameter-alignment' and +;; `lisp-lambda-list-keyword-parameter-indentation' -- dvl + +(defvar lisp-indent-lambda-list-keywords-regexp + "&\\(\ +optional\\|rest\\|key\\|allow-other-keys\\|aux\\|whole\\|body\\|\ +environment\\|more\ +\\)\\>" + "Regular expression matching lambda-list keywords.") + +(defun lisp-indent-lambda-list + (indent-point sexp-column containing-form-start) + (if (not lisp-lambda-list-indentation) + (1+ sexp-column) + (lisp-properly-indent-lambda-list + indent-point sexp-column containing-form-start))) + +(defun lisp-properly-indent-lambda-list + (indent-point sexp-column containing-form-start) + (let (limit) + (cond + ((save-excursion + (goto-char indent-point) + (back-to-indentation) + (setq limit (point)) + (looking-at lisp-indent-lambda-list-keywords-regexp)) + ;; We're facing a lambda-list keyword. + (if lisp-lambda-list-keyword-alignment + ;; Align to the first keyword if any, or to the beginning of + ;; the lambda-list. + (save-excursion + (goto-char containing-form-start) + (down-list) + (let ((key-indent nil) + (next t)) + (while (and next (< (point) indent-point)) + (if (looking-at lisp-indent-lambda-list-keywords-regexp) + (setq key-indent (current-column) + next nil) + (setq next (ignore-errors (forward-sexp) t)) + (if next + (ignore-errors + (forward-sexp) + (backward-sexp))))) + (or key-indent + (1+ sexp-column)))) + ;; Align to the beginning of the lambda-list. + (1+ sexp-column))) + (t + ;; Otherwise, align to the first argument of the last lambda-list + ;; keyword, the keyword itself, or the beginning of the + ;; lambda-list. + (save-excursion + (goto-char indent-point) + (let ((indent nil) + (next t)) + (while (and next (> (point) containing-form-start)) + (setq next (ignore-errors (backward-sexp) t)) + (let* ((col (current-column)) + (pos + (save-excursion + (ignore-errors (forward-sexp)) + (skip-chars-forward " \t") + (if (eolp) + (+ col + lisp-lambda-list-keyword-parameter-indentation) + col)))) + (if (looking-at lisp-indent-lambda-list-keywords-regexp) + (setq indent + (if lisp-lambda-list-keyword-parameter-alignment + (or indent pos) + (+ col + lisp-lambda-list-keyword-parameter-indentation)) + next nil) + (setq indent col)))) + (or indent (1+ sexp-column)))))))) + +(defun common-lisp-lambda-list-initial-value-form-p (point) + (let ((state 'x) + (point (save-excursion + (goto-char point) + (back-to-indentation) + (point)))) + (save-excursion + (backward-sexp) + (ignore-errors (down-list 1)) + (while (and point (< (point) point)) + (cond ((or (looking-at "&key") (looking-at "&optional") + (looking-at "&aux")) + (setq state 'key)) + ((looking-at lisp-indent-lambda-list-keywords-regexp) + (setq state 'x))) + (if (not (ignore-errors (forward-sexp) t)) + (setq point nil) + (ignore-errors + (forward-sexp) + (backward-sexp)) + (cond ((> (point) point) + (backward-sexp) + (when (eq state 'var) + (setq state 'x)) + (or (ignore-errors + (down-list 1) + (cond ((> (point) point) + (backward-up-list)) + ((eq 'key state) + (setq state 'var))) + t) + (setq point nil))) + ((eq state 'var) + (setq state 'form)))))) + (eq 'form state))) + +;; Blame the crufty control structure on dynamic scoping +;; -- not on me! +(defun lisp-indent-259 + (method path state indent-point sexp-column normal-indent) + (catch 'exit + (let* ((p (cdr path)) + (containing-form-start (elt state 1)) + (n (1- (car path))) + tem tail) + (if (not (consp method)) + (lisp-indent-report-bad-format method)) + (while n + ;; This while loop is for advancing along a method + ;; until the relevant (possibly &rest/&body) pattern + ;; is reached. + ;; n is set to (1- n) and method to (cdr method) + ;; each iteration. + (setq tem (car method)) + + (or (eq tem 'nil) ;default indentation + (eq tem '&lambda) ;lambda list + (and (eq tem '&body) (null (cdr method))) + (and (eq tem '&rest) + (consp (cdr method)) + (null (cddr method))) + (integerp tem) ;explicit indentation specified + (and (consp tem) ;destructuring + (or (consp (car tem)) + (and (eq (car tem) '&whole) + (or (symbolp (cadr tem)) + (integerp (cadr tem)))))) + (and (symbolp tem) ;a function to call to do the work. + (null (cdr method))) + (lisp-indent-report-bad-format method)) + (cond ((eq tem '&body) + ;; &body means (&rest ) + (throw 'exit + (if (null p) + (+ sexp-column lisp-body-indent) + normal-indent))) + ((eq tem '&rest) + ;; this pattern holds for all remaining forms + (setq tail (> n 0) + n 0 + method (cdr method))) + ((> n 0) + ;; try next element of pattern + (setq n (1- n) + method (cdr method)) + (if (< n 0) + ;; Too few elements in pattern. + (throw 'exit normal-indent))) + ((eq tem 'nil) + (throw 'exit (if (consp normal-indent) + normal-indent + (list normal-indent containing-form-start)))) + ((eq tem '&lambda) + (throw 'exit + (cond ((not (common-lisp-looking-back ")")) + ;; If it's not a list at all, indent it + ;; like body instead. + (if (null p) + (+ sexp-column lisp-body-indent) + normal-indent)) + ((common-lisp-lambda-list-initial-value-form-p + indent-point) + (if (consp normal-indent) + normal-indent + (list normal-indent containing-form-start))) + ((null p) + (list (+ sexp-column 4) containing-form-start)) + (t + ;; Indentation within a lambda-list. -- dvl + (list (lisp-indent-lambda-list + indent-point + sexp-column + containing-form-start) + containing-form-start))))) + ((integerp tem) + (throw 'exit + (if (null p) ;not in subforms + (list (+ sexp-column tem) containing-form-start) + normal-indent))) + ((symbolp tem) ;a function to call + (throw 'exit + (funcall tem path state indent-point + sexp-column normal-indent))) + (t + ;; must be a destructing frob + (if p + ;; descend + (setq method (cddr tem) + n (car p) + p (cdr p) + tail nil) + (let ((wholep (eq '&whole (car tem)))) + (setq tem (cadr tem)) + (throw 'exit + (cond (tail + (if (and wholep (integerp tem) + (save-excursion + (goto-char indent-point) + (back-to-indentation) + (looking-at "\\sw"))) + ;; There's a further level of + ;; destructuring, but we're looking at a + ;; word -- indent to sexp. + (+ sexp-column tem) + normal-indent)) + ((not tem) + (list normal-indent + containing-form-start)) + ((integerp tem) + (list (+ sexp-column tem) + containing-form-start)) + (t + (funcall tem path state indent-point + sexp-column normal-indent)))))))))))) + +(defun lisp-indent-tagbody (path state indent-point sexp-column normal-indent) + (if (not (null (cdr path))) + normal-indent + (save-excursion + (goto-char indent-point) + (back-to-indentation) + (list (cond ((looking-at "\\sw\\|\\s_") + ;; a tagbody tag + (+ sexp-column lisp-tag-indentation)) + ((integerp lisp-tag-body-indentation) + (+ sexp-column lisp-tag-body-indentation)) + ((eq lisp-tag-body-indentation 't) + (condition-case () + (progn (backward-sexp 1) (current-column)) + (error (1+ sexp-column)))) + (t (+ sexp-column lisp-body-indent))) +; (cond ((integerp lisp-tag-body-indentation) +; (+ sexp-column lisp-tag-body-indentation)) +; ((eq lisp-tag-body-indentation 't) +; normal-indent) +; (t +; (+ sexp-column lisp-body-indent))) + (elt state 1) + )))) + +(defun lisp-indent-do (path state indent-point sexp-column normal-indent) + (if (>= (car path) 3) + (let ((lisp-tag-body-indentation lisp-body-indent)) + (funcall (function lisp-indent-tagbody) + path state indent-point sexp-column normal-indent)) + (funcall (function lisp-indent-259) + '((&whole nil &rest + ;; the following causes weird indentation + ;;(&whole 1 1 2 nil) + ) + (&whole nil &rest 1)) + path state indent-point sexp-column normal-indent))) + +(defun lisp-indent-defsetf + (path state indent-point sexp-column normal-indent) + (list + (cond + ;; Inside the lambda-list in a long-form defsetf. + ((and (eql 2 (car path)) (cdr path)) + (lisp-indent-lambda-list indent-point sexp-column (elt state 1))) + ;; Long form: has a lambda-list. + ((or (cdr path) + (save-excursion + (goto-char (elt state 1)) + (ignore-errors + (down-list) + (forward-sexp 3) + (backward-sexp) + (looking-at "nil\\|(")))) + (+ sexp-column + (case (car path) + ((1 3) 4) + (2 4) + (t 2)))) + ;; Short form. + (t + (+ sexp-column + (case (car path) + (1 4) + (2 4) + (t 2))))) + (elt state 1))) + +(defun lisp-beginning-of-defmethod-qualifiers () + (let ((regexp-1 "(defmethod\\|(DEFMETHOD") + (regexp-2 "(:method\\|(:METHOD")) + (while (and (not (or (looking-at regexp-1) + (looking-at regexp-2))) + (ignore-errors (backward-up-list) t))) + (cond ((looking-at regexp-1) + (forward-char) + ;; Skip name. + (forward-sexp 2) + 1) + ((looking-at regexp-2) + (forward-char) + (forward-sexp 1) + 0)))) + +;; LISP-INDENT-DEFMETHOD now supports the presence of more than one method +;; qualifier and indents the method's lambda list properly. -- dvl +(defun lisp-indent-defmethod + (path state indent-point sexp-column normal-indent) + (lisp-indent-259 + (let ((nskip nil)) + (if (save-excursion + (when (setq nskip (lisp-beginning-of-defmethod-qualifiers)) + (skip-chars-forward " \t\n") + (while (looking-at "\\sw\\|\\s_") + (incf nskip) + (forward-sexp) + (skip-chars-forward " \t\n")) + t)) + (append (make-list nskip 4) '(&lambda &body)) + (common-lisp-get-indentation 'defun))) + path state indent-point sexp-column normal-indent)) + +(defun lisp-indent-function-lambda-hack (path state indent-point + sexp-column normal-indent) + ;; indent (function (lambda () )) kludgily. + (if (or (cdr path) ; wtf? + (> (car path) 3)) + ;; line up under previous body form + normal-indent + ;; line up under function rather than under lambda in order to + ;; conserve horizontal space. (Which is what #' is for.) + (condition-case () + (save-excursion + (backward-up-list 2) + (forward-char 1) + (if (looking-at "\\(lisp:+\\)?function\\(\\Sw\\|\\S_\\)") + (+ lisp-body-indent -1 (current-column)) + (+ sexp-column lisp-body-indent))) + (error (+ sexp-column lisp-body-indent))))) + +(defun lisp-indent-loop (path state indent-point sexp-column normal-indent) + (if (cdr path) + normal-indent + (let* ((loop-start (elt state 1)) + (type (common-lisp-loop-type loop-start))) + (cond ((and lisp-loop-indent-subclauses + (member type '(extended extended/split))) + (list (common-lisp-indent-loop-macro-1 state indent-point) + (common-lisp-indent-parse-state-start state))) + (t + (common-lisp-loop-part-indentation indent-point state type)))))) + +;;;; LOOP indentation, the complex version -- handles subclause indentation + +;; Regexps matching various varieties of loop macro keyword ... +(defvar common-lisp-body-introducing-loop-macro-keyword + "\\(#?:\\)?\\(do\\(ing\\)?\\|finally\\|initially\\)" + "Regexp matching loop macro keywords which introduce body forms.") + +;; Not currenctly used +(defvar common-lisp-accumlation-loop-macro-keyword + "\\(#?:\\)?\\(collect\\(ing\\)?\\|append\\(ing\\)?\\|nconc\\(ing\\)?\\|\ +count\\(ing\\)?\\|sum\\(ming\\)?\\|maximiz\\(e\\|ing\\)\\|\ +minimiz\\(e\\|ing\\)\\)" + "Regexp matching loop macro keywords which introduce accumulation clauses.") + +;; This is so "and when" and "else when" get handled right +;; (not to mention "else do" !!!) +(defvar common-lisp-prefix-loop-macro-keyword + "\\(#?:\\)?\\(and\\|else\\)" + "Regexp matching loop macro keywords which are prefixes.") + +(defvar common-lisp-indent-clause-joining-loop-macro-keyword + "\\(#?:\\)?and" + "Regexp matching 'and', and anything else there ever comes to be like it.") + +(defvar common-lisp-indent-indented-loop-macro-keyword + "\\(#?:\\)?\\(\\(up\\|down\\)?(from\\|to)\\|below\\|above\\|in\\(to\\)?\\|\ +on\\|=\\|then\\|across\\|being\\|each\\|the\\|of\\|using\\|\ +\\(present-\\|external-\\)?symbols?\\|fixnum\\|float\\|t\\|nil\\|of-type\\)" + "Regexp matching keywords introducing loop subclauses. +Always indented two.") + +(defvar common-lisp-indenting-loop-macro-keyword + "\\(#?:\\)?\\(when\\|unless\\|if\\)" + "Regexp matching keywords introducing conditional clauses. +Cause subsequent clauses to be indented.") + +(defvar common-lisp-loop-macro-else-keyword "\\(#?:\\)?else") + +;;; Attempt to indent the loop macro ... + +(defun common-lisp-indent-parse-state-depth (parse-state) + (car parse-state)) + +(defun common-lisp-indent-parse-state-start (parse-state) + (car (cdr parse-state))) + +(defun common-lisp-indent-parse-state-prev (parse-state) + (car (cdr (cdr parse-state)))) + +(defun common-lisp-loop-part-indentation (indent-point state type) + "Compute the indentation of loop form constituents." + (let* ((loop-start (elt state 1)) + (loop-indentation (save-excursion + (goto-char loop-start) + (if (eq type 'extended/split) + (- (current-column) 4) + (current-column)))) + (indent nil) + (re "\\(\\(#?:\\)?\\sw+\\|)\\|\n\\)")) + (goto-char indent-point) + (back-to-indentation) + (cond ((eq type 'simple/split) + (+ loop-indentation lisp-simple-loop-indentation)) + ((eq type 'simple) + (+ loop-indentation 6)) + ;; We are already in a body, with forms in it. + ((and (not (looking-at re)) + (save-excursion + (while (and (ignore-errors (backward-sexp) t) + (not (looking-at re))) + (setq indent (current-column))) + (when (and indent + (looking-at + common-lisp-body-introducing-loop-macro-keyword)) + t))) + (list indent loop-start)) + ;; Keyword-style or comment outside body + ((or lisp-loop-indent-forms-like-keywords + (looking-at re) + (looking-at ";")) + (if (and (looking-at ";") + (let ((p (common-lisp-trailing-comment))) + (when p + (setq loop-indentation p)))) + (list loop-indentation loop-start) + (list (+ loop-indentation 6) loop-start))) + ;; Form-style + (t + (list (+ loop-indentation 9) loop-start))))) + +(defun common-lisp-indent-loop-macro-1 (parse-state indent-point) + (catch 'return-indentation + (save-excursion + ;; Find first clause of loop macro, and use it to establish + ;; base column for indentation + (goto-char (common-lisp-indent-parse-state-start parse-state)) + (let ((loop-start-column (current-column))) + (common-lisp-loop-advance-past-keyword-on-line) + + (when (eolp) + (forward-line 1) + (end-of-line) + ;; If indenting first line after "(loop " + ;; cop out ... + (if (<= indent-point (point)) + (throw 'return-indentation (+ lisp-loop-clauses-indentation + loop-start-column))) + (back-to-indentation)) + + (let* ((case-fold-search t) + (loop-macro-first-clause (point)) + (previous-expression-start + (common-lisp-indent-parse-state-prev parse-state)) + (default-value (current-column)) + (loop-body-p nil) + (loop-body-indentation nil) + (indented-clause-indentation (+ 2 default-value))) + ;; Determine context of this loop clause, starting with the + ;; expression immediately preceding the line we're trying to indent + (goto-char previous-expression-start) + + ;; Handle a body-introducing-clause which ends a line specially. + (if (looking-at common-lisp-body-introducing-loop-macro-keyword) + (let ((keyword-position (current-column))) + (setq loop-body-p t) + (setq loop-body-indentation + (if (common-lisp-loop-advance-past-keyword-on-line) + (current-column) + (back-to-indentation) + (if (/= (current-column) keyword-position) + (+ 2 (current-column)) + (+ lisp-loop-body-forms-indentation + (if lisp-loop-indent-body-forms-relative-to-loop-start + loop-start-column + keyword-position)))))) + + (back-to-indentation) + (if (< (point) loop-macro-first-clause) + (goto-char loop-macro-first-clause)) + ;; If there's an "and" or "else," advance over it. + ;; If it is alone on the line, the next "cond" will treat it + ;; as if there were a "when" and indent under it ... + (let ((exit nil)) + (while (and (null exit) + (looking-at common-lisp-prefix-loop-macro-keyword)) + (if (null (common-lisp-loop-advance-past-keyword-on-line)) + (progn (setq exit t) + (back-to-indentation))))) + + ;; Found start of loop clause preceding the one we're + ;; trying to indent. Glean context ... + (cond + ((looking-at "(") + ;; We're in the middle of a clause body ... + (setq loop-body-p t) + (setq loop-body-indentation (current-column))) + ((looking-at common-lisp-body-introducing-loop-macro-keyword) + (setq loop-body-p t) + ;; Know there's something else on the line (or would + ;; have been caught above) + (common-lisp-loop-advance-past-keyword-on-line) + (setq loop-body-indentation (current-column))) + (t + (setq loop-body-p nil) + (if (or (looking-at common-lisp-indenting-loop-macro-keyword) + (looking-at common-lisp-prefix-loop-macro-keyword)) + (setq default-value (+ 2 (current-column)))) + (setq indented-clause-indentation (+ 2 (current-column))) + ;; We still need loop-body-indentation for "syntax errors" ... + (goto-char previous-expression-start) + (setq loop-body-indentation (current-column))))) + + ;; Go to first non-blank character of the line we're trying + ;; to indent. (if none, wind up poised on the new-line ...) + (goto-char indent-point) + (back-to-indentation) + (cond + ((looking-at "(") + ;; Clause body ... + loop-body-indentation) + ((or (eolp) (looking-at ";")) + ;; Blank line. If body-p, indent as body, else indent as + ;; vanilla clause. + (if loop-body-p + loop-body-indentation + (or (and (looking-at ";") (common-lisp-trailing-comment)) + default-value))) + ((looking-at common-lisp-indent-indented-loop-macro-keyword) + indented-clause-indentation) + ((looking-at common-lisp-indent-clause-joining-loop-macro-keyword) + (let ((stolen-indent-column nil)) + (forward-line -1) + (while (and (null stolen-indent-column) + (> (point) loop-macro-first-clause)) + (back-to-indentation) + (if (and (< (current-column) loop-body-indentation) + (looking-at "\\(#?:\\)?\\sw")) + (progn + (if (looking-at common-lisp-loop-macro-else-keyword) + (common-lisp-loop-advance-past-keyword-on-line)) + (setq stolen-indent-column + (current-column))) + (forward-line -1))) + (if stolen-indent-column + stolen-indent-column + default-value))) + (t default-value))))))) + +(defun common-lisp-loop-advance-past-keyword-on-line () + (forward-word 1) + (while (and (looking-at "\\s-") (not (eolp))) + (forward-char 1)) + (if (eolp) + nil + (current-column))) + +;;;; IF* is not standard, but a plague upon the land +;;;; ...let's at least try to indent it. + +(defvar common-lisp-indent-if*-keyword + "threnret\\|elseif\\|then\\|else" + "Regexp matching if* keywords") + +(defun common-lisp-indent-if* + (path parse-state indent-point sexp-column normal-indent) + (list (common-lisp-indent-if*-1 parse-state indent-point) + (common-lisp-indent-parse-state-start parse-state))) + +(defun common-lisp-indent-if*-1 (parse-state indent-point) + (catch 'return-indentation + (save-excursion + ;; Find first clause of if* macro, and use it to establish + ;; base column for indentation + (goto-char (common-lisp-indent-parse-state-start parse-state)) + (let ((if*-start-column (current-column))) + (common-lisp-indent-if*-advance-past-keyword-on-line) + (let* ((case-fold-search t) + (if*-first-clause (point)) + (previous-expression-start + (common-lisp-indent-parse-state-prev parse-state)) + (default-value (current-column)) + (if*-body-p nil) + (if*-body-indentation nil)) + ;; Determine context of this if* clause, starting with the + ;; expression immediately preceding the line we're trying to indent + (goto-char previous-expression-start) + ;; Handle a body-introducing-clause which ends a line specially. + (back-to-indentation) + (if (< (point) if*-first-clause) + (goto-char if*-first-clause)) + ;; Found start of if* clause preceding the one we're trying + ;; to indent. Glean context ... + (cond + ((looking-at common-lisp-indent-if*-keyword) + (setq if*-body-p t) + ;; Know there's something else on the line (or would + ;; have been caught above) + (common-lisp-indent-if*-advance-past-keyword-on-line) + (setq if*-body-indentation (current-column))) + ((looking-at "#'\\|'\\|(") + ;; We're in the middle of a clause body ... + (setq if*-body-p t) + (setq if*-body-indentation (current-column))) + (t + (setq if*-body-p nil) + ;; We still need if*-body-indentation for "syntax errors" ... + (goto-char previous-expression-start) + (setq if*-body-indentation (current-column)))) + + ;; Go to first non-blank character of the line we're trying + ;; to indent. (if none, wind up poised on the new-line ...) + (goto-char indent-point) + (back-to-indentation) + (cond + ((or (eolp) (looking-at ";")) + ;; Blank line. If body-p, indent as body, else indent as + ;; vanilla clause. + (if if*-body-p + if*-body-indentation + default-value)) + ((not (looking-at common-lisp-indent-if*-keyword)) + ;; Clause body ... + if*-body-indentation) + (t + (- (+ 7 if*-start-column) + (- (match-end 0) (match-beginning 0)))))))))) + +(defun common-lisp-indent-if*-advance-past-keyword-on-line () + (forward-word 1) + (block move-forward + (while (and (looking-at "\\s-") (not (eolp))) + (forward-char 1))) + (if (eolp) + nil + (current-column))) + + +;;;; Indentation specs for standard symbols, and a few semistandard ones. +(defun common-lisp-init-standard-indentation () + (let ((l '((block 1) + (case (4 &rest (&whole 2 &rest 1))) + (ccase (as case)) + (ecase (as case)) + (typecase (as case)) + (etypecase (as case)) + (ctypecase (as case)) + (catch 1) + (cond (&rest (&whole 2 &rest nil))) + ;; for DEFSTRUCT + (:constructor (4 &lambda)) + (defvar (4 2 2)) + (defclass (6 (&whole 4 &rest 1) + (&whole 2 &rest 1) + (&whole 2 &rest 1))) + (defconstant (as defvar)) + (defcustom (4 2 2 2)) + (defparameter (as defvar)) + (defconst (as defcustom)) + (define-condition (as defclass)) + (define-modify-macro (4 &lambda &body)) + (defsetf lisp-indent-defsetf) + (defun (4 &lambda &body)) + (defgeneric (4 &lambda &body)) + (define-setf-method (as defun)) + (define-setf-expander (as defun)) + (defmacro (as defun)) + (defsubst (as defun)) + (deftype (as defun)) + (defmethod lisp-indent-defmethod) + (defpackage (4 2)) + (defstruct ((&whole 4 &rest (&whole 2 &rest 1)) + &rest (&whole 2 &rest 1))) + (destructuring-bind (&lambda 4 &body)) + (do lisp-indent-do) + (do* (as do)) + (dolist ((&whole 4 2 1) &body)) + (dotimes (as dolist)) + (eval-when 1) + (flet ((&whole 4 &rest (&whole 1 4 &lambda &body)) &body)) + (labels (as flet)) + (macrolet (as flet)) + (generic-flet (as flet)) + (generic-labels (as flet)) + (handler-case (4 &rest (&whole 2 &lambda &body))) + (restart-case (as handler-case)) + ;; single-else style (then and else equally indented) + (if (&rest nil)) + (if* common-lisp-indent-if*) + (lambda (&lambda &rest lisp-indent-function-lambda-hack)) + (let ((&whole 4 &rest (&whole 1 1 2)) &body)) + (let* (as let)) + (compiler-let (as let)) + (handler-bind (as let)) + (restart-bind (as let)) + (locally 1) + (loop lisp-indent-loop) + (:method lisp-indent-defmethod) ; in `defgeneric' + (multiple-value-bind ((&whole 6 &rest 1) 4 &body)) + (multiple-value-call (4 &body)) + (multiple-value-prog1 1) + (multiple-value-setq (4 2)) + (multiple-value-setf (as multiple-value-setq)) + (named-lambda (4 &lambda &rest lisp-indent-function-lambda-hack)) + (pprint-logical-block (4 2)) + (print-unreadable-object ((&whole 4 1 &rest 1) &body)) + ;; Combines the worst features of BLOCK, LET and TAGBODY + (prog (&lambda &rest lisp-indent-tagbody)) + (prog* (as prog)) + (prog1 1) + (prog2 2) + (progn 0) + (progv (4 4 &body)) + (return 0) + (return-from (nil &body)) + (symbol-macrolet (as let)) + (tagbody lisp-indent-tagbody) + (throw 1) + (unless 1) + (unwind-protect (5 &body)) + (when 1) + (with-accessors (as multiple-value-bind)) + (with-compilation-unit ((&whole 4 &rest 1) &body)) + (with-condition-restarts (as multiple-value-bind)) + (with-output-to-string (4 2)) + (with-slots (as multiple-value-bind)) + (with-standard-io-syntax (2))))) + (dolist (el l) + (let* ((name (car el)) + (spec (cdr el)) + (indentation + (if (symbolp spec) + (error "Old style indirect indentation spec: %s" el) + (when (cdr spec) + (error "Malformed indentation specification: %s" el)) + (car spec)))) + (unless (symbolp name) + (error "Cannot set Common Lisp indentation of a non-symbol: %s" + name)) + (put name 'common-lisp-indent-function indentation))))) +(common-lisp-init-standard-indentation) + +(provide 'cl-indent) +(provide 'slime-cl-indent) + +;;; slime-cl-indent.el ends here diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-clipboard.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-clipboard.el new file mode 100644 index 0000000..4f5dd17 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-clipboard.el @@ -0,0 +1,172 @@ +(require 'slime) +(require 'slime-repl) +(require 'cl-lib) +(eval-when-compile + (require 'cl)) ; lexical-let + +(define-slime-contrib slime-clipboard + "This add a few commands to put objects into a clipboard and to +insert textual references to those objects. + +The clipboard command prefix is C-c @. + + C-c @ + adds an object to the clipboard + C-c @ @ inserts a reference to an object in the clipboard + C-c @ ? displays the clipboard + +This package also also binds the + key in the inspector and +debugger to add the object at point to the clipboard." + (:authors "Helmut Eller ") + (:license "GPL") + (:swank-dependencies swank-clipboard)) + +(define-derived-mode slime-clipboard-mode fundamental-mode + "Slime-Clipboard" + "SLIME Clipboad Mode. + +\\{slime-clipboard-mode-map}") + +(slime-define-keys slime-clipboard-mode-map + ("g" 'slime-clipboard-redisplay) + ((kbd "C-k") 'slime-clipboard-delete-entry) + ("i" 'slime-clipboard-inspect)) + +(defvar slime-clipboard-map (make-sparse-keymap)) + +(slime-define-keys slime-clipboard-map + ("?" 'slime-clipboard-display) + ("+" 'slime-clipboard-add) + ("@" 'slime-clipboard-ref)) + +(define-key slime-mode-map (kbd "C-c @") slime-clipboard-map) +(define-key slime-repl-mode-map (kbd "C-c @") slime-clipboard-map) + +(slime-define-keys slime-inspector-mode-map + ("+" 'slime-clipboard-add-from-inspector)) + +(slime-define-keys sldb-mode-map + ("+" 'slime-clipboard-add-from-sldb)) + +(defun slime-clipboard-add (exp package) + "Add an object to the clipboard." + (interactive (list (slime-read-from-minibuffer + "Add to clipboard (evaluated): " + (slime-sexp-at-point)) + (slime-current-package))) + (slime-clipboard-add-internal `(:string ,exp ,package))) + +(defun slime-clipboard-add-internal (datum) + (slime-eval-async `(swank-clipboard:add ',datum) + (lambda (result) (message "%s" result)))) + +(defun slime-clipboard-display () + "Display the content of the clipboard." + (interactive) + (slime-eval-async `(swank-clipboard:entries) + #'slime-clipboard-display-entries)) + +(defun slime-clipboard-display-entries (entries) + (slime-with-popup-buffer ((slime-buffer-name :clipboard) + :mode 'slime-clipboard-mode) + (slime-clipboard-insert-entries entries))) + +(defun slime-clipboard-insert-entries (entries) + (let ((fstring "%2s %3s %s\n")) + (insert (format fstring "Nr" "Id" "Value") + (format fstring "--" "--" "-----" )) + (save-excursion + (cl-loop for i from 0 for (ref . value) in entries do + (slime-insert-propertized `(slime-clipboard-entry ,i + slime-clipboard-ref ,ref) + (format fstring i ref value)))))) + +(defun slime-clipboard-redisplay () + "Update the clipboard buffer." + (interactive) + (lexical-let ((saved (point))) + (slime-eval-async + `(swank-clipboard:entries) + (lambda (entries) + (let ((inhibit-read-only t)) + (erase-buffer) + (slime-clipboard-insert-entries entries) + (when (< saved (point-max)) + (goto-char saved))))))) + +(defun slime-clipboard-entry-at-point () + (or (get-text-property (point) 'slime-clipboard-entry) + (error "No clipboard entry at point"))) + +(defun slime-clipboard-ref-at-point () + (or (get-text-property (point) 'slime-clipboard-ref) + (error "No clipboard ref at point"))) + +(defun slime-clipboard-inspect (&optional entry) + "Inspect the current clipboard entry." + (interactive (list (slime-clipboard-ref-at-point))) + (slime-inspect (prin1-to-string `(swank-clipboard::clipboard-ref ,entry)))) + +(defun slime-clipboard-delete-entry (&optional entry) + "Delete the current entry from the clipboard." + (interactive (list (slime-clipboard-entry-at-point))) + (slime-eval-async `(swank-clipboard:delete-entry ,entry) + (lambda (result) + (slime-clipboard-redisplay) + (message "%s" result)))) + +(defun slime-clipboard-ref () + "Ask for a clipboard entry number and insert a reference to it." + (interactive) + (slime-clipboard-read-entry-number #'slime-clipboard-insert-ref)) + +;; insert a reference to clipboard entry ENTRY at point. The text +;; receives a special 'display property to make it look nicer. We +;; remove this property in a modification when a user tries to modify +;; he real text. +(defun slime-clipboard-insert-ref (entry) + (cl-destructuring-bind (ref . string) + (slime-eval `(swank-clipboard:entry-to-ref ,entry)) + (slime-insert-propertized + `(display ,(format "#@%d%s" ref string) + modification-hooks (slime-clipboard-ref-modified) + rear-nonsticky t) + (format "(swank-clipboard::clipboard-ref %d)" ref)))) + +(defun slime-clipboard-ref-modified (start end) + (when (get-text-property start 'display) + (let ((inhibit-modification-hooks t)) + (save-excursion + (goto-char start) + (cl-destructuring-bind (dstart dend) (slime-property-bounds 'display) + (unless (and (= start dstart) (= end dend)) + (remove-list-of-text-properties + dstart dend '(display modification-hooks)))))))) + +;; Read a entry number. +;; Written in CPS because the display the clipboard before reading. +(defun slime-clipboard-read-entry-number (k) + (slime-eval-async + `(swank-clipboard:entries) + (slime-rcurry + (lambda (entries window-config k) + (slime-clipboard-display-entries entries) + (let ((entry (unwind-protect + (read-from-minibuffer "Entry number: " nil nil t) + (set-window-configuration window-config)))) + (funcall k entry))) + (current-window-configuration) + k))) + +(defun slime-clipboard-add-from-inspector () + (interactive) + (let ((part (or (get-text-property (point) 'slime-part-number) + (error "No part at point")))) + (slime-clipboard-add-internal `(:inspector ,part)))) + +(defun slime-clipboard-add-from-sldb () + (interactive) + (slime-clipboard-add-internal + `(:sldb ,(sldb-frame-number-at-point) + ,(sldb-var-number-at-point)))) + +(provide 'slime-clipboard) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-compiler-notes-tree.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-compiler-notes-tree.el new file mode 100644 index 0000000..bada587 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-compiler-notes-tree.el @@ -0,0 +1,184 @@ +(require 'slime) +(require 'cl-lib) + +(define-slime-contrib slime-compiler-notes-tree + "Display compiler messages in tree layout. + +M-x slime-list-compiler-notes display the compiler notes in a tree +grouped by severity. + + `slime-maybe-list-compiler-notes' can be used as + `slime-compilation-finished-hook'. +" + (:authors "Helmut Eller ") + (:license "GPL")) + +(defun slime-maybe-list-compiler-notes (notes) + "Show the compiler notes if appropriate." + ;; don't pop up a buffer if all notes are already annotated in the + ;; buffer itself + (unless (cl-every #'slime-note-has-location-p notes) + (slime-list-compiler-notes notes))) + +(defun slime-list-compiler-notes (notes) + "Show the compiler notes NOTES in tree view." + (interactive (list (slime-compiler-notes))) + (with-temp-message "Preparing compiler note tree..." + (slime-with-popup-buffer ((slime-buffer-name :notes) + :mode 'slime-compiler-notes-mode) + (when (null notes) + (insert "[no notes]")) + (let ((collapsed-p)) + (dolist (tree (slime-compiler-notes-to-tree notes)) + (when (slime-tree.collapsed-p tree) (setf collapsed-p t)) + (slime-tree-insert tree "") + (insert "\n")) + (goto-char (point-min)))))) + +(defvar slime-tree-printer 'slime-tree-default-printer) + +(defun slime-tree-for-note (note) + (make-slime-tree :item (slime-note.message note) + :plist (list 'note note) + :print-fn slime-tree-printer)) + +(defun slime-tree-for-severity (severity notes collapsed-p) + (make-slime-tree :item (format "%s (%d)" + (slime-severity-label severity) + (length notes)) + :kids (mapcar #'slime-tree-for-note notes) + :collapsed-p collapsed-p)) + +(defun slime-compiler-notes-to-tree (notes) + (let* ((alist (slime-alistify notes #'slime-note.severity #'eq)) + (collapsed-p (slime-length> alist 1))) + (cl-loop for (severity . notes) in alist + collect (slime-tree-for-severity severity notes + collapsed-p)))) + +(defvar slime-compiler-notes-mode-map) + +(define-derived-mode slime-compiler-notes-mode fundamental-mode + "Compiler-Notes" + "\\\ +\\{slime-compiler-notes-mode-map} +\\{slime-popup-buffer-mode-map} +" + (slime-set-truncate-lines)) + +(slime-define-keys slime-compiler-notes-mode-map + ((kbd "RET") 'slime-compiler-notes-default-action-or-show-details) + ([return] 'slime-compiler-notes-default-action-or-show-details) + ([mouse-2] 'slime-compiler-notes-default-action-or-show-details/mouse)) + +(defun slime-compiler-notes-default-action-or-show-details/mouse (event) + "Invoke the action pointed at by the mouse, or show details." + (interactive "e") + (cl-destructuring-bind (mouse-2 (w pos &rest _) &rest __) event + (save-excursion + (goto-char pos) + (let ((fn (get-text-property (point) + 'slime-compiler-notes-default-action))) + (if fn (funcall fn) (slime-compiler-notes-show-details)))))) + +(defun slime-compiler-notes-default-action-or-show-details () + "Invoke the action at point, or show details." + (interactive) + (let ((fn (get-text-property (point) 'slime-compiler-notes-default-action))) + (if fn (funcall fn) (slime-compiler-notes-show-details)))) + +(defun slime-compiler-notes-show-details () + (interactive) + (let* ((tree (slime-tree-at-point)) + (note (plist-get (slime-tree.plist tree) 'note)) + (inhibit-read-only t)) + (cond ((not (slime-tree-leaf-p tree)) + (slime-tree-toggle tree)) + (t + (slime-show-source-location (slime-note.location note) t))))) + + +;;;;;; Tree Widget + +(cl-defstruct (slime-tree (:conc-name slime-tree.)) + item + (print-fn #'slime-tree-default-printer :type function) + (kids '() :type list) + (collapsed-p t :type boolean) + (prefix "" :type string) + (start-mark nil) + (end-mark nil) + (plist '() :type list)) + +(defun slime-tree-leaf-p (tree) + (not (slime-tree.kids tree))) + +(defun slime-tree-default-printer (tree) + (princ (slime-tree.item tree) (current-buffer))) + +(defun slime-tree-decoration (tree) + (cond ((slime-tree-leaf-p tree) "-- ") + ((slime-tree.collapsed-p tree) "[+] ") + (t "-+ "))) + +(defun slime-tree-insert-list (list prefix) + "Insert a list of trees." + (cl-loop for (elt . rest) on list + do (cond (rest + (insert prefix " |") + (slime-tree-insert elt (concat prefix " |")) + (insert "\n")) + (t + (insert prefix " `") + (slime-tree-insert elt (concat prefix " ")))))) + +(defun slime-tree-insert-decoration (tree) + (insert (slime-tree-decoration tree))) + +(defun slime-tree-indent-item (start end prefix) + "Insert PREFIX at the beginning of each but the first line. +This is used for labels spanning multiple lines." + (save-excursion + (goto-char end) + (beginning-of-line) + (while (< start (point)) + (insert-before-markers prefix) + (forward-line -1)))) + +(defun slime-tree-insert (tree prefix) + "Insert TREE prefixed with PREFIX at point." + (with-struct (slime-tree. print-fn kids collapsed-p start-mark end-mark) tree + (let ((line-start (line-beginning-position))) + (setf start-mark (point-marker)) + (slime-tree-insert-decoration tree) + (funcall print-fn tree) + (slime-tree-indent-item start-mark (point) (concat prefix " ")) + (add-text-properties line-start (point) (list 'slime-tree tree)) + (set-marker-insertion-type start-mark t) + (when (and kids (not collapsed-p)) + (terpri (current-buffer)) + (slime-tree-insert-list kids prefix)) + (setf (slime-tree.prefix tree) prefix) + (setf end-mark (point-marker))))) + +(defun slime-tree-at-point () + (cond ((get-text-property (point) 'slime-tree)) + (t (error "No tree at point")))) + +(defun slime-tree-delete (tree) + "Delete the region for TREE." + (delete-region (slime-tree.start-mark tree) + (slime-tree.end-mark tree))) + +(defun slime-tree-toggle (tree) + "Toggle the visibility of TREE's children." + (with-struct (slime-tree. collapsed-p start-mark end-mark prefix) tree + (setf collapsed-p (not collapsed-p)) + (slime-tree-delete tree) + (insert-before-markers " ") ; move parent's end-mark + (backward-char 1) + (slime-tree-insert tree prefix) + (delete-char 1) + (goto-char start-mark))) + +(provide 'slime-compiler-notes-tree) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-editing-commands.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-editing-commands.el new file mode 100644 index 0000000..db7bb01 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-editing-commands.el @@ -0,0 +1,183 @@ +(require 'slime) +(require 'slime-repl) +(require 'cl-lib) + +(define-slime-contrib slime-editing-commands + "Editing commands without server interaction." + (:authors "Thomas F. Burdick " + "Luke Gorrie " + "Bill Clementson " + "Tobias C. Rittweiler ") + (:license "GPL") + (:on-load + (define-key slime-mode-map "\M-\C-a" 'slime-beginning-of-defun) + (define-key slime-mode-map "\M-\C-e" 'slime-end-of-defun) + (define-key slime-mode-map "\C-c\M-q" 'slime-reindent-defun) + (define-key slime-mode-map "\C-c\C-]" 'slime-close-all-parens-in-sexp))) + +(defun slime-beginning-of-defun () + (interactive) + (if (and (boundp 'slime-repl-input-start-mark) + slime-repl-input-start-mark) + (slime-repl-beginning-of-defun) + (let ((this-command 'beginning-of-defun)) ; needed for push-mark + (call-interactively 'beginning-of-defun)))) + +(defun slime-end-of-defun () + (interactive) + (if (eq major-mode 'slime-repl-mode) + (slime-repl-end-of-defun) + (end-of-defun))) + +(defvar slime-comment-start-regexp + "\\(\\(^\\|[^\n\\\\]\\)\\([\\\\][\\\\]\\)*\\);+[ \t]*" + "Regexp to match the start of a comment.") + +(defun slime-beginning-of-comment () + "Move point to beginning of comment. +If point is inside a comment move to beginning of comment and return point. +Otherwise leave point unchanged and return NIL." + (let ((boundary (point))) + (beginning-of-line) + (cond ((re-search-forward slime-comment-start-regexp boundary t) + (point)) + (t (goto-char boundary) + nil)))) + +(defvar slime-close-parens-limit nil + "Maxmimum parens for `slime-close-all-sexp' to insert. NIL +means to insert as many parentheses as necessary to correctly +close the form.") + +(defun slime-close-all-parens-in-sexp (&optional region) + "Balance parentheses of open s-expressions at point. +Insert enough right parentheses to balance unmatched left parentheses. +Delete extra left parentheses. Reformat trailing parentheses +Lisp-stylishly. + +If REGION is true, operate on the region. Otherwise operate on +the top-level sexp before point." + (interactive "P") + (let ((sexp-level 0) + point) + (save-excursion + (save-restriction + (when region + (narrow-to-region (region-beginning) (region-end)) + (goto-char (point-max))) + ;; skip over closing parens, but not into comment + (skip-chars-backward ") \t\n") + (when (slime-beginning-of-comment) + (forward-line) + (skip-chars-forward " \t")) + (setq point (point)) + ;; count sexps until either '(' or comment is found at first column + (while (and (not (looking-at "^[(;]")) + (ignore-errors (backward-up-list 1) t)) + (incf sexp-level)))) + (when (> sexp-level 0) + ;; insert correct number of right parens + (goto-char point) + (dotimes (i sexp-level) (insert ")")) + ;; delete extra right parens + (setq point (point)) + (skip-chars-forward " \t\n)") + (skip-chars-backward " \t\n") + (let* ((deleted-region (delete-and-extract-region point (point))) + (deleted-text (substring-no-properties deleted-region)) + (prior-parens-count (cl-count ?\) deleted-text))) + ;; Remember: we always insert as many parentheses as necessary + ;; and only afterwards delete the superfluously-added parens. + (when slime-close-parens-limit + (let ((missing-parens (- sexp-level prior-parens-count + slime-close-parens-limit))) + (dotimes (i (max 0 missing-parens)) + (delete-char -1)))))))) + +(defun slime-insert-balanced-comments (arg) + "Insert a set of balanced comments around the s-expression +containing the point. If this command is invoked repeatedly +\(without any other command occurring between invocations), the +comment progressively moves outward over enclosing expressions. +If invoked with a positive prefix argument, the s-expression arg +expressions out is enclosed in a set of balanced comments." + (interactive "*p") + (save-excursion + (when (eq last-command this-command) + (when (search-backward "#|" nil t) + (save-excursion + (delete-char 2) + (while (and (< (point) (point-max)) (not (looking-at " *|#"))) + (forward-sexp)) + (replace-match "")))) + (while (> arg 0) + (backward-char 1) + (cond ((looking-at ")") (incf arg)) + ((looking-at "(") (decf arg)))) + (insert "#|") + (forward-sexp) + (insert "|#"))) + +(defun slime-remove-balanced-comments () + "Remove a set of balanced comments enclosing point." + (interactive "*") + (save-excursion + (when (search-backward "#|" nil t) + (delete-char 2) + (while (and (< (point) (point-max)) (not (looking-at " *|#"))) + (forward-sexp)) + (replace-match "")))) + + +;; SLIME-CLOSE-PARENS-AT-POINT is obsolete: + +;; It doesn't work correctly on the REPL, because there +;; BEGINNING-OF-DEFUN-FUNCTION and END-OF-DEFUN-FUNCTION is bound to +;; SLIME-REPL-MODE-BEGINNING-OF-DEFUN (and +;; SLIME-REPL-MODE-END-OF-DEFUN respectively) which compromises the +;; way how they're expect to work (i.e. END-OF-DEFUN does not signal +;; an UNBOUND-PARENTHESES error.) + +;; Use SLIME-CLOSE-ALL-PARENS-IN-SEXP instead. + +;; (defun slime-close-parens-at-point () +;; "Close parenthesis at point to complete the top-level-form. Simply +;; inserts ')' characters at point until `beginning-of-defun' and +;; `end-of-defun' execute without errors, or `slime-close-parens-limit' +;; is exceeded." +;; (interactive) +;; (loop for i from 1 to slime-close-parens-limit +;; until (save-excursion +;; (slime-beginning-of-defun) +;; (ignore-errors (slime-end-of-defun) t)) +;; do (insert ")"))) + +(defun slime-reindent-defun (&optional force-text-fill) + "Reindent the current defun, or refill the current paragraph. +If point is inside a comment block, the text around point will be +treated as a paragraph and will be filled with `fill-paragraph'. +Otherwise, it will be treated as Lisp code, and the current defun +will be reindented. If the current defun has unbalanced parens, +an attempt will be made to fix it before reindenting. + +When given a prefix argument, the text around point will always +be treated as a paragraph. This is useful for filling docstrings." + (interactive "P") + (save-excursion + (if (or force-text-fill (slime-beginning-of-comment)) + (fill-paragraph nil) + (let ((start (progn (unless (or (and (zerop (current-column)) + (eq ?\( (char-after))) + (and slime-repl-input-start-mark + (slime-repl-at-prompt-start-p))) + (slime-beginning-of-defun)) + (point))) + (end (ignore-errors (slime-end-of-defun) (point)))) + (unless end + (forward-paragraph) + (slime-close-all-parens-in-sexp) + (slime-end-of-defun) + (setf end (point))) + (indent-region start end nil))))) + +(provide 'slime-editing-commands) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-enclosing-context.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-enclosing-context.el new file mode 100644 index 0000000..53cee76 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-enclosing-context.el @@ -0,0 +1,226 @@ +(require 'slime) +(require 'slime-parse) +(require 'cl-lib) + +(define-slime-contrib slime-enclosing-context + "Utilities on top of slime-parse." + (:authors "Tobias C. Rittweiler ") + (:license "GPL")) + +(defun slime-parse-sexp-at-point (&optional n) + "Returns the sexps at point as a list of strings, otherwise nil. +\(If there are not as many sexps as N, a list with < N sexps is +returned.\) +If SKIP-BLANKS-P is true, leading whitespaces &c are skipped. +" + (interactive "p") (or n (setq n 1)) + (save-excursion + (let ((result nil)) + (dotimes (i n) + ;; Is there an additional sexp in front of us? + (save-excursion + (unless (slime-point-moves-p (ignore-errors (forward-sexp))) + (cl-return))) + (push (slime-sexp-at-point) result) + ;; Skip current sexp + (ignore-errors (forward-sexp) (skip-chars-forward "[:space:]"))) + (nreverse result)))) + +(defun slime-has-symbol-syntax-p (string) + (if (and string (not (zerop (length string)))) + (member (char-syntax (aref string 0)) + '(?w ?_ ?\' ?\\)))) + +(defun slime-beginning-of-string () + (let* ((parser-state (slime-current-parser-state)) + (inside-string-p (nth 3 parser-state)) + (string-start-pos (nth 8 parser-state))) + (if inside-string-p + (goto-char string-start-pos) + (error "We're not within a string")))) + +(defun slime-enclosing-form-specs (&optional max-levels) + "Return the list of ``raw form specs'' of all the forms +containing point from right to left. + +As a secondary value, return a list of indices: Each index tells +for each corresponding form spec in what argument position the +user's point is. + +As tertiary value, return the positions of the operators that are +contained in the returned form specs. + +When MAX-LEVELS is non-nil, go up at most this many levels of +parens. + +\(See SWANK::PARSE-FORM-SPEC for more information about what +exactly constitutes a ``raw form specs'') + +Examples: + + A return value like the following + + (values ((\"quux\") (\"bar\") (\"foo\")) (3 2 1) (p1 p2 p3)) + + can be interpreted as follows: + + The user point is located in the 3rd argument position of a + form with the operator name \"quux\" (which starts at P1.) + + This form is located in the 2nd argument position of a form + with the operator name \"bar\" (which starts at P2.) + + This form again is in the 1st argument position of a form + with the operator name \"foo\" (which itself begins at P3.) + + For instance, the corresponding buffer content could have looked + like `(foo (bar arg1 (quux 1 2 |' where `|' denotes point. +" + (let ((level 1) + (parse-sexp-lookup-properties nil) + (initial-point (point)) + (result '()) (arg-indices '()) (points '())) + ;; The expensive lookup of syntax-class text properties is only + ;; used for interactive balancing of #<...> in presentations; we + ;; do not need them in navigating through the nested lists. + ;; This speeds up this function significantly. + (ignore-errors + (save-excursion + ;; Make sure we get the whole thing at point. + (if (not (slime-inside-string-p)) + (slime-end-of-symbol) + (slime-beginning-of-string) + (forward-sexp)) + (save-restriction + ;; Don't parse more than 20000 characters before point, so we don't spend + ;; too much time. + (narrow-to-region (max (point-min) (- (point) 20000)) (point-max)) + (narrow-to-region (save-excursion (beginning-of-defun) (point)) + (min (1+ (point)) (point-max))) + (while (or (not max-levels) + (<= level max-levels)) + (let ((arg-index 0)) + ;; Move to the beginning of the current sexp if not already there. + (if (or (and (char-after) + (member (char-syntax (char-after)) '(?\( ?'))) + (member (char-syntax (char-before)) '(?\ ?>))) + (cl-incf arg-index)) + (ignore-errors (backward-sexp 1)) + (while (and (< arg-index 64) + (ignore-errors (backward-sexp 1) + (> (point) (point-min)))) + (cl-incf arg-index)) + (backward-up-list 1) + (when (member (char-syntax (char-after)) '(?\( ?')) + (cl-incf level) + (forward-char 1) + (let ((name (slime-symbol-at-point))) + (push (and name `(,name)) result) + (push arg-index arg-indices) + (push (point) points)) + (backward-up-list 1))))))) + (cl-values + (nreverse result) + (nreverse arg-indices) + (nreverse points)))) + +(defvar slime-variable-binding-ops-alist + '((let &bindings &body) + (let* &bindings &body))) + +(defvar slime-function-binding-ops-alist + '((flet &bindings &body) + (labels &bindings &body) + (macrolet &bindings &body))) + +(defun slime-lookup-binding-op (op &optional binding-type) + (cl-labels ((lookup-in (list) (cl-assoc op list :test 'cl-equalp :key 'symbol-name))) + (cond ((eq binding-type :variable) (lookup-in slime-variable-binding-ops-alist)) + ((eq binding-type :function) (lookup-in slime-function-binding-ops-alist)) + (t (or (lookup-in slime-variable-binding-ops-alist) + (lookup-in slime-function-binding-ops-alist)))))) + +(defun slime-binding-op-p (op &optional binding-type) + (and (slime-lookup-binding-op op binding-type) t)) + +(defun slime-binding-op-body-pos (op) + (let ((special-lambda-list (slime-lookup-binding-op op))) + (if special-lambda-list (cl-position '&body special-lambda-list)))) + +(defun slime-binding-op-bindings-pos (op) + (let ((special-lambda-list (slime-lookup-binding-op op))) + (if special-lambda-list (cl-position '&bindings special-lambda-list)))) + +(defun slime-enclosing-bound-names () + "Returns all bound function names as first value, and the +points where their bindings are established as second value." + (cl-multiple-value-call #'slime-find-bound-names + (slime-enclosing-form-specs))) + +(defun slime-find-bound-names (ops indices points) + (let ((binding-names) (binding-start-points)) + (save-excursion + (cl-loop for (op . nil) in ops + for index in indices + for point in points + do (when (and (slime-binding-op-p op) + ;; Are the bindings of OP in scope? + (>= index (slime-binding-op-body-pos op))) + (goto-char point) + (forward-sexp (slime-binding-op-bindings-pos op)) + (down-list) + (ignore-errors + (cl-loop + (down-list) + (push (slime-symbol-at-point) binding-names) + (push (save-excursion (backward-up-list) (point)) + binding-start-points) + (up-list))))) + (cl-values (nreverse binding-names) (nreverse binding-start-points))))) + + +(defun slime-enclosing-bound-functions () + (cl-multiple-value-call #'slime-find-bound-functions + (slime-enclosing-form-specs))) + +(defun slime-find-bound-functions (ops indices points) + (let ((names) (arglists) (start-points)) + (save-excursion + (cl-loop for (op . nil) in ops + for index in indices + for point in points + do (when (and (slime-binding-op-p op :function) + ;; Are the bindings of OP in scope? + (>= index (slime-binding-op-body-pos op))) + (goto-char point) + (forward-sexp (slime-binding-op-bindings-pos op)) + (down-list) + ;; If we're at the end of the bindings, an error will + ;; be signalled by the `down-list' below. + (ignore-errors + (cl-loop + (down-list) + (cl-destructuring-bind (name arglist) + (slime-parse-sexp-at-point 2) + (cl-assert (slime-has-symbol-syntax-p name)) + (cl-assert arglist) + (push name names) + (push arglist arglists) + (push (save-excursion (backward-up-list) (point)) + start-points)) + (up-list))))) + (cl-values (nreverse names) + (nreverse arglists) + (nreverse start-points))))) + + +(defun slime-enclosing-bound-macros () + (cl-multiple-value-call #'slime-find-bound-macros + (slime-enclosing-form-specs))) + +(defun slime-find-bound-macros (ops indices points) + ;; Kludgy! + (let ((slime-function-binding-ops-alist '((macrolet &bindings &body)))) + (slime-find-bound-functions ops indices points))) + +(provide 'slime-enclosing-context) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-fancy-inspector.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-fancy-inspector.el new file mode 100644 index 0000000..02d0131 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-fancy-inspector.el @@ -0,0 +1,42 @@ +(eval-and-compile + (require 'slime)) + +(define-slime-contrib slime-fancy-inspector + "Fancy inspector for CLOS objects." + (:authors "Marco Baringer and others") + (:license "GPL") + (:slime-dependencies slime-parse) + (:swank-dependencies swank-fancy-inspector) + (:on-load + (add-hook 'slime-edit-definition-hooks 'slime-edit-inspector-part)) + (:on-unload + (remove-hook 'slime-edit-definition-hooks 'slime-edit-inspector-part))) + +(defun slime-inspect-definition () + "Inspect definition at point" + (interactive) + (slime-inspect (slime-definition-at-point))) + +(defun slime-disassemble-definition () + "Disassemble definition at point" + (interactive) + (slime-eval-describe `(swank:disassemble-form + ,(slime-definition-at-point t)))) + +(defun slime-edit-inspector-part (name &optional where) + (and (eq major-mode 'slime-inspector-mode) + (cl-destructuring-bind (&optional property value) + (slime-inspector-property-at-point) + (when (eq property 'slime-part-number) + (let ((location (slime-eval `(swank:find-definition-for-thing + (swank:inspector-nth-part ,value)))) + (name (format "Inspector part %s" value))) + (when (and (consp location) + (not (eq (car location) :error))) + (slime-edit-definition-cont + (list (make-slime-xref :dspec `(,name) + :location location)) + name + where))))))) + +(provide 'slime-fancy-inspector) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-fancy-trace.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-fancy-trace.el new file mode 100644 index 0000000..06a1fab --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-fancy-trace.el @@ -0,0 +1,68 @@ +(eval-and-compile + (require 'slime)) + +(define-slime-contrib slime-fancy-trace + "Enhanced version of slime-trace capable of tracing local functions, +methods, setf functions, and other entities supported by specific +swank:swank-toggle-trace backends. Invoke via C-u C-t." + (:authors "Matthias Koeppe " + "Tobias C. Rittweiler ") + (:license "GPL") + (:slime-dependencies slime-parse)) + +(defun slime-trace-query (spec) + "Ask the user which function to trace; SPEC is the default. +The result is a string." + (cond ((null spec) + (slime-read-from-minibuffer "(Un)trace: ")) + ((stringp spec) + (slime-read-from-minibuffer "(Un)trace: " spec)) + ((symbolp spec) ; `slime-extract-context' can return symbols. + (slime-read-from-minibuffer "(Un)trace: " (prin1-to-string spec))) + (t + (slime-dcase spec + ((setf n) + (slime-read-from-minibuffer "(Un)trace: " (prin1-to-string spec))) + ((:defun n) + (slime-read-from-minibuffer "(Un)trace: " (prin1-to-string n))) + ((:defgeneric n) + (let* ((name (prin1-to-string n)) + (answer (slime-read-from-minibuffer "(Un)trace: " name))) + (cond ((and (string= name answer) + (y-or-n-p (concat "(Un)trace also all " + "methods implementing " + name "? "))) + (prin1-to-string `(:defgeneric ,n))) + (t + answer)))) + ((:defmethod &rest _) + (slime-read-from-minibuffer "(Un)trace: " (prin1-to-string spec))) + ((:call caller callee) + (let* ((callerstr (prin1-to-string caller)) + (calleestr (prin1-to-string callee)) + (answer (slime-read-from-minibuffer "(Un)trace: " + calleestr))) + (cond ((and (string= calleestr answer) + (y-or-n-p (concat "(Un)trace only when " calleestr + " is called by " callerstr "? "))) + (prin1-to-string `(:call ,caller ,callee))) + (t + answer)))) + (((:labels :flet) &rest _) + (slime-read-from-minibuffer "(Un)trace local function: " + (prin1-to-string spec))) + (t (error "Don't know how to trace the spec %S" spec)))))) + +(defun slime-toggle-fancy-trace (&optional using-context-p) + "Toggle trace." + (interactive "P") + (let* ((spec (if using-context-p + (slime-extract-context) + (slime-symbol-at-point))) + (spec (slime-trace-query spec))) + (message "%s" (slime-eval `(swank:swank-toggle-trace ,spec))))) + +;; override slime-toggle-trace-fdefinition +(define-key slime-prefix-map "\C-t" 'slime-toggle-fancy-trace) + +(provide 'slime-fancy-trace) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-fancy.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-fancy.el new file mode 100644 index 0000000..5aba81c --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-fancy.el @@ -0,0 +1,38 @@ +(require 'slime) + +(define-slime-contrib slime-fancy + "Make SLIME fancy." + (:authors "Matthias Koeppe " + "Tobias C Rittweiler ") + (:license "GPL") + (:slime-dependencies slime-repl + slime-autodoc + slime-c-p-c + slime-editing-commands + slime-fancy-inspector + slime-fancy-trace + slime-fuzzy + slime-mdot-fu + slime-macrostep + slime-presentations + slime-scratch + slime-references + slime-package-fu + slime-fontifying-fu + slime-trace-dialog) + (:on-load + (slime-trace-dialog-init) + (slime-repl-init) + (slime-autodoc-init) + (slime-c-p-c-init) + (slime-editing-commands-init) + (slime-fancy-inspector-init) + (slime-fancy-trace-init) + (slime-fuzzy-init) + (slime-presentations-init) + (slime-scratch-init) + (slime-references-init) + (slime-package-fu-init) + (slime-fontifying-fu-init))) + +(provide 'slime-fancy) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-fontifying-fu.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-fontifying-fu.el new file mode 100644 index 0000000..42de251 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-fontifying-fu.el @@ -0,0 +1,231 @@ +(require 'slime) +(require 'slime-parse) +(require 'slime-autodoc) +(require 'font-lock) +(require 'cl-lib) + +;;; Fontify WITH-FOO, DO-FOO, and DEFINE-FOO like standard macros. +;;; Fontify CHECK-FOO like CHECK-TYPE. +(defvar slime-additional-font-lock-keywords + '(("(\\(\\(\\s_\\|\\w\\)*:\\(define-\\|do-\\|with-\\|without-\\)\\(\\s_\\|\\w\\)*\\)" 1 font-lock-keyword-face) + ("(\\(\\(define-\\|do-\\|with-\\)\\(\\s_\\|\\w\\)*\\)" 1 font-lock-keyword-face) + ("(\\(check-\\(\\s_\\|\\w\\)*\\)" 1 font-lock-warning-face) + ("(\\(assert-\\(\\s_\\|\\w\\)*\\)" 1 font-lock-warning-face))) + +;;;; Specially fontify forms suppressed by a reader conditional. +(defcustom slime-highlight-suppressed-forms t + "Display forms disabled by reader conditionals as comments." + :type '(choice (const :tag "Enable" t) (const :tag "Disable" nil)) + :group 'slime-mode) + +(define-slime-contrib slime-fontifying-fu + "Additional fontification tweaks: +Fontify WITH-FOO, DO-FOO, DEFINE-FOO like standard macros. +Fontify CHECK-FOO like CHECK-TYPE." + (:authors "Tobias C. Rittweiler ") + (:license "GPL") + (:on-load + (font-lock-add-keywords + 'lisp-mode slime-additional-font-lock-keywords) + (when slime-highlight-suppressed-forms + (slime-activate-font-lock-magic))) + (:on-unload + ;; FIXME: remove `slime-search-suppressed-forms', and remove the + ;; extend-region hook. + (font-lock-remove-keywords + 'lisp-mode slime-additional-font-lock-keywords))) + +(defface slime-reader-conditional-face + '((t (:inherit font-lock-comment-face))) + "Face for compiler notes while selected." + :group 'slime-mode-faces) + +(defvar slime-search-suppressed-forms-match-data (list nil nil)) + +(defun slime-search-suppressed-forms-internal (limit) + (when (search-forward-regexp slime-reader-conditionals-regexp limit t) + (let ((start (match-beginning 0)) ; save match data + (state (slime-current-parser-state))) + (if (or (nth 3 state) (nth 4 state)) ; inside string or comment? + (slime-search-suppressed-forms-internal limit) + (let* ((char (char-before)) + (expr (read (current-buffer))) + (val (slime-eval-feature-expression expr))) + (when (<= (point) limit) + (if (or (and (eq char ?+) (not val)) + (and (eq char ?-) val)) + ;; If `slime-extend-region-for-font-lock' did not + ;; fully extend the region, the assertion below may + ;; fail. This should only happen on XEmacs and older + ;; versions of GNU Emacs. + (ignore-errors + (forward-sexp) (backward-sexp) + ;; Try to suppress as far as possible. + (slime-forward-sexp) + (cl-assert (<= (point) limit)) + (let ((md (match-data nil slime-search-suppressed-forms-match-data))) + (setf (cl-first md) start) + (setf (cl-second md) (point)) + (set-match-data md) + t)) + (slime-search-suppressed-forms-internal limit)))))))) + +(defun slime-search-suppressed-forms (limit) + "Find reader conditionalized forms where the test is false." + (when (and slime-highlight-suppressed-forms + (slime-connected-p)) + (let ((result 'retry)) + (while (and (eq result 'retry) (<= (point) limit)) + (condition-case condition + (setq result (slime-search-suppressed-forms-internal limit)) + (end-of-file ; e.g. #+( + (setq result nil)) + ;; We found a reader conditional we couldn't process for + ;; some reason; however, there may still be other reader + ;; conditionals before `limit'. + (invalid-read-syntax ; e.g. #+#.foo + (setq result 'retry)) + (scan-error ; e.g. #+nil (foo ... + (setq result 'retry)) + (slime-incorrect-feature-expression ; e.g. #+(not foo bar) + (setq result 'retry)) + (slime-unknown-feature-expression ; e.g. #+(foo) + (setq result 'retry)) + (error + (setq result nil) + (slime-display-warning + (concat "Caught error during fontification while searching for forms\n" + "that are suppressed by reader-conditionals. The error was: %S.") + condition)))) + result))) + + +(defun slime-search-directly-preceding-reader-conditional () + "Search for a directly preceding reader conditional. Return its +position, or nil." + ;;; We search for a preceding reader conditional. Then we check that + ;;; between the reader conditional and the point where we started is + ;;; no other intervening sexp, and we check that the reader + ;;; conditional is at the same nesting level. + (condition-case nil + (let* ((orig-pt (point)) + (reader-conditional-pt + (search-backward-regexp slime-reader-conditionals-regexp + ;; We restrict the search to the + ;; beginning of the /previous/ defun. + (save-excursion + (beginning-of-defun) + (point)) + t))) + (when reader-conditional-pt + (let* ((parser-state + (parse-partial-sexp + (progn (goto-char (+ reader-conditional-pt 2)) + (forward-sexp) ; skip feature expr. + (point)) + orig-pt)) + (paren-depth (car parser-state)) + (last-sexp-pt (cl-caddr parser-state))) + (if (and paren-depth + (not (cl-plusp paren-depth)) ; no '(' in between? + (not last-sexp-pt)) ; no complete sexp in between? + reader-conditional-pt + nil)))) + (scan-error nil))) ; improper feature expression + + +;;; We'll push this onto `font-lock-extend-region-functions'. In past, +;;; we didn't do so which made our reader-conditional font-lock magic +;;; pretty unreliable (it wouldn't highlight all suppressed forms, and +;;; worked quite non-deterministic in general.) +;;; +;;; Cf. _Elisp Manual_, 23.6.10 Multiline Font Lock Constructs. +;;; +;;; We make sure that `font-lock-beg' and `font-lock-end' always point +;;; to the beginning or end of a toplevel form. So we never miss a +;;; reader-conditional, or point in mid of one. +(defvar font-lock-beg) ; shoosh compiler +(defvar font-lock-end) + +(defun slime-extend-region-for-font-lock () + (when slime-highlight-suppressed-forms + (condition-case c + (let (changedp) + (cl-multiple-value-setq (changedp font-lock-beg font-lock-end) + (slime-compute-region-for-font-lock font-lock-beg font-lock-end)) + changedp) + (error + (slime-display-warning + (concat "Caught error when trying to extend the region for fontification.\n" + "The error was: %S\n" + "Further: font-lock-beg=%d, font-lock-end=%d.") + c font-lock-beg font-lock-end))))) + +(defun slime-beginning-of-tlf () + (let ((pos (syntax-ppss-toplevel-pos (slime-current-parser-state)))) + (if pos (goto-char pos)))) + +(defun slime-compute-region-for-font-lock (orig-beg orig-end) + (let ((beg orig-beg) + (end orig-end)) + (goto-char beg) + (inline (slime-beginning-of-tlf)) + (cl-assert (not (cl-plusp (nth 0 (slime-current-parser-state))))) + (setq beg (let ((pt (point))) + (cond ((> (- beg pt) 20000) beg) + ((slime-search-directly-preceding-reader-conditional)) + (t pt)))) + (goto-char end) + (while (search-backward-regexp slime-reader-conditionals-regexp beg t) + (setq end (max end (save-excursion + (ignore-errors (slime-forward-reader-conditional)) + (point))))) + (cl-values (or (/= beg orig-beg) (/= end orig-end)) beg end))) + + +(defun slime-activate-font-lock-magic () + (if (featurep 'xemacs) + (let ((pattern `((slime-search-suppressed-forms + (0 slime-reader-conditional-face t))))) + (dolist (sym '(lisp-font-lock-keywords + lisp-font-lock-keywords-1 + lisp-font-lock-keywords-2)) + (set sym (append (symbol-value sym) pattern)))) + (font-lock-add-keywords + 'lisp-mode + `((slime-search-suppressed-forms 0 ,''slime-reader-conditional-face t))) + + (add-hook 'lisp-mode-hook + #'(lambda () + (add-hook 'font-lock-extend-region-functions + 'slime-extend-region-for-font-lock t t))))) + +(let ((byte-compile-warnings '())) + (mapc (lambda (sym) + (cond ((fboundp sym) + (unless (byte-code-function-p (symbol-function sym)) + (byte-compile sym))) + (t (error "%S is not fbound" sym)))) + '(slime-extend-region-for-font-lock + slime-compute-region-for-font-lock + slime-search-directly-preceding-reader-conditional + slime-search-suppressed-forms + slime-beginning-of-tlf))) + +(cl-defun slime-initialize-lisp-buffer-for-test-suite + (&key (font-lock-magic t) (autodoc t)) + (let ((hook lisp-mode-hook)) + (unwind-protect + (progn + (set (make-local-variable 'slime-highlight-suppressed-forms) + font-lock-magic) + (setq lisp-mode-hook nil) + (lisp-mode) + (slime-mode 1) + (when (boundp 'slime-autodoc-mode) + (if autodoc + (slime-autodoc-mode 1) + (slime-autodoc-mode -1)))) + (setq lisp-mode-hook hook)))) + +(provide 'slime-fontifying-fu) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-fuzzy.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-fuzzy.el new file mode 100644 index 0000000..b2f22f1 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-fuzzy.el @@ -0,0 +1,604 @@ +(require 'slime) +(require 'slime-repl) +(require 'slime-c-p-c) +(require 'cl-lib) + +(define-slime-contrib slime-fuzzy + "Fuzzy symbol completion." + (:authors "Brian Downing " + "Tobias C. Rittweiler " + "Attila Lendvai ") + (:license "GPL") + (:swank-dependencies swank-fuzzy) + (:on-load + (define-key slime-mode-map "\C-c\M-i" 'slime-fuzzy-complete-symbol) + (when (featurep 'slime-repl) + (define-key slime-repl-mode-map "\C-c\M-i" + 'slime-fuzzy-complete-symbol)))) + +(defcustom slime-fuzzy-completion-in-place t + "When non-NIL the fuzzy symbol completion is done in place as +opposed to moving the point to the completion buffer." + :group 'slime-mode + :type 'boolean) + +(defcustom slime-fuzzy-completion-limit 300 + "Only return and present this many symbols from swank." + :group 'slime-mode + :type 'integer) + +(defcustom slime-fuzzy-completion-time-limit-in-msec 1500 + "Limit the time spent (given in msec) in swank while gathering +completions." + :group 'slime-mode + :type 'integer) + +(defcustom slime-when-complete-filename-expand nil + "Use comint-replace-by-expanded-filename instead of +comint-filename-completion to complete file names" + :group 'slime-mode + :type 'boolean) + + +(defvar slime-fuzzy-target-buffer nil + "The buffer that is the target of the completion activities.") +(defvar slime-fuzzy-saved-window-configuration nil + "The saved window configuration before the fuzzy completion +buffer popped up.") +(defvar slime-fuzzy-start nil + "The beginning of the completion slot in the target buffer. +This is a non-advancing marker.") +(defvar slime-fuzzy-end nil + "The end of the completion slot in the target buffer. +This is an advancing marker.") +(defvar slime-fuzzy-original-text nil + "The original text that was in the completion slot in the +target buffer. This is what is put back if completion is +aborted.") +(defvar slime-fuzzy-text nil + "The text that is currently in the completion slot in the +target buffer. If this ever doesn't match, the target buffer has +been modified and we abort without touching it.") +(defvar slime-fuzzy-first nil + "The position of the first completion in the completions buffer. +The descriptive text and headers are above this.") +(defvar slime-fuzzy-last nil + "The position of the last completion in the completions buffer. +If the time limit has exhausted during generation possible completion +choices inside SWANK, an indication is printed below this.") +(defvar slime-fuzzy-current-completion nil + "The current completion object. If this is the same before and +after point moves in the completions buffer, the text is not +replaced in the target for efficiency.") +(defvar slime-fuzzy-current-completion-overlay nil + "The overlay representing the current completion in the completion +buffer. This is used to hightlight the text.") + +;;;;;;; slime-target-buffer-fuzzy-completions-mode +;; NOTE: this mode has to be able to override key mappings in slime-mode + +(defvar slime-target-buffer-fuzzy-completions-map + (let ((map (make-sparse-keymap))) + (cl-labels ((def (keys command) + (unless (listp keys) + (setq keys (list keys))) + (dolist (key keys) + (define-key map key command)))) + (def `([remap keyboard-quit] + ,(kbd "C-g")) + 'slime-fuzzy-abort) + (def `([remap slime-fuzzy-indent-and-complete-symbol] + [remap slime-indent-and-complete-symbol] + ,(kbd "")) + 'slime-fuzzy-select-or-update-completions) + (def `([remap previous-line] + ,(kbd "")) + 'slime-fuzzy-prev) + (def `([remap next-line] + ,(kbd "")) + 'slime-fuzzy-next) + (def `([remap isearch-forward] + ,(kbd "C-s")) + 'slime-fuzzy-continue-isearch-in-fuzzy-buffer) + ;; some unconditional direct bindings + (def (list (kbd "") (kbd "RET") (kbd "") "(" ")" "[" "]") + 'slime-fuzzy-select-and-process-event-in-target-buffer)) + map) + "Keymap for slime-target-buffer-fuzzy-completions-mode. +This will override the key bindings in the target buffer +temporarily during completion.") + +;; Make sure slime-fuzzy-target-buffer-completions-mode's map is +;; before everything else. +(setf minor-mode-map-alist + (cl-stable-sort minor-mode-map-alist + (lambda (a b) + (eq a 'slime-fuzzy-target-buffer-completions-mode)) + :key #'car)) + +(defun slime-fuzzy-continue-isearch-in-fuzzy-buffer () + (interactive) + (select-window (get-buffer-window (slime-get-fuzzy-buffer))) + (call-interactively 'isearch-forward)) + +(define-minor-mode slime-fuzzy-target-buffer-completions-mode + "This minor mode is intented to override key bindings during +fuzzy completions in the target buffer. Most of the bindings will +do an implicit select in the completion window and let the +keypress be processed in the target buffer." + nil + nil + slime-target-buffer-fuzzy-completions-map) + +(add-to-list 'minor-mode-alist + '(slime-fuzzy-target-buffer-completions-mode + " Fuzzy Target Buffer Completions")) + +(defvar slime-fuzzy-completions-map + (let ((map (make-sparse-keymap))) + (cl-labels ((def (keys command) + (unless (listp keys) + (setq keys (list keys))) + (dolist (key keys) + (define-key map key command)))) + (def `([remap keyboard-quit] + "q" + ,(kbd "C-g")) + 'slime-fuzzy-abort) + (def `([remap previous-line] + "p" + "\M-p" + ,(kbd "")) + 'slime-fuzzy-prev) + (def `([remap next-line] + "n" + "\M-n" + ,(kbd "")) + 'slime-fuzzy-next) + (def "\d" 'scroll-down) + (def `([remap slime-fuzzy-indent-and-complete-symbol] + [remap slime-indent-and-complete-symbol] + ,(kbd "")) + 'slime-fuzzy-select) + (def (kbd "") 'slime-fuzzy-select/mouse) + (def `(,(kbd "RET") + ,(kbd "")) + 'slime-fuzzy-select)) + map) + "Keymap for slime-fuzzy-completions-mode when in the completion buffer.") + +(define-derived-mode slime-fuzzy-completions-mode + fundamental-mode "Fuzzy Completions" + "Major mode for presenting fuzzy completion results. + +When you run `slime-fuzzy-complete-symbol', the symbol token at +point is completed using the Fuzzy Completion algorithm; this +means that the token is taken as a sequence of characters and all +the various possibilities that this sequence could meaningfully +represent are offered as selectable choices, sorted by how well +they deem to be a match for the token. (For instance, the first +choice of completing on \"mvb\" would be \"multiple-value-bind\".) + +Therefore, a new buffer (*Fuzzy Completions*) will pop up that +contains the different completion choices. Simultaneously, a +special minor-mode will be temporarily enabled in the original +buffer where you initiated fuzzy completion (also called the +``target buffer'') in order to navigate through the *Fuzzy +Completions* buffer without leaving. + +With focus in *Fuzzy Completions*: + Type `n' and `p' (`UP', `DOWN') to navigate between completions. + Type `RET' or `TAB' to select the completion near point. + Type `q' to abort. + +With focus in the target buffer: + Type `UP' and `DOWN' to navigate between completions. + Type a character that does not constitute a symbol name + to insert the current choice and then that character (`(', `)', + `SPACE', `RET'.) Use `TAB' to simply insert the current choice. + Use C-g to abort. + +Alternatively, you can click on a completion to select it. + + +Complete listing of keybindings within the target buffer: + +\\\ +\\{slime-target-buffer-fuzzy-completions-map} + +Complete listing of keybindings with *Fuzzy Completions*: + +\\\ +\\{slime-fuzzy-completions-map}" + (use-local-map slime-fuzzy-completions-map) + (set (make-local-variable 'slime-fuzzy-current-completion-overlay) + (make-overlay (point) (point) nil t nil))) + +(defun slime-fuzzy-completions (prefix &optional default-package) + "Get the list of sorted completion objects from completing +`prefix' in `package' from the connected Lisp." + (let ((prefix (cl-etypecase prefix + (symbol (symbol-name prefix)) + (string prefix)))) + (slime-eval `(swank:fuzzy-completions ,prefix + ,(or default-package + (slime-current-package)) + :limit ,slime-fuzzy-completion-limit + :time-limit-in-msec + ,slime-fuzzy-completion-time-limit-in-msec)))) + +(defun slime-fuzzy-selected (prefix completion) + "Tell the connected Lisp that the user selected completion +`completion' as the completion for `prefix'." + (let ((no-properties (copy-sequence prefix))) + (set-text-properties 0 (length no-properties) nil no-properties) + (slime-eval `(swank:fuzzy-completion-selected ,no-properties + ',completion)))) + +(defun slime-fuzzy-indent-and-complete-symbol () + "Indent the current line and perform fuzzy symbol completion. First +indent the line. If indenting doesn't move point, complete the +symbol. If there's no symbol at the point, show the arglist for the +most recently enclosed macro or function." + (interactive) + (let ((pos (point))) + (unless (get-text-property (line-beginning-position) 'slime-repl-prompt) + (lisp-indent-line)) + (when (= pos (point)) + (cond ((save-excursion (re-search-backward "[^() \n\t\r]+\\=" nil t)) + (slime-fuzzy-complete-symbol)) + ((memq (char-before) '(?\t ?\ )) + (slime-echo-arglist)))))) + +(cl-defun slime-fuzzy-complete-symbol () + "Fuzzily completes the abbreviation at point into a symbol." + (interactive) + (when (save-excursion (re-search-backward "\"[^ \t\n]+\\=" nil t)) + (cl-return-from slime-fuzzy-complete-symbol + ;; don't add space after completion + (let ((comint-completion-addsuffix '("/" . ""))) + (if slime-when-complete-filename-expand + (comint-replace-by-expanded-filename) + ;; FIXME: use `comint-filename-completion' when dropping emacs23 + (funcall (if (>= emacs-major-version 24) + 'comint-filename-completion + 'comint-dynamic-complete-as-filename)))))) + (let* ((end (move-marker (make-marker) (slime-symbol-end-pos))) + (beg (move-marker (make-marker) (slime-symbol-start-pos))) + (prefix (buffer-substring-no-properties beg end))) + (cl-destructuring-bind (completion-set interrupted-p) + (slime-fuzzy-completions prefix) + (if (null completion-set) + (progn (slime-minibuffer-respecting-message + "Can't find completion for \"%s\"" prefix) + (ding) + (slime-fuzzy-done)) + (goto-char end) + (cond ((slime-length= completion-set 1) + ;; insert completed string + (insert-and-inherit (caar completion-set)) + (delete-region beg end) + (goto-char (+ beg (length (caar completion-set)))) + (slime-minibuffer-respecting-message "Sole completion") + (slime-fuzzy-done)) + ;; Incomplete + (t + (slime-fuzzy-choices-buffer completion-set interrupted-p + beg end) + (slime-minibuffer-respecting-message + "Complete but not unique"))))))) + + +(defun slime-get-fuzzy-buffer () + (get-buffer-create "*Fuzzy Completions*")) + +(defvar slime-fuzzy-explanation + "For help on how the use this buffer, see `slime-fuzzy-completions-mode'. + +Flags: boundp fboundp generic-function class macro special-operator package +\n" + "The explanation that gets inserted at the beginning of the +*Fuzzy Completions* buffer.") + +(defun slime-fuzzy-insert-completion-choice (completion max-length) + "Inserts the completion object `completion' as a formatted +completion choice into the current buffer, and mark it with the +proper text properties." + (cl-destructuring-bind (symbol-name score chunks classification-string) + completion + (let ((start (point)) + (end)) + (insert symbol-name) + (setq end (point)) + (dolist (chunk chunks) + (put-text-property (+ start (cl-first chunk)) + (+ start (cl-first chunk) + (length (cl-second chunk))) + 'face 'bold)) + (put-text-property start (point) 'mouse-face 'highlight) + (dotimes (i (- max-length (- end start))) + (insert " ")) + (insert (format " %s %s\n" + classification-string + score)) + (put-text-property start (point) 'completion completion)))) + +(defun slime-fuzzy-insert (text) + "Inserts `text' into the target buffer in the completion slot. +If the buffer has been modified in the meantime, abort the +completion process. Otherwise, update all completion variables +so that the new text is present." + (with-current-buffer slime-fuzzy-target-buffer + (cond + ((not (string-equal slime-fuzzy-text + (buffer-substring slime-fuzzy-start + slime-fuzzy-end))) + (slime-fuzzy-done) + (beep) + (message "Target buffer has been modified!")) + (t + (goto-char slime-fuzzy-start) + (delete-region slime-fuzzy-start slime-fuzzy-end) + (insert-and-inherit text) + (setq slime-fuzzy-text text) + (goto-char slime-fuzzy-end))))) + +(defun slime-minibuffer-p (buffer) + (if (featurep 'xemacs) + (eq buffer (window-buffer (minibuffer-window))) + (minibufferp buffer))) + +(defun slime-fuzzy-choices-buffer (completions interrupted-p start end) + "Creates (if neccessary), populates, and pops up the *Fuzzy +Completions* buffer with the completions from `completions' and +the completion slot in the current buffer bounded by `start' and +`end'. This saves the window configuration before popping the +buffer so that it can possibly be restored when the user is +done." + (let ((new-completion-buffer (not slime-fuzzy-target-buffer)) + (connection (slime-connection))) + (when new-completion-buffer + (setq slime-fuzzy-saved-window-configuration + (current-window-configuration))) + (slime-fuzzy-enable-target-buffer-completions-mode) + (setq slime-fuzzy-target-buffer (current-buffer)) + (setq slime-fuzzy-start (move-marker (make-marker) start)) + (setq slime-fuzzy-end (move-marker (make-marker) end)) + (set-marker-insertion-type slime-fuzzy-end t) + (setq slime-fuzzy-original-text (buffer-substring start end)) + (setq slime-fuzzy-text slime-fuzzy-original-text) + (slime-fuzzy-fill-completions-buffer completions interrupted-p) + (pop-to-buffer (slime-get-fuzzy-buffer)) + (slime-fuzzy-next) + (setq slime-buffer-connection connection) + (when new-completion-buffer + ;; Hook to nullify window-config restoration if the user changes + ;; the window configuration himself. + (when (boundp 'window-configuration-change-hook) + (add-hook 'window-configuration-change-hook + 'slime-fuzzy-window-configuration-change)) + (add-hook 'kill-buffer-hook 'slime-fuzzy-abort 'append t) + (set (make-local-variable 'cursor-type) nil) + (setq buffer-quit-function 'slime-fuzzy-abort)) ; M-Esc Esc + (when slime-fuzzy-completion-in-place + ;; switch back to the original buffer + (if (slime-minibuffer-p slime-fuzzy-target-buffer) + (select-window (minibuffer-window)) + (switch-to-buffer-other-window slime-fuzzy-target-buffer))))) + +(defun slime-fuzzy-fill-completions-buffer (completions interrupted-p) + "Erases and fills the completion buffer with the given completions." + (with-current-buffer (slime-get-fuzzy-buffer) + (setq buffer-read-only nil) + (erase-buffer) + (slime-fuzzy-completions-mode) + (insert slime-fuzzy-explanation) + (let ((max-length 12)) + (dolist (completion completions) + (setf max-length (max max-length (length (cl-first completion))))) + + (insert "Completion:") + (dotimes (i (- max-length 10)) (insert " ")) + ;; Flags: Score: + ;; ... ------- -------- + ;; bfgctmsp + (let* ((example-classification-string (cl-fourth (cl-first completions))) + (classification-length (length example-classification-string)) + (spaces (- classification-length (length "Flags:")))) + (insert "Flags:") + (dotimes (i spaces) (insert " ")) + (insert " Score:\n") + (dotimes (i max-length) (insert "-")) + (insert " ") + (dotimes (i classification-length) (insert "-")) + (insert " --------\n") + (setq slime-fuzzy-first (point))) + + (dolist (completion completions) + (setq slime-fuzzy-last (point)) ; will eventually become the last entry + (slime-fuzzy-insert-completion-choice completion max-length)) + + (when interrupted-p + (insert "...\n") + (insert "[Interrupted: time limit exhausted]")) + + (setq buffer-read-only t)) + (setq slime-fuzzy-current-completion + (caar completions)) + (goto-char 0))) + +(defun slime-fuzzy-enable-target-buffer-completions-mode () + "Store the target buffer's local map, so that we can restore it." + (unless slime-fuzzy-target-buffer-completions-mode +; (slime-log-event "Enabling target buffer completions mode") + (slime-fuzzy-target-buffer-completions-mode 1))) + +(defun slime-fuzzy-disable-target-buffer-completions-mode () + "Restores the target buffer's local map when completion is finished." + (when slime-fuzzy-target-buffer-completions-mode +; (slime-log-event "Disabling target buffer completions mode") + (slime-fuzzy-target-buffer-completions-mode 0))) + +(defun slime-fuzzy-insert-from-point () + "Inserts the completion that is under point in the completions +buffer into the target buffer. If the completion in question had +already been inserted, it does nothing." + (with-current-buffer (slime-get-fuzzy-buffer) + (let ((current-completion (get-text-property (point) 'completion))) + (when (and current-completion + (not (eq slime-fuzzy-current-completion + current-completion))) + (slime-fuzzy-insert + (cl-first (get-text-property (point) 'completion))) + (setq slime-fuzzy-current-completion + current-completion))))) + +(defun slime-fuzzy-post-command-hook () + "The post-command-hook for the *Fuzzy Completions* buffer. +This makes sure the completion slot in the target buffer matches +the completion that point is on in the completions buffer." + (condition-case err + (when slime-fuzzy-target-buffer + (slime-fuzzy-insert-from-point)) + (error + ;; Because this is called on the post-command-hook, we mustn't let + ;; errors propagate. + (message "Error in slime-fuzzy-post-command-hook: %S" err)))) + +(defun slime-fuzzy-next () + "Moves point directly to the next completion in the completions +buffer." + (interactive) + (with-current-buffer (slime-get-fuzzy-buffer) + (let ((point (next-single-char-property-change + (point) 'completion nil slime-fuzzy-last))) + (set-window-point (get-buffer-window (current-buffer)) point) + (goto-char point)) + (slime-fuzzy-highlight-current-completion))) + +(defun slime-fuzzy-prev () + "Moves point directly to the previous completion in the +completions buffer." + (interactive) + (with-current-buffer (slime-get-fuzzy-buffer) + (let ((point (previous-single-char-property-change + (point) + 'completion nil slime-fuzzy-first))) + (set-window-point (get-buffer-window (current-buffer)) point) + (goto-char point)) + (slime-fuzzy-highlight-current-completion))) + +(defun slime-fuzzy-highlight-current-completion () + "Highlights the current completion, +so that the user can see it on the screen." + (let ((pos (point))) + (when (overlayp slime-fuzzy-current-completion-overlay) + (move-overlay slime-fuzzy-current-completion-overlay + (point) (1- (search-forward " "))) + (overlay-put slime-fuzzy-current-completion-overlay + 'face 'secondary-selection)) + (goto-char pos))) + +(defun slime-fuzzy-abort () + "Aborts the completion process, setting the completions slot in +the target buffer back to its original contents." + (interactive) + (when slime-fuzzy-target-buffer + (slime-fuzzy-done))) + +(defun slime-fuzzy-select () + "Selects the current completion, making sure that it is inserted +into the target buffer. This tells the connected Lisp what completion +was selected." + (interactive) + (when slime-fuzzy-target-buffer + (with-current-buffer (slime-get-fuzzy-buffer) + (let ((completion (get-text-property (point) 'completion))) + (when completion + (slime-fuzzy-insert (cl-first completion)) + (slime-fuzzy-selected slime-fuzzy-original-text + completion) + (slime-fuzzy-done)))))) + +(defun slime-fuzzy-select-or-update-completions () + "If there were no changes since the last time fuzzy completion was started +this function will select the current completion. +Otherwise refreshes the completion list based on the changes made." + (interactive) +; (slime-log-event "Selecting or updating completions") + (if (string-equal slime-fuzzy-original-text + (buffer-substring slime-fuzzy-start + slime-fuzzy-end)) + (slime-fuzzy-select) + (slime-fuzzy-complete-symbol))) + +(defun slime-fuzzy-process-event-in-completions-buffer () + "Simply processes the event in the target buffer" + (interactive) + (with-current-buffer (slime-get-fuzzy-buffer) + (push last-input-event unread-command-events))) + +(defun slime-fuzzy-select-and-process-event-in-target-buffer () + "Selects the current completion, making sure that it is inserted +into the target buffer and processes the event in the target buffer." + (interactive) +; (slime-log-event "Selecting and processing event in target buffer") + (when slime-fuzzy-target-buffer + (let ((buff slime-fuzzy-target-buffer)) + (slime-fuzzy-select) + (with-current-buffer buff + (slime-fuzzy-disable-target-buffer-completions-mode) + (push last-input-event unread-command-events))))) + +(defun slime-fuzzy-select/mouse (event) + "Handle a mouse-2 click on a completion choice as if point were +on the completion choice and the slime-fuzzy-select command was +run." + (interactive "e") + (with-current-buffer (window-buffer (posn-window (event-end event))) + (save-excursion + (goto-char (posn-point (event-end event))) + (when (get-text-property (point) 'mouse-face) + (slime-fuzzy-insert-from-point) + (slime-fuzzy-select))))) + +(defun slime-fuzzy-done () + "Cleans up after the completion process. This removes all hooks, +and attempts to restore the window configuration. If this fails, +it just burys the completions buffer and leaves the window +configuration alone." + (when slime-fuzzy-target-buffer + (set-buffer slime-fuzzy-target-buffer) + (slime-fuzzy-disable-target-buffer-completions-mode) + (if (slime-fuzzy-maybe-restore-window-configuration) + (bury-buffer (slime-get-fuzzy-buffer)) + ;; We couldn't restore the windows, so just bury the fuzzy + ;; completions buffer and let something else fill it in. + (pop-to-buffer (slime-get-fuzzy-buffer)) + (bury-buffer)) + (if (slime-minibuffer-p slime-fuzzy-target-buffer) + (select-window (minibuffer-window)) + (pop-to-buffer slime-fuzzy-target-buffer)) + (goto-char slime-fuzzy-end) + (setq slime-fuzzy-target-buffer nil) + (remove-hook 'window-configuration-change-hook + 'slime-fuzzy-window-configuration-change))) + +(defun slime-fuzzy-maybe-restore-window-configuration () + "Restores the saved window configuration if it has not been +nullified." + (when (boundp 'window-configuration-change-hook) + (remove-hook 'window-configuration-change-hook + 'slime-fuzzy-window-configuration-change)) + (if (not slime-fuzzy-saved-window-configuration) + nil + (set-window-configuration slime-fuzzy-saved-window-configuration) + (setq slime-fuzzy-saved-window-configuration nil) + t)) + +(defun slime-fuzzy-window-configuration-change () + "Called on window-configuration-change-hook. Since the window +configuration was changed, we nullify our saved configuration." + (setq slime-fuzzy-saved-window-configuration nil)) + +(provide 'slime-fuzzy) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-highlight-edits.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-highlight-edits.el new file mode 100644 index 0000000..2a3f0a8 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-highlight-edits.el @@ -0,0 +1,81 @@ +(require 'slime) +(require 'slime-parse) + +(define-slime-contrib slime-highlight-edits + "Highlight edited, i.e. not yet compiled, code." + (:authors "William Bland ") + (:license "GPL") + (:on-load (add-hook 'slime-mode-hook 'slime-activate-highlight-edits)) + (:on-unload (remove-hook 'slime-mode-hook 'slime-activate-highlight-edits))) + +(defun slime-activate-highlight-edits () + (slime-highlight-edits-mode 1)) + +(defface slime-highlight-edits-face + `((((class color) (background light)) + (:background "lightgray")) + (((class color) (background dark)) + (:background "dimgray")) + (t (:background "yellow"))) + "Face for displaying edit but not compiled code." + :group 'slime-mode-faces) + +(define-minor-mode slime-highlight-edits-mode + "Minor mode to highlight not-yet-compiled code." nil) + +(add-hook 'slime-highlight-edits-mode-on-hook + 'slime-highlight-edits-init-buffer) + +(add-hook 'slime-highlight-edits-mode-off-hook + 'slime-highlight-edits-reset-buffer) + +(defun slime-highlight-edits-init-buffer () + (make-local-variable 'after-change-functions) + (add-to-list 'after-change-functions + 'slime-highlight-edits) + (add-to-list 'slime-before-compile-functions + 'slime-highlight-edits-compile-hook)) + +(defun slime-highlight-edits-reset-buffer () + (setq after-change-functions + (remove 'slime-highlight-edits after-change-functions)) + (slime-remove-edits (point-min) (point-max))) + +;; FIXME: what's the LEN arg for? +(defun slime-highlight-edits (beg end &optional len) + (save-match-data + (when (and (slime-connected-p) + (not (slime-inside-comment-p)) + (not (slime-only-whitespace-p beg end))) + (let ((overlay (make-overlay beg end))) + (overlay-put overlay 'face 'slime-highlight-edits-face) + (overlay-put overlay 'slime-edit t))))) + +(defun slime-remove-edits (start end) + "Delete the existing Slime edit hilights in the current buffer." + (save-excursion + (goto-char start) + (while (< (point) end) + (dolist (o (overlays-at (point))) + (when (overlay-get o 'slime-edit) + (delete-overlay o))) + (goto-char (next-overlay-change (point)))))) + +(defun slime-highlight-edits-compile-hook (start end) + (when slime-highlight-edits-mode + (let ((start (save-excursion (goto-char start) + (skip-chars-backward " \t\n\r") + (point))) + (end (save-excursion (goto-char end) + (skip-chars-forward " \t\n\r") + (point)))) + (slime-remove-edits start end)))) + +(defun slime-only-whitespace-p (beg end) + "Contains the region from BEG to END only whitespace?" + (save-excursion + (goto-char beg) + (skip-chars-forward " \n\t\r" end) + (<= end (point)))) + +(provide 'slime-highlight-edits) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-hyperdoc.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-hyperdoc.el new file mode 100644 index 0000000..64de7ee --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-hyperdoc.el @@ -0,0 +1,48 @@ +(require 'slime) +(require 'url-http) +(require 'browse-url) +(eval-when-compile (require 'cl)) ; lexical-let + +(defvar slime-old-documentation-lookup-function + slime-documentation-lookup-function) + +(define-slime-contrib slime-hyperdoc + "Extensible C-c C-d h." + (:authors "Tobias C Rittweiler ") + (:license "GPL") + (:swank-dependencies swank-hyperdoc) + (:on-load + (setq slime-documentation-lookup-function 'slime-hyperdoc-lookup)) + (:on-unload + (setq slime-documentation-lookup-function + slime-old-documentation-lookup-function))) + +;;; TODO: `url-http-file-exists-p' is slow, make it optional behaviour. + +(defun slime-hyperdoc-lookup-rpc (symbol-name) + (slime-eval-async `(swank:hyperdoc ,symbol-name) + (lexical-let ((symbol-name symbol-name)) + #'(lambda (result) + (slime-log-event result) + (cl-loop with foundp = nil + for (doc-type . url) in result do + (when (and url (stringp url) + (let ((url-show-status nil)) + (url-http-file-exists-p url))) + (message "Visiting documentation for %s `%s'..." + (substring (symbol-name doc-type) 1) + symbol-name) + (browse-url url) + (setq foundp t)) + finally + (unless foundp + (error "Could not find documentation for `%s'." + symbol-name))))))) + +(defun slime-hyperdoc-lookup (symbol-name) + (interactive (list (slime-read-symbol-name "Symbol: "))) + (if (memq :hyperdoc (slime-lisp-features)) + (slime-hyperdoc-lookup-rpc symbol-name) + (slime-hyperspec-lookup symbol-name))) + +(provide 'slime-hyperdoc) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-indentation.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-indentation.el new file mode 100644 index 0000000..8e323e0 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-indentation.el @@ -0,0 +1,31 @@ +(require 'slime) +(require 'slime-cl-indent) +(require 'cl-lib) + +(define-slime-contrib slime-indentation + "Contrib interfacing `slime-cl-indent' and SLIME." + (:swank-dependencies swank-indentation) + (:on-load + (setq common-lisp-current-package-function 'slime-current-package))) + +(defun slime-update-system-indentation (symbol indent packages) + (let ((list (gethash symbol common-lisp-system-indentation)) + (ok nil)) + (if (not list) + (puthash symbol (list (cons indent packages)) + common-lisp-system-indentation) + (dolist (spec list) + (cond ((equal (car spec) indent) + (dolist (p packages) + (unless (member p (cdr spec)) + (push p (cdr spec)))) + (setf ok t)) + (t + (setf (cdr spec) + (cl-set-difference (cdr spec) packages :test 'equal))))) + (unless ok + (puthash symbol (cons (cons indent packages) + list) + common-lisp-system-indentation))))) + +(provide 'slime-indentation) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-listener-hooks.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-listener-hooks.el new file mode 100644 index 0000000..ec573da --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-listener-hooks.el @@ -0,0 +1,11 @@ +(require 'slime) +(require 'cl-lib) + +(define-slime-contrib slime-listener-hooks + "Enable slime integration in an application'w event loop" + (:authors "Alan Ruttenberg , R. Mattes ") + (:license "GPL") + (:slime-dependencies slime-repl) + (:swank-dependencies swank-listener-hooks)) + +(provide 'slime-listener-hooks) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-macrostep.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-macrostep.el new file mode 100644 index 0000000..a9dff73 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-macrostep.el @@ -0,0 +1,129 @@ +;;; slime-macrostep.el -- fancy macro-expansion via macrostep.el + +;; Authors: Luís Oliveira +;; Jon Oddie " + "Jon Oddie ") + (:license "GPL") + (:swank-dependencies swank-macrostep) + (:on-load + (easy-menu-add-item slime-mode-map '(menu-bar SLIME Debugging) + ["Macro stepper..." macrostep-expand (slime-connected-p)] + "Create Trace Buffer") + (add-hook 'slime-mode-hook #'macrostep-slime-mode-hook) + (define-key slime-mode-map (kbd "C-c M-e") #'macrostep-expand) + (eval-after-load 'slime-repl + '(progn + (add-hook 'slime-repl-mode-hook #'macrostep-slime-mode-hook) + (define-key slime-repl-mode-map (kbd "C-c M-e") #'macrostep-expand))))) + +(defun macrostep-slime-mode-hook () + (setq macrostep-sexp-at-point-function #'macrostep-slime-sexp-at-point) + (setq macrostep-environment-at-point-function #'macrostep-slime-context) + (setq macrostep-expand-1-function #'macrostep-slime-expand-1) + (setq macrostep-print-function #'macrostep-slime-insert) + (setq macrostep-macro-form-p-function #'macrostep-slime-macro-form-p)) + +(defun macrostep-slime-sexp-at-point (&rest _ignore) + (slime-sexp-at-point)) + +(defun macrostep-slime-context () + (let (defun-start defun-end) + (save-excursion + (while + (condition-case nil + (progn (backward-up-list) t) + (scan-error nil))) + (setq defun-start (point)) + (setq defun-end (scan-sexps (point) 1))) + (list (buffer-substring-no-properties + defun-start (point)) + (buffer-substring-no-properties + (scan-sexps (point) 1) defun-end)))) + +(defun macrostep-slime-expand-1 (string context) + (slime-dcase + (slime-eval + `(swank-macrostep:macrostep-expand-1 + ,string ,macrostep-expand-compiler-macros ',context)) + ((:error error-message) + (error "%s" error-message)) + ((:ok expansion positions) + (list expansion positions)))) + +(defun macrostep-slime-insert (result _ignore) + "Insert RESULT at point, indenting to match the current column." + (cl-destructuring-bind (expansion positions) result + (let ((start (point)) + (column-offset (current-column))) + (insert expansion) + (macrostep-slime--propertize-macros start positions) + (indent-rigidly start (point) column-offset)))) + +(defun macrostep-slime--propertize-macros (start-offset positions) + "Put text properties on macro forms." + (dolist (position positions) + (cl-destructuring-bind (operator type start) + position + (let ((open-paren-position + (+ start-offset start))) + (put-text-property open-paren-position + (1+ open-paren-position) + 'macrostep-macro-start + t) + ;; this assumes that the operator starts right next to the + ;; opening parenthesis. We could probably be more robust. + (let ((op-start (1+ open-paren-position))) + (put-text-property op-start + (+ op-start (length operator)) + 'font-lock-face + (if (eq type :macro) + 'macrostep-macro-face + 'macrostep-compiler-macro-face))))))) + +(defun macrostep-slime-macro-form-p (string context) + (slime-dcase + (slime-eval + `(swank-macrostep:macro-form-p + ,string ,macrostep-expand-compiler-macros ',context)) + ((:error error-message) + (error "%s" error-message)) + ((:ok result) + result))) + + + +(provide 'slime-macrostep) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-mdot-fu.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-mdot-fu.el new file mode 100644 index 0000000..ed2e96a --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-mdot-fu.el @@ -0,0 +1,31 @@ +(require 'slime) +(require 'cl-lib) + +(define-slime-contrib slime-mdot-fu + "Making M-. work on local functions." + (:authors "Tobias C. Rittweiler ") + (:license "GPL") + (:slime-dependencies slime-enclosing-context) + (:on-load + (add-hook 'slime-edit-definition-hooks 'slime-edit-local-definition)) + (:on-unload + (remove-hook 'slime-edit-definition-hooks 'slime-edit-local-definition))) + + +(defun slime-edit-local-definition (name &optional where) + "Like `slime-edit-definition', but tries to find the definition +in a local function binding near point." + (interactive (list (slime-read-symbol-name "Name: "))) + (cl-multiple-value-bind (binding-name point) + (cl-multiple-value-call #'cl-some #'(lambda (binding-name point) + (when (cl-equalp binding-name name) + (cl-values binding-name point))) + (slime-enclosing-bound-names)) + (when (and binding-name point) + (slime-edit-definition-cont + `((,binding-name + ,(make-slime-buffer-location (buffer-name (current-buffer)) point))) + name + where)))) + +(provide 'slime-mdot-fu) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-media.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-media.el new file mode 100644 index 0000000..cb839eb --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-media.el @@ -0,0 +1,46 @@ +(eval-and-compile + (require 'slime)) + +(define-slime-contrib slime-media + "Display things other than text in SLIME buffers" + (:authors "Christophe Rhodes ") + (:license "GPL") + (:slime-dependencies slime-repl) + (:swank-dependencies swank-media) + (:on-load + (add-hook 'slime-event-hooks 'slime-dispatch-media-event))) + +(defun slime-media-decode-image (image) + (mapcar (lambda (image) + (if (plist-get image :data) + (plist-put image :data (base64-decode-string (plist-get image :data))) + image)) + image)) + +(defun slime-dispatch-media-event (event) + (slime-dcase event + ((:write-image image string) + (let ((img (or (find-image (slime-media-decode-image image)) + (create-image image)))) + (slime-media-insert-image img string)) + t) + ((:popup-buffer bufname string mode) + (slime-with-popup-buffer (bufname :connection t :package t) + (when mode (funcall mode)) + (princ string) + (goto-char (point-min))) + t) + (t nil))) + +(defun slime-media-insert-image (image string &optional bol) + (with-current-buffer (slime-output-buffer) + (let ((marker (slime-repl-output-target-marker :repl-result))) + (goto-char marker) + (slime-propertize-region `(face slime-repl-result-face + rear-nonsticky (face)) + (insert-image image string)) + ;; Move the input-start marker after the REPL result. + (set-marker marker (point))) + (slime-repl-show-maximum-output))) + +(provide 'slime-media) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-mrepl.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-mrepl.el new file mode 100644 index 0000000..d9ebc38 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-mrepl.el @@ -0,0 +1,150 @@ +;; An experimental implementation of multiple REPLs multiplexed over a +;; single Slime socket. M-x slime-new-mrepl creates a new REPL buffer. +;; +(require 'slime) +(require 'inferior-slime) ; inferior-slime-indent-lime +(require 'cl-lib) + +(define-slime-contrib slime-mrepl + "Multiple REPLs." + (:authors "Helmut Eller ") + (:license "GPL") + (:swank-dependencies swank-mrepl)) + +(require 'comint) + +(defvar slime-mrepl-remote-channel nil) +(defvar slime-mrepl-expect-sexp nil) + +(define-derived-mode slime-mrepl-mode comint-mode "mrepl" + ;; idea lifted from ielm + (unless (get-buffer-process (current-buffer)) + (let* ((process-connection-type nil) + (proc (start-process "mrepl (dummy)" (current-buffer) "hexl"))) + (set-process-query-on-exit-flag proc nil))) + (set (make-local-variable 'comint-use-prompt-regexp) nil) + (set (make-local-variable 'comint-inhibit-carriage-motion) t) + (set (make-local-variable 'comint-input-sender) 'slime-mrepl-input-sender) + (set (make-local-variable 'comint-output-filter-functions) nil) + (set (make-local-variable 'slime-mrepl-expect-sexp) t) + ;;(set (make-local-variable 'comint-get-old-input) 'ielm-get-old-input) + (set-syntax-table lisp-mode-syntax-table) + ) + +(slime-define-keys slime-mrepl-mode-map + ((kbd "RET") 'slime-mrepl-return) + ([return] 'slime-mrepl-return) + ;;((kbd "TAB") 'slime-indent-and-complete-symbol) + ((kbd "C-c C-b") 'slime-interrupt) + ((kbd "C-c C-c") 'slime-interrupt)) + +(defun slime-mrepl-process% () (get-buffer-process (current-buffer))) ;stupid +(defun slime-mrepl-mark () (process-mark (slime-mrepl-process%))) + +(defun slime-mrepl-insert (string) + (comint-output-filter (slime-mrepl-process%) string)) + +(slime-define-channel-type listener) + +(slime-define-channel-method listener :prompt (package prompt) + (with-current-buffer (slime-channel-get self 'buffer) + (slime-mrepl-prompt package prompt))) + +(defun slime-mrepl-prompt (package prompt) + (setf slime-buffer-package package) + (slime-mrepl-insert (format "%s%s> " + (cl-case (current-column) + (0 "") + (t "\n")) + prompt)) + (slime-mrepl-recenter)) + +(defun slime-mrepl-recenter () + (when (get-buffer-window) + (recenter -1))) + +(slime-define-channel-method listener :write-result (result) + (with-current-buffer (slime-channel-get self 'buffer) + (goto-char (point-max)) + (slime-mrepl-insert result))) + +(slime-define-channel-method listener :evaluation-aborted () + (with-current-buffer (slime-channel-get self 'buffer) + (goto-char (point-max)) + (slime-mrepl-insert "; Evaluation aborted\n"))) + +(slime-define-channel-method listener :write-string (string) + (slime-mrepl-write-string self string)) + +(defun slime-mrepl-write-string (self string) + (with-current-buffer (slime-channel-get self 'buffer) + (goto-char (slime-mrepl-mark)) + (slime-mrepl-insert string))) + +(slime-define-channel-method listener :set-read-mode (mode) + (with-current-buffer (slime-channel-get self 'buffer) + (cl-ecase mode + (:read (setq slime-mrepl-expect-sexp nil) + (message "[Listener is waiting for input]")) + (:eval (setq slime-mrepl-expect-sexp t))))) + +(defun slime-mrepl-return (&optional end-of-input) + (interactive "P") + (slime-check-connected) + (goto-char (point-max)) + (cond ((and slime-mrepl-expect-sexp + (or (slime-input-complete-p (slime-mrepl-mark) (point)) + end-of-input)) + (comint-send-input)) + ((not slime-mrepl-expect-sexp) + (unless end-of-input + (insert "\n")) + (comint-send-input t)) + (t + (insert "\n") + (inferior-slime-indent-line) + (message "[input not complete]"))) + (slime-mrepl-recenter)) + +(defun slime-mrepl-input-sender (proc string) + (slime-mrepl-send-string (substring-no-properties string))) + +(defun slime-mrepl-send-string (string &optional command-string) + (slime-mrepl-send `(:process ,string))) + +(defun slime-mrepl-send (msg) + "Send MSG to the remote channel." + (slime-send-to-remote-channel slime-mrepl-remote-channel msg)) + +(defun slime-new-mrepl () + "Create a new listener window." + (interactive) + (let ((channel (slime-make-channel slime-listener-channel-methods))) + (slime-eval-async + `(swank-mrepl:create-mrepl ,(slime-channel.id channel)) + (slime-rcurry + (lambda (result channel) + (cl-destructuring-bind (remote thread-id package prompt) result + (pop-to-buffer (generate-new-buffer (slime-buffer-name :mrepl))) + (slime-mrepl-mode) + (setq slime-current-thread thread-id) + (setq slime-buffer-connection (slime-connection)) + (set (make-local-variable 'slime-mrepl-remote-channel) remote) + (slime-channel-put channel 'buffer (current-buffer)) + (slime-channel-send channel `(:prompt ,package ,prompt)))) + channel)))) + +(defun slime-mrepl () + (let ((conn (slime-connection))) + (cl-find-if (lambda (x) + (with-current-buffer x + (and (eq major-mode 'slime-mrepl-mode) + (eq (slime-current-connection) conn)))) + (buffer-list)))) + +(def-slime-selector-method ?m + "First mrepl-buffer" + (or (slime-mrepl) + (error "No mrepl buffer (%s)" (slime-connection-name)))) + +(provide 'slime-mrepl) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-package-fu.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-package-fu.el new file mode 100644 index 0000000..00a1449 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-package-fu.el @@ -0,0 +1,320 @@ +(require 'slime) +(require 'slime-c-p-c) +(require 'slime-parse) + +(defvar slime-package-fu-init-undo-stack nil) + +(define-slime-contrib slime-package-fu + "Exporting/Unexporting symbols at point." + (:authors "Tobias C. Rittweiler ") + (:license "GPL") + (:swank-dependencies swank-package-fu) + (:on-load + (push `(progn (define-key slime-mode-map "\C-cx" + ',(lookup-key slime-mode-map "\C-cx"))) + slime-package-fu-init-undo-stack) + (define-key slime-mode-map "\C-cx" 'slime-export-symbol-at-point)) + (:on-unload + (while slime-c-p-c-init-undo-stack + (eval (pop slime-c-p-c-init-undo-stack))))) + +(defvar slime-package-file-candidates + (mapcar #'file-name-nondirectory + '("package.lisp" "packages.lisp" "pkgdcl.lisp" + "defpackage.lisp"))) + +(defvar slime-export-symbol-representation-function + #'(lambda (n) (format "#:%s" n))) + +(defvar slime-export-symbol-representation-auto t + "Determine automatically which style is used for symbols, #: or : +If it's mixed or no symbols are exported so far, +use `slime-export-symbol-representation-function'.") + +(defvar slime-export-save-file nil + "Save the package file after each automatic modification") + +(defvar slime-defpackage-regexp + "^(\\(cl:\\|common-lisp:\\)?defpackage\\>[ \t']*") + +(defun slime-find-package-definition-rpc (package) + (slime-eval `(swank:find-definition-for-thing + (swank::guess-package ,package)))) + +(defun slime-find-package-definition-regexp (package) + (save-excursion + (save-match-data + (goto-char (point-min)) + (cl-block nil + (while (re-search-forward slime-defpackage-regexp nil t) + (when (slime-package-equal package (slime-sexp-at-point)) + (backward-sexp) + (cl-return (make-slime-file-location (buffer-file-name) + (1- (point)))))))))) + +(defun slime-package-equal (designator1 designator2) + ;; First try to be lucky and compare the strings themselves (for the + ;; case when one of the designated packages isn't loaded in the + ;; image.) Then try to do it properly using the inferior Lisp which + ;; will also resolve nicknames for us &c. + (or (cl-equalp (slime-cl-symbol-name designator1) + (slime-cl-symbol-name designator2)) + (slime-eval `(swank:package= ,designator1 ,designator2)))) + +(defun slime-export-symbol (symbol package) + "Unexport `symbol' from `package' in the Lisp image." + (slime-eval `(swank:export-symbol-for-emacs ,symbol ,package))) + +(defun slime-unexport-symbol (symbol package) + "Export `symbol' from `package' in the Lisp image." + (slime-eval `(swank:unexport-symbol-for-emacs ,symbol ,package))) + + +(defun slime-find-possible-package-file (buffer-file-name) + (cl-labels ((file-name-subdirectory (dirname) + (expand-file-name + (concat (file-name-as-directory (slime-to-lisp-filename dirname)) + (file-name-as-directory "..")))) + (try (dirname) + (cl-dolist (package-file-name slime-package-file-candidates) + (let ((f (slime-to-lisp-filename + (concat dirname package-file-name)))) + (when (file-readable-p f) + (cl-return f)))))) + (when buffer-file-name + (let ((buffer-cwd (file-name-directory buffer-file-name))) + (or (try buffer-cwd) + (try (file-name-subdirectory buffer-cwd)) + (try (file-name-subdirectory + (file-name-subdirectory buffer-cwd)))))))) + +(defun slime-goto-package-source-definition (package) + "Tries to find the DEFPACKAGE form of `package'. If found, +places the cursor at the start of the DEFPACKAGE form." + (cl-labels ((try (location) + (when (slime-location-p location) + (slime-goto-source-location location) + t))) + (or (try (slime-find-package-definition-rpc package)) + (try (slime-find-package-definition-regexp package)) + (try (let ((package-file (slime-find-possible-package-file + (buffer-file-name)))) + (when package-file + (with-current-buffer (find-file-noselect package-file t) + (slime-find-package-definition-regexp package))))) + (error "Couldn't find source definition of package: %s" package)))) + +(defun slime-at-expression-p (pattern) + (when (ignore-errors + ;; at a list? + (= (point) (progn (down-list 1) + (backward-up-list 1) + (point)))) + (save-excursion + (down-list 1) + (slime-in-expression-p pattern)))) + +(defun slime-goto-next-export-clause () + ;; Assumes we're inside the beginning of a DEFPACKAGE form. + (let ((point)) + (save-excursion + (cl-block nil + (while (ignore-errors (slime-forward-sexp) t) + (skip-chars-forward " \n\t") + (when (slime-at-expression-p '(:export *)) + (setq point (point)) + (cl-return))))) + (if point + (goto-char point) + (error "No next (:export ...) clause found")))) + +(defun slime-search-exports-in-defpackage (symbol-name) + "Look if `symbol-name' is mentioned in one of the :EXPORT clauses." + ;; Assumes we're inside the beginning of a DEFPACKAGE form. + (cl-labels ((target-symbol-p (symbol) + (string-match-p (format "^\\(\\(#:\\)\\|:\\)?%s$" + (regexp-quote symbol-name)) + symbol))) + (save-excursion + (cl-block nil + (while (ignore-errors (slime-goto-next-export-clause) t) + (let ((clause-end (save-excursion (forward-sexp) (point)))) + (save-excursion + (while (search-forward symbol-name clause-end t) + (when (target-symbol-p (slime-symbol-at-point)) + (cl-return (if (slime-inside-string-p) + ;; Include the following " + (1+ (point)) + (point)))))))))))) + +(defun slime-export-symbols () + "Return a list of symbols inside :export clause of a defpackage." + ;; Assumes we're at the beginning of :export + (cl-labels ((read-sexp () + (ignore-errors + (forward-comment (point-max)) + (buffer-substring-no-properties + (point) (progn (forward-sexp) (point)))))) + (save-excursion + (cl-loop for sexp = (read-sexp) while sexp collect sexp)))) + +(defun slime-defpackage-exports () + "Return a list of symbols inside :export clause of a defpackage." + ;; Assumes we're inside the beginning of a DEFPACKAGE form. + (cl-labels ((normalize-name (name) + (if (string-prefix-p "\"" name) + (read name) + (replace-regexp-in-string "^\\(\\(#:\\)\\|:\\)" + "" name)))) + (save-excursion + (mapcar #'normalize-name + (cl-loop while (ignore-errors (slime-goto-next-export-clause) t) + do (down-list) (forward-sexp) + append (slime-export-symbols) + do (up-list) (backward-sexp)))))) + +(defun slime-symbol-exported-p (name symbols) + (cl-member name symbols :test 'cl-equalp)) + +(defun slime-frob-defpackage-form (current-package do-what symbols) + "Adds/removes `symbol' from the DEFPACKAGE form of `current-package' +depending on the value of `do-what' which can either be `:export', +or `:unexport'. + +Returns t if the symbol was added/removed. Nil if the symbol was +already exported/unexported." + (save-excursion + (slime-goto-package-source-definition current-package) + (down-list 1) ; enter DEFPACKAGE form + (forward-sexp) ; skip DEFPACKAGE symbol + ;; Don't or will fail if (:export ...) is immediately following + ;; (forward-sexp) ; skip package name + (let ((exported-symbols (slime-defpackage-exports)) + (symbols (if (consp symbols) + symbols + (list symbols))) + (number-of-actions 0)) + (cl-ecase do-what + (:export + (slime-add-export) + (dolist (symbol symbols) + (let ((symbol-name (slime-cl-symbol-name symbol))) + (unless (slime-symbol-exported-p symbol-name exported-symbols) + (cl-incf number-of-actions) + (slime-insert-export symbol-name))))) + (:unexport + (dolist (symbol symbols) + (let ((symbol-name (slime-cl-symbol-name symbol))) + (when (slime-symbol-exported-p symbol-name exported-symbols) + (slime-remove-export symbol-name) + (cl-incf number-of-actions)))))) + (when slime-export-save-file + (save-buffer)) + number-of-actions))) + +(defun slime-add-export () + (let (point) + (save-excursion + (while (ignore-errors (slime-goto-next-export-clause) t) + (setq point (point)))) + (cond (point + (goto-char point) + (down-list) + (slime-end-of-list)) + (t + (slime-end-of-list) + (unless (looking-back "^\\s-*") + (newline-and-indent)) + (insert "(:export ") + (save-excursion (insert ")")))))) + +(defun slime-determine-symbol-style () + ;; Assumes we're inside :export + (save-excursion + (slime-beginning-of-list) + (slime-forward-sexp) + (let ((symbols (slime-export-symbols))) + (cond ((null symbols) + slime-export-symbol-representation-function) + ((cl-every (lambda (x) + (string-match "^:" x)) + symbols) + (lambda (n) (format ":%s" n))) + ((cl-every (lambda (x) + (string-match "^#:" x)) + symbols) + (lambda (n) (format "#:%s" n))) + ((cl-every (lambda (x) + (string-prefix-p "\"" x)) + symbols) + (lambda (n) (prin1-to-string (upcase (substring-no-properties n))))) + (t + slime-export-symbol-representation-function))))) + +(defun slime-format-symbol-for-defpackage (symbol-name) + (funcall (if slime-export-symbol-representation-auto + (slime-determine-symbol-style) + slime-export-symbol-representation-function) + symbol-name)) + +(defun slime-insert-export (symbol-name) + ;; Assumes we're at the inside :export after the last symbol + (let ((symbol-name (slime-format-symbol-for-defpackage symbol-name))) + (unless (looking-back "^\\s-*") + (newline-and-indent)) + (insert symbol-name))) + +(defun slime-remove-export (symbol-name) + ;; Assumes we're inside the beginning of a DEFPACKAGE form. + (let ((point)) + (while (setq point (slime-search-exports-in-defpackage symbol-name)) + (save-excursion + (goto-char point) + (backward-sexp) + (delete-region (point) point) + (beginning-of-line) + (when (looking-at "^\\s-*$") + (join-line) + (delete-trailing-whitespace (point) (line-end-position))))))) + +(defun slime-export-symbol-at-point () + "Add the symbol at point to the defpackage source definition +belonging to the current buffer-package. With prefix-arg, remove +the symbol again. Additionally performs an EXPORT/UNEXPORT of the +symbol in the Lisp image if possible." + (interactive) + (let ((package (slime-current-package)) + (symbol (slime-symbol-at-point))) + (unless symbol (error "No symbol at point.")) + (cond (current-prefix-arg + (if (cl-plusp (slime-frob-defpackage-form package :unexport symbol)) + (message "Symbol `%s' no longer exported form `%s'" + symbol package) + (message "Symbol `%s' is not exported from `%s'" + symbol package)) + (slime-unexport-symbol symbol package)) + (t + (if (cl-plusp (slime-frob-defpackage-form package :export symbol)) + (message "Symbol `%s' now exported from `%s'" + symbol package) + (message "Symbol `%s' already exported from `%s'" + symbol package)) + (slime-export-symbol symbol package))))) + +(defun slime-export-class (name) + "Export acessors, constructors, etc. associated with a structure or a class" + (interactive (list (slime-read-from-minibuffer "Export structure named: " + (slime-symbol-at-point)))) + (let* ((package (slime-current-package)) + (symbols (slime-eval `(swank:export-structure ,name ,package)))) + (message "%s symbols exported from `%s'" + (slime-frob-defpackage-form package :export symbols) + package))) + +(defalias 'slime-export-structure 'slime-export-class) + +(provide 'slime-package-fu) + +;; Local Variables: +;; indent-tabs-mode: nil +;; End: diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-parse.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-parse.el new file mode 100644 index 0000000..ed81eb3 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-parse.el @@ -0,0 +1,358 @@ +(require 'slime) +(require 'cl-lib) + +(define-slime-contrib slime-parse + "Utility contrib containg functions to parse forms in a buffer." + (:authors "Matthias Koeppe " + "Tobias C. Rittweiler ") + (:license "GPL")) + +(defun slime-parse-form-until (limit form-suffix) + "Parses form from point to `limit'." + ;; For performance reasons, this function does not use recursion. + (let ((todo (list (point))) ; stack of positions + (sexps) ; stack of expressions + (cursexp) + (curpos) + (depth 1)) ; This function must be called from the + ; start of the sexp to be parsed. + (while (and (setq curpos (pop todo)) + (progn + (goto-char curpos) + ;; (Here we also move over suppressed + ;; reader-conditionalized code! Important so CL-side + ;; of autodoc won't see that garbage.) + (ignore-errors (slime-forward-cruft)) + (< (point) limit))) + (setq cursexp (pop sexps)) + (cond + ;; End of an sexp? + ((or (looking-at "\\s)") (eolp)) + (cl-decf depth) + (push (nreverse cursexp) (car sexps))) + ;; Start of a new sexp? + ((looking-at "\\s'*@*\\s(") + (let ((subpt (match-end 0))) + (ignore-errors + (forward-sexp) + ;; (In case of error, we're at an incomplete sexp, and + ;; nothing's left todo after it.) + (push (point) todo)) + (push cursexp sexps) + (push subpt todo) ; to descend into new sexp + (push nil sexps) + (cl-incf depth))) + ;; In mid of an sexp.. + (t + (let ((pt1 (point)) + (pt2 (condition-case e + (progn (forward-sexp) (point)) + (scan-error + (cl-fourth e))))) ; end of sexp + (push (buffer-substring-no-properties pt1 pt2) cursexp) + (push pt2 todo) + (push cursexp sexps))))) + (when sexps + (setf (car sexps) (cl-nreconc form-suffix (car sexps))) + (while (> depth 1) + (push (nreverse (pop sexps)) (car sexps)) + (cl-decf depth)) + (nreverse (car sexps))))) + +(defun slime-compare-char-syntax (get-char-fn syntax &optional unescaped) + "Returns t if the character that `get-char-fn' yields has +characer syntax of `syntax'. If `unescaped' is true, it's ensured +that the character is not escaped." + (let ((char (funcall get-char-fn (point))) + (char-before (funcall get-char-fn (1- (point))))) + (if (and char (eq (char-syntax char) (aref syntax 0))) + (if unescaped + (or (null char-before) + (not (eq (char-syntax char-before) ?\\))) + t) + nil))) + +(defconst slime-cursor-marker 'swank::%cursor-marker%) + +(defun slime-parse-form-upto-point (&optional max-levels) + (save-restriction + ;; Don't parse more than 500 lines before point, so we don't spend + ;; too much time. NB. Make sure to go to beginning of line, and + ;; not possibly anywhere inside comments or strings. + (narrow-to-region (line-beginning-position -500) (point-max)) + (save-excursion + (let ((suffix (list slime-cursor-marker))) + (cond ((slime-compare-char-syntax #'char-after "(" t) + ;; We're at the start of some expression, so make sure + ;; that SWANK::%CURSOR-MARKER% will come after that + ;; expression. If the expression is not balanced, make + ;; still sure that the marker does *not* come directly + ;; after the preceding expression. + (or (ignore-errors (forward-sexp) t) + (push "" suffix))) + ((or (bolp) (slime-compare-char-syntax #'char-before " " t)) + ;; We're after some expression, so we have to make sure + ;; that %CURSOR-MARKER% does *not* come directly after + ;; that expression. + (push "" suffix)) + ((slime-compare-char-syntax #'char-before "(" t) + ;; We're directly after an opening parenthesis, so we + ;; have to make sure that something comes before + ;; %CURSOR-MARKER%. + (push "" suffix)) + (t + ;; We're at a symbol, so make sure we get the whole symbol. + (slime-end-of-symbol))) + (let ((pt (point))) + (ignore-errors (up-list (if max-levels (- max-levels) -5))) + (ignore-errors (down-list)) + (slime-parse-form-until pt suffix)))))) + +(require 'bytecomp) + +(mapc (lambda (sym) + (cond ((fboundp sym) + (unless (byte-code-function-p (symbol-function sym)) + (byte-compile sym))) + (t (error "%S is not fbound" sym)))) + '(slime-parse-form-upto-point + slime-parse-form-until + slime-compare-char-syntax)) + +;;;; Test cases +(defun slime-extract-context () + "Parse the context for the symbol at point. +Nil is returned if there's no symbol at point. Otherwise we detect +the following cases (the . shows the point position): + + (defun n.ame (...) ...) -> (:defun name) + (defun (setf n.ame) (...) ...) -> (:defun (setf name)) + (defmethod n.ame (...) ...) -> (:defmethod name (...)) + (defun ... (...) (labels ((n.ame (...) -> (:labels (:defun ...) name) + (defun ... (...) (flet ((n.ame (...) -> (:flet (:defun ...) name) + (defun ... (...) ... (n.ame ...) ...) -> (:call (:defun ...) name) + (defun ... (...) ... (setf (n.ame ...) -> (:call (:defun ...) (setf name)) + + (defmacro n.ame (...) ...) -> (:defmacro name) + (defsetf n.ame (...) ...) -> (:defsetf name) + (define-setf-expander n.ame (...) ...) -> (:define-setf-expander name) + (define-modify-macro n.ame (...) ...) -> (:define-modify-macro name) + (define-compiler-macro n.ame (...) ...) -> (:define-compiler-macro name) + (defvar n.ame (...) ...) -> (:defvar name) + (defparameter n.ame ...) -> (:defparameter name) + (defconstant n.ame ...) -> (:defconstant name) + (defclass n.ame ...) -> (:defclass name) + (defstruct n.ame ...) -> (:defstruct name) + (defpackage n.ame ...) -> (:defpackage name) +For other contexts we return the symbol at point." + (let ((name (slime-symbol-at-point))) + (if name + (let ((symbol (read name))) + (or (progn ;;ignore-errors + (slime-parse-context symbol)) + symbol))))) + +(defun slime-parse-context (name) + (save-excursion + (cond ((slime-in-expression-p '(defun *)) `(:defun ,name)) + ((slime-in-expression-p '(defmacro *)) `(:defmacro ,name)) + ((slime-in-expression-p '(defgeneric *)) `(:defgeneric ,name)) + ((slime-in-expression-p '(setf *)) + ;;a setf-definition, but which? + (backward-up-list 1) + (slime-parse-context `(setf ,name))) + ((slime-in-expression-p '(defmethod *)) + (unless (looking-at "\\s ") + (forward-sexp 1)) ; skip over the methodname + (let (qualifiers arglist) + (cl-loop for e = (read (current-buffer)) + until (listp e) do (push e qualifiers) + finally (setq arglist e)) + `(:defmethod ,name ,@qualifiers + ,(slime-arglist-specializers arglist)))) + ((and (symbolp name) + (slime-in-expression-p `(,name))) + ;; looks like a regular call + (let ((toplevel (ignore-errors (slime-parse-toplevel-form)))) + (cond ((slime-in-expression-p `(setf (*))) ;a setf-call + (if toplevel + `(:call ,toplevel (setf ,name)) + `(setf ,name))) + ((not toplevel) + name) + ((slime-in-expression-p `(labels ((*)))) + `(:labels ,toplevel ,name)) + ((slime-in-expression-p `(flet ((*)))) + `(:flet ,toplevel ,name)) + (t + `(:call ,toplevel ,name))))) + ((slime-in-expression-p '(define-compiler-macro *)) + `(:define-compiler-macro ,name)) + ((slime-in-expression-p '(define-modify-macro *)) + `(:define-modify-macro ,name)) + ((slime-in-expression-p '(define-setf-expander *)) + `(:define-setf-expander ,name)) + ((slime-in-expression-p '(defsetf *)) + `(:defsetf ,name)) + ((slime-in-expression-p '(defvar *)) `(:defvar ,name)) + ((slime-in-expression-p '(defparameter *)) `(:defparameter ,name)) + ((slime-in-expression-p '(defconstant *)) `(:defconstant ,name)) + ((slime-in-expression-p '(defclass *)) `(:defclass ,name)) + ((slime-in-expression-p '(defpackage *)) `(:defpackage ,name)) + ((slime-in-expression-p '(defstruct *)) + `(:defstruct ,(if (consp name) + (car name) + name))) + (t + name)))) + + +(defun slime-in-expression-p (pattern) + "A helper function to determine the current context. +The pattern can have the form: + pattern ::= () ;matches always + | (*) ;matches inside a list + | ( ) ;matches if the first element in + ; the current list is and + ; if matches. + | (()) ;matches if we are in a nested list." + (save-excursion + (let ((path (reverse (slime-pattern-path pattern)))) + (cl-loop for p in path + always (ignore-errors + (cl-etypecase p + (symbol (slime-beginning-of-list) + (eq (read (current-buffer)) p)) + (number (backward-up-list p) + t))))))) + +(defun slime-pattern-path (pattern) + ;; Compute the path to the * in the pattern to make matching + ;; easier. The path is a list of symbols and numbers. A number + ;; means "(down-list )" and a symbol "(look-at )") + (if (null pattern) + '() + (cl-etypecase (car pattern) + ((member *) '()) + (symbol (cons (car pattern) (slime-pattern-path (cdr pattern)))) + (cons (cons 1 (slime-pattern-path (car pattern))))))) + +(defun slime-beginning-of-list (&optional up) + "Move backward to the beginning of the current expression. +Point is placed before the first expression in the list." + (backward-up-list (or up 1)) + (down-list 1) + (skip-syntax-forward " ")) + +(defun slime-end-of-list (&optional up) + (backward-up-list (or up 1)) + (forward-list 1) + (down-list -1)) + +(defun slime-parse-toplevel-form () + (ignore-errors ; (foo) + (save-excursion + (goto-char (car (slime-region-for-defun-at-point))) + (down-list 1) + (forward-sexp 1) + (slime-parse-context (read (current-buffer)))))) + +(defun slime-arglist-specializers (arglist) + (cond ((or (null arglist) + (member (cl-first arglist) '(&optional &key &rest &aux))) + (list)) + ((consp (cl-first arglist)) + (cons (cl-second (cl-first arglist)) + (slime-arglist-specializers (cl-rest arglist)))) + (t + (cons 't + (slime-arglist-specializers (cl-rest arglist)))))) + +(defun slime-definition-at-point (&optional only-functional) + "Return object corresponding to the definition at point." + (let ((toplevel (slime-parse-toplevel-form))) + (if (or (symbolp toplevel) + (and only-functional + (not (member (car toplevel) + '(:defun :defgeneric :defmethod + :defmacro :define-compiler-macro))))) + (error "Not in a definition") + (slime-dcase toplevel + (((:defun :defgeneric) symbol) + (format "#'%s" symbol)) + (((:defmacro :define-modify-macro) symbol) + (format "(macro-function '%s)" symbol)) + ((:define-compiler-macro symbol) + (format "(compiler-macro-function '%s)" symbol)) + ((:defmethod symbol &rest args) + (declare (ignore args)) + (format "#'%s" symbol)) + (((:defparameter :defvar :defconstant) symbol) + (format "'%s" symbol)) + (((:defclass :defstruct) symbol) + (format "(find-class '%s)" symbol)) + ((:defpackage symbol) + (format "(or (find-package '%s) (error \"Package %s not found\"))" + symbol symbol)) + (t + (error "Not in a definition")))))) + +(defsubst slime-current-parser-state () + ;; `syntax-ppss' does not save match data as it invokes + ;; `beginning-of-defun' implicitly which does not save match + ;; data. This issue has been reported to the Emacs maintainer on + ;; Feb27. + (syntax-ppss)) + +(defun slime-inside-string-p () + (nth 3 (slime-current-parser-state))) + +(defun slime-inside-comment-p () + (nth 4 (slime-current-parser-state))) + +(defun slime-inside-string-or-comment-p () + (let ((state (slime-current-parser-state))) + (or (nth 3 state) (nth 4 state)))) + +;;; The following two functions can be handy when inspecting +;;; source-location while debugging `M-.'. +;;; +(defun slime-current-tlf-number () + "Return the current toplevel number." + (interactive) + (let ((original-pos (car (slime-region-for-defun-at-point))) + (n 0)) + (save-excursion + ;; We use this and no repeated `beginning-of-defun's to get + ;; reader conditionals right. + (goto-char (point-min)) + (while (progn (slime-forward-sexp) + (< (point) original-pos)) + (cl-incf n))) + n)) + +;;; This is similiar to `slime-enclosing-form-paths' in the +;;; `slime-parse' contrib except that this does not do any duck-tape +;;; parsing, and gets reader conditionals right. +(defun slime-current-form-path () + "Returns the path from the beginning of the current toplevel +form to the atom at point, or nil if we're in front of a tlf." + (interactive) + (let ((source-path nil)) + (save-excursion + ;; Moving forward to get reader conditionals right. + (cl-loop for inner-pos = (point) + for outer-pos = (cl-nth-value 1 (slime-current-parser-state)) + while outer-pos do + (goto-char outer-pos) + (unless (eq (char-before) ?#) ; when at #(...) continue. + (forward-char) + (let ((n 0)) + (while (progn (slime-forward-sexp) + (< (point) inner-pos)) + (cl-incf n)) + (push n source-path) + (goto-char outer-pos))))) + source-path)) + +(provide 'slime-parse) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-presentation-streams.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-presentation-streams.el new file mode 100644 index 0000000..786c549 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-presentation-streams.el @@ -0,0 +1,18 @@ +(eval-and-compile + (require 'slime)) + +(define-slime-contrib slime-presentation-streams + "Streams that allow attaching object identities to portions of + output." + (:authors "Alan Ruttenberg " + "Matthias Koeppe " + "Helmut Eller ") + (:license "GPL") + (:on-load + (add-hook 'slime-connected-hook 'slime-presentation-streams-on-connected)) + (:swank-dependencies swank-presentation-streams)) + +(defun slime-presentation-streams-on-connected () + (slime-eval `(swank:init-presentation-streams))) + +(provide 'slime-presentation-streams) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-presentations.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-presentations.el new file mode 100644 index 0000000..229bf8a --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-presentations.el @@ -0,0 +1,872 @@ +(require 'slime) +(require 'bridge) +(require 'cl-lib) +(eval-when-compile + (require 'cl)) + +(define-slime-contrib slime-presentations + "Imitate LispM presentations." + (:authors "Alan Ruttenberg " + "Matthias Koeppe ") + (:license "GPL") + (:slime-dependencies slime-repl) + (:swank-dependencies swank-presentations) + (:on-load + (add-hook 'slime-repl-mode-hook + (lambda () + ;; Respect the syntax text properties of presentation. + (set (make-local-variable 'parse-sexp-lookup-properties) t) + (add-hook 'after-change-functions + 'slime-after-change-function 'append t))) + (add-hook 'slime-event-hooks 'slime-dispatch-presentation-event) + (setq slime-write-string-function 'slime-presentation-write) + (add-hook 'slime-connected-hook 'slime-presentations-on-connected) + (add-hook 'slime-repl-return-hooks 'slime-presentation-on-return-pressed) + (add-hook 'slime-repl-current-input-hooks 'slime-presentation-current-input) + (add-hook 'slime-open-stream-hooks 'slime-presentation-on-stream-open) + (add-hook 'slime-repl-clear-buffer-hook 'slime-clear-presentations) + (add-hook 'slime-edit-definition-hooks 'slime-edit-presentation) + (setq sldb-insert-frame-variable-value-function + 'slime-presentation-sldb-insert-frame-variable-value) + (slime-presentation-init-keymaps) + (slime-presentation-add-easy-menu))) + +;; To get presentations in the inspector as well, add this to your +;; init file. +;; +;; (eval-after-load 'slime-presentations +;; '(setq slime-inspector-insert-ispec-function +;; 'slime-presentation-inspector-insert-ispec)) +;; +(defface slime-repl-output-mouseover-face + '((t (:box (:line-width 1 :color "black" :style released-button) + :inherit slime-repl-inputed-output-face))) + "Face for Lisp output in the SLIME REPL, when the mouse hovers over it" + :group 'slime-repl) + +(defface slime-repl-inputed-output-face + '((((class color) (background light)) (:foreground "Red")) + (((class color) (background dark)) (:foreground "Red")) + (t (:slant italic))) + "Face for the result of an evaluation in the SLIME REPL." + :group 'slime-repl) + +;; FIXME: This conditional is not right - just used because the code +;; here does not work in XEmacs. +(when (boundp 'text-property-default-nonsticky) + (pushnew '(slime-repl-presentation . t) text-property-default-nonsticky + :test 'equal) + (pushnew '(slime-repl-result-face . t) text-property-default-nonsticky + :test 'equal)) + +(make-variable-buffer-local + (defvar slime-presentation-start-to-point (make-hash-table))) + +(defun slime-mark-presentation-start (id &optional target) + "Mark the beginning of a presentation with the given ID. +TARGET can be nil (regular process output) or :repl-result." + (setf (gethash id slime-presentation-start-to-point) + ;; We use markers because text can also be inserted before this presentation. + ;; (Output arrives while we are writing presentations within REPL results.) + (copy-marker (slime-repl-output-target-marker target) nil))) + +(defun slime-mark-presentation-start-handler (process string) + (if (and string (string-match "<\\([-0-9]+\\)" string)) + (let* ((match (substring string (match-beginning 1) (match-end 1))) + (id (car (read-from-string match)))) + (slime-mark-presentation-start id)))) + +(defun slime-mark-presentation-end (id &optional target) + "Mark the end of a presentation with the given ID. +TARGET can be nil (regular process output) or :repl-result." + (let ((start (gethash id slime-presentation-start-to-point))) + (remhash id slime-presentation-start-to-point) + (when start + (let* ((marker (slime-repl-output-target-marker target)) + (buffer (and marker (marker-buffer marker)))) + (with-current-buffer buffer + (let ((end (marker-position marker))) + (slime-add-presentation-properties start end + id nil))))))) + +(defun slime-mark-presentation-end-handler (process string) + (if (and string (string-match ">\\([-0-9]+\\)" string)) + (let* ((match (substring string (match-beginning 1) (match-end 1))) + (id (car (read-from-string match)))) + (slime-mark-presentation-end id)))) + +(cl-defstruct slime-presentation text id) + +(defvar slime-presentation-syntax-table + (let ((table (copy-syntax-table lisp-mode-syntax-table))) + ;; We give < and > parenthesis syntax, so that #< ... > is treated + ;; as a balanced expression. This allows to use C-M-k, C-M-SPC, + ;; etc. to deal with a whole presentation. (For Lisp mode, this + ;; is not desirable, since we do not wish to get a mismatched + ;; paren highlighted everytime we type < or >.) + (modify-syntax-entry ?< "(>" table) + (modify-syntax-entry ?> ")<" table) + table) + "Syntax table for presentations.") + +(defun slime-add-presentation-properties (start end id result-p) + "Make the text between START and END a presentation with ID. +RESULT-P decides whether a face for a return value or output text is used." + (let* ((text (buffer-substring-no-properties start end)) + (presentation (make-slime-presentation :text text :id id))) + (let ((inhibit-modification-hooks t)) + (add-text-properties start end + `(modification-hooks (slime-after-change-function) + insert-in-front-hooks (slime-after-change-function) + insert-behind-hooks (slime-after-change-function) + syntax-table ,slime-presentation-syntax-table + rear-nonsticky t)) + ;; Use the presentation as the key of a text property + (case (- end start) + (0) + (1 + (add-text-properties start end + `(slime-repl-presentation ,presentation + ,presentation :start-and-end))) + (t + (add-text-properties start (1+ start) + `(slime-repl-presentation ,presentation + ,presentation :start)) + (when (> (- end start) 2) + (add-text-properties (1+ start) (1- end) + `(,presentation :interior))) + (add-text-properties (1- end) end + `(slime-repl-presentation ,presentation + ,presentation :end)))) + ;; Also put an overlay for the face and the mouse-face. This enables + ;; highlighting of nested presentations. However, overlays get lost + ;; when we copy a presentation; their removal is also not undoable. + ;; In these cases the mouse-face text properties need to take over --- + ;; but they do not give nested highlighting. + (slime-ensure-presentation-overlay start end presentation)))) + +(defvar slime-presentation-map (make-sparse-keymap)) + +(defun slime-ensure-presentation-overlay (start end presentation) + (unless (cl-find presentation (overlays-at start) + :key (lambda (overlay) + (overlay-get overlay 'slime-repl-presentation))) + (let ((overlay (make-overlay start end (current-buffer) t nil))) + (overlay-put overlay 'slime-repl-presentation presentation) + (overlay-put overlay 'mouse-face 'slime-repl-output-mouseover-face) + (overlay-put overlay 'help-echo + (if (eq major-mode 'slime-repl-mode) + "mouse-2: copy to input; mouse-3: menu" + "mouse-2: inspect; mouse-3: menu")) + (overlay-put overlay 'face 'slime-repl-inputed-output-face) + (overlay-put overlay 'keymap slime-presentation-map)))) + +(defun slime-remove-presentation-properties (from to presentation) + (let ((inhibit-read-only t)) + (remove-text-properties from to + `(,presentation t syntax-table t rear-nonsticky t)) + (when (eq (get-text-property from 'slime-repl-presentation) presentation) + (remove-text-properties from (1+ from) `(slime-repl-presentation t))) + (when (eq (get-text-property (1- to) 'slime-repl-presentation) presentation) + (remove-text-properties (1- to) to `(slime-repl-presentation t))) + (dolist (overlay (overlays-at from)) + (when (eq (overlay-get overlay 'slime-repl-presentation) presentation) + (delete-overlay overlay))))) + +(defun slime-insert-presentation (string output-id &optional rectangle) + "Insert STRING in current buffer and mark it as a presentation +corresponding to OUTPUT-ID. If RECTANGLE is true, indent multi-line +strings to line up below the current point." + (cl-labels ((insert-it () + (if rectangle + (slime-insert-indented string) + (insert string)))) + (let ((start (point))) + (insert-it) + (slime-add-presentation-properties start (point) output-id t)))) + +(defun slime-presentation-whole-p (presentation start end &optional object) + (let ((object (or object (current-buffer)))) + (string= (etypecase object + (buffer (with-current-buffer object + (buffer-substring-no-properties start end))) + (string (substring-no-properties object start end))) + (slime-presentation-text presentation)))) + +(defun slime-presentations-around-point (point &optional object) + (let ((object (or object (current-buffer)))) + (loop for (key value . rest) on (text-properties-at point object) by 'cddr + when (slime-presentation-p key) + collect key))) + +(defun slime-presentation-start-p (tag) + (memq tag '(:start :start-and-end))) + +(defun slime-presentation-stop-p (tag) + (memq tag '(:end :start-and-end))) + +(cl-defun slime-presentation-start (point presentation + &optional (object (current-buffer))) + "Find start of `presentation' at `point' in `object'. +Return buffer index and whether a start-tag was found." + (let* ((this-presentation (get-text-property point presentation object))) + (while (not (slime-presentation-start-p this-presentation)) + (let ((change-point (previous-single-property-change + point presentation object (point-min)))) + (unless change-point + (return-from slime-presentation-start + (values (etypecase object + (buffer (with-current-buffer object 1)) + (string 0)) + nil))) + (setq this-presentation (get-text-property change-point + presentation object)) + (unless this-presentation + (return-from slime-presentation-start + (values point nil))) + (setq point change-point))) + (values point t))) + +(cl-defun slime-presentation-end (point presentation + &optional (object (current-buffer))) + "Find end of presentation at `point' in `object'. Return buffer +index (after last character of the presentation) and whether an +end-tag was found." + (let* ((this-presentation (get-text-property point presentation object))) + (while (not (slime-presentation-stop-p this-presentation)) + (let ((change-point (next-single-property-change + point presentation object))) + (unless change-point + (return-from slime-presentation-end + (values (etypecase object + (buffer (with-current-buffer object (point-max))) + (string (length object))) + nil))) + (setq point change-point) + (setq this-presentation (get-text-property point + presentation object)))) + (if this-presentation + (let ((after-end (next-single-property-change point + presentation object))) + (if (not after-end) + (values (etypecase object + (buffer (with-current-buffer object (point-max))) + (string (length object))) + t) + (values after-end t))) + (values point nil)))) + +(cl-defun slime-presentation-bounds (point presentation + &optional (object (current-buffer))) + "Return start index and end index of `presentation' around `point' +in `object', and whether the presentation is complete." + (multiple-value-bind (start good-start) + (slime-presentation-start point presentation object) + (multiple-value-bind (end good-end) + (slime-presentation-end point presentation object) + (values start end + (and good-start good-end + (slime-presentation-whole-p presentation + start end object)))))) + +(defun slime-presentation-around-point (point &optional object) + "Return presentation, start index, end index, and whether the +presentation is complete." + (let ((object (or object (current-buffer))) + (innermost-presentation nil) + (innermost-start 0) + (innermost-end most-positive-fixnum)) + (dolist (presentation (slime-presentations-around-point point object)) + (multiple-value-bind (start end whole-p) + (slime-presentation-bounds point presentation object) + (when whole-p + (when (< (- end start) (- innermost-end innermost-start)) + (setq innermost-start start + innermost-end end + innermost-presentation presentation))))) + (values innermost-presentation + innermost-start innermost-end))) + +(defun slime-presentation-around-or-before-point (point &optional object) + (let ((object (or object (current-buffer)))) + (multiple-value-bind (presentation start end whole-p) + (slime-presentation-around-point point object) + (if (or presentation (= point (point-min))) + (values presentation start end whole-p) + (slime-presentation-around-point (1- point) object))))) + +(defun slime-presentation-around-or-before-point-or-error (point) + (multiple-value-bind (presentation start end whole-p) + (slime-presentation-around-or-before-point point) + (unless presentation + (error "No presentation at point")) + (values presentation start end whole-p))) + +(cl-defun slime-for-each-presentation-in-region (from to function + &optional (object (current-buffer))) + "Call `function' with arguments `presentation', `start', `end', +`whole-p' for every presentation in the region `from'--`to' in the +string or buffer `object'." + (cl-labels ((handle-presentation (presentation point) + (multiple-value-bind (start end whole-p) + (slime-presentation-bounds point presentation object) + (funcall function presentation start end whole-p)))) + ;; Handle presentations active at `from'. + (dolist (presentation (slime-presentations-around-point from object)) + (handle-presentation presentation from)) + ;; Use the `slime-repl-presentation' property to search for new presentations. + (let ((point from)) + (while (< point to) + (setq point (next-single-property-change point 'slime-repl-presentation + object to)) + (let* ((presentation (get-text-property point 'slime-repl-presentation object)) + (status (get-text-property point presentation object))) + (when (slime-presentation-start-p status) + (handle-presentation presentation point))))))) + +;; XEmacs compatibility hack, from message by Stephen J. Turnbull on +;; xemacs-beta@xemacs.org of 18 Mar 2002 +(unless (boundp 'undo-in-progress) + (defvar undo-in-progress nil + "Placeholder defvar for XEmacs compatibility from SLIME.") + (defadvice undo-more (around slime activate) + (let ((undo-in-progress t)) ad-do-it))) + +(defun slime-after-change-function (start end &rest ignore) + "Check all presentations within and adjacent to the change. +When a presentation has been altered, change it to plain text." + (let ((inhibit-modification-hooks t)) + (let ((real-start (max 1 (1- start))) + (real-end (min (1+ (buffer-size)) (1+ end))) + (any-change nil)) + ;; positions around the change + (slime-for-each-presentation-in-region + real-start real-end + (lambda (presentation from to whole-p) + (cond + (whole-p + (slime-ensure-presentation-overlay from to presentation)) + ((not undo-in-progress) + (slime-remove-presentation-properties from to + presentation) + (setq any-change t))))) + (when any-change + (undo-boundary))))) + +(defun slime-presentation-around-click (event) + "Return the presentation around the position of the mouse-click EVENT. +If there is no presentation, signal an error. +Also return the start position, end position, and buffer of the presentation." + (when (and (featurep 'xemacs) (not (button-press-event-p event))) + (error "Command must be bound to a button-press-event")) + (let ((point (if (featurep 'xemacs) (event-point event) (posn-point (event-end event)))) + (window (if (featurep 'xemacs) (event-window event) (caadr event)))) + (with-current-buffer (window-buffer window) + (multiple-value-bind (presentation start end) + (slime-presentation-around-point point) + (unless presentation + (error "No presentation at click")) + (values presentation start end (current-buffer)))))) + +(defun slime-check-presentation (from to buffer presentation) + (unless (slime-eval `(cl:nth-value 1 (swank:lookup-presented-object + ',(slime-presentation-id presentation)))) + (with-current-buffer buffer + (slime-remove-presentation-properties from to presentation)))) + +(defun slime-copy-or-inspect-presentation-at-mouse (event) + (interactive "e") ; no "@" -- we don't want to select the clicked-at window + (multiple-value-bind (presentation start end buffer) + (slime-presentation-around-click event) + (slime-check-presentation start end buffer presentation) + (if (with-current-buffer buffer + (eq major-mode 'slime-repl-mode)) + (slime-copy-presentation-at-mouse-to-repl event) + (slime-inspect-presentation-at-mouse event)))) + +(defun slime-inspect-presentation (presentation start end buffer) + (let ((reset-p + (with-current-buffer buffer + (not (eq major-mode 'slime-inspector-mode))))) + (slime-eval-async `(swank:inspect-presentation ',(slime-presentation-id presentation) ,reset-p) + 'slime-open-inspector))) + +(defun slime-inspect-presentation-at-mouse (event) + (interactive "e") + (multiple-value-bind (presentation start end buffer) + (slime-presentation-around-click event) + (slime-inspect-presentation presentation start end buffer))) + +(defun slime-inspect-presentation-at-point (point) + (interactive "d") + (multiple-value-bind (presentation start end) + (slime-presentation-around-or-before-point-or-error point) + (slime-inspect-presentation presentation start end (current-buffer)))) + + +(defun slime-M-.-presentation (presentation start end buffer &optional where) + (let* ((id (slime-presentation-id presentation)) + (presentation-string (format "Presentation %s" id)) + (location (slime-eval `(swank:find-definition-for-thing + (swank:lookup-presented-object + ',(slime-presentation-id presentation)))))) + (unless (eq (car location) :error) + (slime-edit-definition-cont + (and location (list (make-slime-xref :dspec `(,presentation-string) + :location location))) + presentation-string + where)))) + +(defun slime-M-.-presentation-at-mouse (event) + (interactive "e") + (multiple-value-bind (presentation start end buffer) + (slime-presentation-around-click event) + (slime-M-.-presentation presentation start end buffer))) + +(defun slime-M-.-presentation-at-point (point) + (interactive "d") + (multiple-value-bind (presentation start end) + (slime-presentation-around-or-before-point-or-error point) + (slime-M-.-presentation presentation start end (current-buffer)))) + +(defun slime-edit-presentation (name &optional where) + (if (or current-prefix-arg (not (equal (slime-symbol-at-point) name))) + nil ; NAME came from user explicitly, so decline. + (multiple-value-bind (presentation start end whole-p) + (slime-presentation-around-or-before-point (point)) + (when presentation + (slime-M-.-presentation presentation start end (current-buffer) where))))) + +(defun slime-copy-presentation-to-repl (presentation start end buffer) + (let ((text (with-current-buffer buffer + ;; we use the buffer-substring rather than the + ;; presentation text to capture any overlays + (buffer-substring start end))) + (id (slime-presentation-id presentation))) + (unless (integerp id) + (setq id (slime-eval `(swank:lookup-and-save-presented-object-or-lose ',id)))) + (unless (eql major-mode 'slime-repl-mode) + (slime-switch-to-output-buffer)) + (cl-flet ((do-insertion () + (unless (looking-back "\\s-" (- (point) 1)) + (insert " ")) + (slime-insert-presentation text id) + (unless (or (eolp) (looking-at "\\s-")) + (insert " ")))) + (if (>= (point) slime-repl-prompt-start-mark) + (do-insertion) + (save-excursion + (goto-char (point-max)) + (do-insertion)))))) + +(defun slime-copy-presentation-at-mouse-to-repl (event) + (interactive "e") + (multiple-value-bind (presentation start end buffer) + (slime-presentation-around-click event) + (slime-copy-presentation-to-repl presentation start end buffer))) + +(defun slime-copy-presentation-at-point-to-repl (point) + (interactive "d") + (multiple-value-bind (presentation start end) + (slime-presentation-around-or-before-point-or-error point) + (slime-copy-presentation-to-repl presentation start end (current-buffer)))) + +(defun slime-copy-presentation-at-mouse-to-point (event) + (interactive "e") + (multiple-value-bind (presentation start end buffer) + (slime-presentation-around-click event) + (let ((presentation-text + (with-current-buffer buffer + (buffer-substring start end)))) + (when (not (string-match "\\s-" + (buffer-substring (1- (point)) (point)))) + (insert " ")) + (insert presentation-text) + (slime-after-change-function (point) (point)) + (when (and (not (eolp)) (not (looking-at "\\s-"))) + (insert " "))))) + +(defun slime-copy-presentation-to-kill-ring (presentation start end buffer) + (let ((presentation-text + (with-current-buffer buffer + (buffer-substring start end)))) + (kill-new presentation-text) + (message "Saved presentation \"%s\" to kill ring" presentation-text))) + +(defun slime-copy-presentation-at-mouse-to-kill-ring (event) + (interactive "e") + (multiple-value-bind (presentation start end buffer) + (slime-presentation-around-click event) + (slime-copy-presentation-to-kill-ring presentation start end buffer))) + +(defun slime-copy-presentation-at-point-to-kill-ring (point) + (interactive "d") + (multiple-value-bind (presentation start end) + (slime-presentation-around-or-before-point-or-error point) + (slime-copy-presentation-to-kill-ring presentation start end (current-buffer)))) + +(defun slime-describe-presentation (presentation) + (slime-eval-describe + `(swank::describe-to-string + (swank:lookup-presented-object ',(slime-presentation-id presentation))))) + +(defun slime-describe-presentation-at-mouse (event) + (interactive "@e") + (multiple-value-bind (presentation) (slime-presentation-around-click event) + (slime-describe-presentation presentation))) + +(defun slime-describe-presentation-at-point (point) + (interactive "d") + (multiple-value-bind (presentation) + (slime-presentation-around-or-before-point-or-error point) + (slime-describe-presentation presentation))) + +(defun slime-pretty-print-presentation (presentation) + (slime-eval-describe + `(swank::swank-pprint + (cl:list + (swank:lookup-presented-object ',(slime-presentation-id presentation)))))) + +(defun slime-pretty-print-presentation-at-mouse (event) + (interactive "@e") + (multiple-value-bind (presentation) (slime-presentation-around-click event) + (slime-pretty-print-presentation presentation))) + +(defun slime-pretty-print-presentation-at-point (point) + (interactive "d") + (multiple-value-bind (presentation) + (slime-presentation-around-or-before-point-or-error point) + (slime-pretty-print-presentation presentation))) + +(defun slime-mark-presentation (point) + (interactive "d") + (multiple-value-bind (presentation start end) + (slime-presentation-around-or-before-point-or-error point) + (goto-char start) + (push-mark end nil t))) + +(defun slime-previous-presentation (&optional arg) + "Move point to the beginning of the first presentation before point. +With ARG, do this that many times. +A negative argument means move forward instead." + (interactive "p") + (unless arg (setq arg 1)) + (slime-next-presentation (- arg))) + +(defun slime-next-presentation (&optional arg) + "Move point to the beginning of the next presentation after point. +With ARG, do this that many times. +A negative argument means move backward instead." + (interactive "p") + (unless arg (setq arg 1)) + (cond + ((plusp arg) + (dotimes (i arg) + ;; First skip outside the current surrounding presentation (if any) + (multiple-value-bind (presentation start end) + (slime-presentation-around-point (point)) + (when presentation + (goto-char end))) + (let ((p (next-single-property-change (point) 'slime-repl-presentation))) + (unless p + (error "No next presentation")) + (multiple-value-bind (presentation start end) + (slime-presentation-around-or-before-point-or-error p) + (goto-char start))))) + ((minusp arg) + (dotimes (i (- arg)) + ;; First skip outside the current surrounding presentation (if any) + (multiple-value-bind (presentation start end) + (slime-presentation-around-point (point)) + (when presentation + (goto-char start))) + (let ((p (previous-single-property-change (point) 'slime-repl-presentation))) + (unless p + (error "No previous presentation")) + (multiple-value-bind (presentation start end) + (slime-presentation-around-or-before-point-or-error p) + (goto-char start))))))) + +(define-key slime-presentation-map [mouse-2] 'slime-copy-or-inspect-presentation-at-mouse) +(define-key slime-presentation-map [mouse-3] 'slime-presentation-menu) + +(when (featurep 'xemacs) + (define-key slime-presentation-map [button2] 'slime-copy-or-inspect-presentation-at-mouse) + (define-key slime-presentation-map [button3] 'slime-presentation-menu)) + +;; protocol for handling up a menu. +;; 1. Send lisp message asking for menu choices for this object. +;; Get back list of strings. +;; 2. Let used choose +;; 3. Call back to execute menu choice, passing nth and string of choice + +(defun slime-menu-choices-for-presentation (presentation buffer from to choice-to-lambda) + "Return a menu for `presentation' at `from'--`to' in `buffer', suitable for `x-popup-menu'." + (let* ((what (slime-presentation-id presentation)) + (choices (with-current-buffer buffer + (slime-eval + `(swank::menu-choices-for-presentation-id ',what))))) + (cl-labels ((savel (f) ;; IMPORTANT - xemacs can't handle lambdas in x-popup-menu. So give them a name + (let ((sym (cl-gensym))) + (setf (gethash sym choice-to-lambda) f) + sym))) + (etypecase choices + (list + `(,(format "Presentation %s" (truncate-string-to-width + (slime-presentation-text presentation) + 30 nil nil t)) + ("" + ("Find Definition" . ,(savel 'slime-M-.-presentation-at-mouse)) + ("Inspect" . ,(savel 'slime-inspect-presentation-at-mouse)) + ("Describe" . ,(savel 'slime-describe-presentation-at-mouse)) + ("Pretty-print" . ,(savel 'slime-pretty-print-presentation-at-mouse)) + ("Copy to REPL" . ,(savel 'slime-copy-presentation-at-mouse-to-repl)) + ("Copy to kill ring" . ,(savel 'slime-copy-presentation-at-mouse-to-kill-ring)) + ,@(unless buffer-read-only + `(("Copy to point" . ,(savel 'slime-copy-presentation-at-mouse-to-point)))) + ,@(let ((nchoice 0)) + (mapcar + (lambda (choice) + (incf nchoice) + (cons choice + (savel `(lambda () + (interactive) + (slime-eval + '(swank::execute-menu-choice-for-presentation-id + ',what ,nchoice ,(nth (1- nchoice) choices))))))) + choices))))) + (symbol ; not-present + (with-current-buffer buffer + (slime-remove-presentation-properties from to presentation)) + (sit-for 0) ; allow redisplay + `("Object no longer recorded" + ("sorry" . ,(if (featurep 'xemacs) nil '(nil))))))))) + +(defun slime-presentation-menu (event) + (interactive "e") + (let* ((point (if (featurep 'xemacs) (event-point event) + (posn-point (event-end event)))) + (window (if (featurep 'xemacs) (event-window event) (caadr event))) + (buffer (window-buffer window)) + (choice-to-lambda (make-hash-table))) + (multiple-value-bind (presentation from to) + (with-current-buffer buffer + (slime-presentation-around-point point)) + (unless presentation + (error "No presentation at event position")) + (let ((menu (slime-menu-choices-for-presentation + presentation buffer from to choice-to-lambda))) + (let ((choice (x-popup-menu event menu))) + (when choice + (call-interactively (gethash choice choice-to-lambda)))))))) + +(defun slime-presentation-expression (presentation) + "Return a string that contains a CL s-expression accessing +the presented object." + (let ((id (slime-presentation-id presentation))) + (etypecase id + (number + ;; Make sure it works even if *read-base* is not 10. + (format "(swank:lookup-presented-object-or-lose %d.)" id)) + (list + ;; for frame variables and inspector parts + (format "(swank:lookup-presented-object-or-lose '%s)" id))))) + +(defun slime-buffer-substring-with-reified-output (start end) + (let ((str-props (buffer-substring start end)) + (str-no-props (buffer-substring-no-properties start end))) + (slime-reify-old-output str-props str-no-props))) + +(defun slime-reify-old-output (str-props str-no-props) + (let ((pos (slime-property-position 'slime-repl-presentation str-props))) + (if (null pos) + str-no-props + (multiple-value-bind (presentation start-pos end-pos whole-p) + (slime-presentation-around-point pos str-props) + (if (not presentation) + str-no-props + (concat (substring str-no-props 0 pos) + ;; Eval in the reader so that we play nice with quote. + ;; -luke (19/May/2005) + "#." (slime-presentation-expression presentation) + (slime-reify-old-output (substring str-props end-pos) + (substring str-no-props end-pos)))))))) + + + +(defun slime-repl-grab-old-output (replace) + "Resend the old REPL output at point. +If replace it non-nil the current input is replaced with the old +output; otherwise the new input is appended." + (multiple-value-bind (presentation beg end) + (slime-presentation-around-or-before-point (point)) + (slime-check-presentation beg end (current-buffer) presentation) + (let ((old-output (buffer-substring beg end))) ;;keep properties + ;; Append the old input or replace the current input + (cond (replace (goto-char slime-repl-input-start-mark)) + (t (goto-char (point-max)) + (unless (eq (char-before) ?\ ) + (insert " ")))) + (delete-region (point) (point-max)) + (let ((inhibit-read-only t)) + (insert old-output))))) + +;;; Presentation-related key bindings, non-context menu + +(defvar slime-presentation-command-map nil + "Keymap for presentation-related commands. Bound to a prefix key.") + +(defvar slime-presentation-bindings + '((?i slime-inspect-presentation-at-point) + (?d slime-describe-presentation-at-point) + (?w slime-copy-presentation-at-point-to-kill-ring) + (?r slime-copy-presentation-at-point-to-repl) + (?p slime-previous-presentation) + (?n slime-next-presentation) + (?\ slime-mark-presentation))) + +(defun slime-presentation-init-keymaps () + (slime-init-keymap 'slime-presentation-command-map nil t + slime-presentation-bindings) + (define-key slime-presentation-command-map "\M-o" 'slime-clear-presentations) + ;; C-c C-v is the prefix for the presentation-command map. + (define-key slime-prefix-map "\C-v" slime-presentation-command-map)) + +(defun slime-presentation-around-or-before-point-p () + (multiple-value-bind (presentation beg end) + (slime-presentation-around-or-before-point (point)) + presentation)) + +(defvar slime-presentation-easy-menu + (let ((P '(slime-presentation-around-or-before-point-p))) + `("Presentations" + [ "Find Definition" slime-M-.-presentation-at-point ,P ] + [ "Inspect" slime-inspect-presentation-at-point ,P ] + [ "Describe" slime-describe-presentation-at-point ,P ] + [ "Pretty-print" slime-pretty-print-presentation-at-point ,P ] + [ "Copy to REPL" slime-copy-presentation-at-point-to-repl ,P ] + [ "Copy to kill ring" slime-copy-presentation-at-point-to-kill-ring ,P ] + [ "Mark" slime-mark-presentation ,P ] + "--" + [ "Previous presentation" slime-previous-presentation ] + [ "Next presentation" slime-next-presentation ] + "--" + [ "Clear all presentations" slime-clear-presentations ]))) + +(defun slime-presentation-add-easy-menu () + (easy-menu-define menubar-slime-presentation slime-mode-map "Presentations" slime-presentation-easy-menu) + (easy-menu-define menubar-slime-presentation slime-repl-mode-map "Presentations" slime-presentation-easy-menu) + (easy-menu-define menubar-slime-presentation sldb-mode-map "Presentations" slime-presentation-easy-menu) + (easy-menu-define menubar-slime-presentation slime-inspector-mode-map "Presentations" slime-presentation-easy-menu) + (easy-menu-add slime-presentation-easy-menu 'slime-mode-map) + (easy-menu-add slime-presentation-easy-menu 'slime-repl-mode-map) + (easy-menu-add slime-presentation-easy-menu 'sldb-mode-map) + (easy-menu-add slime-presentation-easy-menu 'slime-inspector-mode-map)) + +;;; hook functions (hard to isolate stuff) + +(defun slime-dispatch-presentation-event (event) + (slime-dcase event + ((:presentation-start id &optional target) + (slime-mark-presentation-start id target) + t) + ((:presentation-end id &optional target) + (slime-mark-presentation-end id target) + t) + (t nil))) + +(defun slime-presentation-write-result (string) + (with-current-buffer (slime-output-buffer) + (let ((marker (slime-repl-output-target-marker :repl-result)) + (saved-point (point-marker))) + (goto-char marker) + (slime-propertize-region `(face slime-repl-result-face + rear-nonsticky (face)) + (insert string)) + ;; Move the input-start marker after the REPL result. + (set-marker marker (point)) + (set-marker slime-output-end (point)) + ;; Restore point before insertion but only it if was farther + ;; than `marker'. Omitting this breaks REPL test + ;; `repl-type-ahead'. + (when (> saved-point (point)) + (goto-char saved-point))) + (slime-repl-show-maximum-output))) + +(defun slime-presentation-write (string &optional target) + (case target + ((nil) ; Regular process output + (slime-repl-emit string)) + (:repl-result + (slime-presentation-write-result string)) + (t (slime-repl-emit-to-target string target)))) + +(defun slime-presentation-current-input (&optional until-point-p) + "Return the current input as string. +The input is the region from after the last prompt to the end of +buffer. Presentations of old results are expanded into code." + (slime-buffer-substring-with-reified-output slime-repl-input-start-mark + (if until-point-p + (point) + (point-max)))) + +(defun slime-presentation-on-return-pressed (end-of-input) + (when (and (car (slime-presentation-around-or-before-point (point))) + (< (point) slime-repl-input-start-mark)) + (slime-repl-grab-old-output end-of-input) + (slime-repl-recenter-if-needed) + t)) + +(defun slime-presentation-bridge-insert (process output) + (slime-output-filter process (or output ""))) + +(defun slime-presentation-on-stream-open (stream) + (install-bridge) + (setq bridge-insert-function #'slime-presentation-bridge-insert) + (setq bridge-destination-insert nil) + (setq bridge-source-insert nil) + (setq bridge-handlers + (list* '("<" . slime-mark-presentation-start-handler) + '(">" . slime-mark-presentation-end-handler) + bridge-handlers))) + +(defun slime-clear-presentations () + "Forget all objects associated to SLIME presentations. +This allows the garbage collector to remove these objects +even on Common Lisp implementations without weak hash tables." + (interactive) + (slime-eval-async `(swank:clear-repl-results)) + (unless (eql major-mode 'slime-repl-mode) + (slime-switch-to-output-buffer)) + (slime-for-each-presentation-in-region 1 (1+ (buffer-size)) + (lambda (presentation from to whole-p) + (slime-remove-presentation-properties from to + presentation)))) + +(defun slime-presentation-inspector-insert-ispec (ispec) + (if (stringp ispec) + (insert ispec) + (slime-dcase ispec + ((:value string id) + (slime-propertize-region + (list 'slime-part-number id + 'mouse-face 'highlight + 'face 'slime-inspector-value-face) + (slime-insert-presentation string `(:inspected-part ,id) t))) + ((:label string) + (insert (slime-inspector-fontify label string))) + ((:action string id) + (slime-insert-propertized (list 'slime-action-number id + 'mouse-face 'highlight + 'face 'slime-inspector-action-face) + string))))) + +(defun slime-presentation-sldb-insert-frame-variable-value (value frame index) + (slime-insert-presentation + (sldb-in-face local-value value) + `(:frame-var ,slime-current-thread ,(car frame) ,index) t)) + +(defun slime-presentations-on-connected () + (slime-eval-async `(swank:init-presentations))) + +(provide 'slime-presentations) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-quicklisp.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-quicklisp.el new file mode 100644 index 0000000..97f5ece --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-quicklisp.el @@ -0,0 +1,51 @@ +(require 'slime) +(require 'cl-lib) + +;;; bits of the following taken from slime-asdf.el + +(define-slime-contrib slime-quicklisp + "Quicklisp support." + (:authors "Matthew Kennedy ") + (:license "GPL") + (:slime-dependencies slime-repl) + (:swank-dependencies swank-quicklisp)) + +;;; Utilities + +(defgroup slime-quicklisp nil + "Quicklisp support for Slime." + :prefix "slime-quicklisp-" + :group 'slime) + +(defvar slime-quicklisp-system-history nil + "History list for Quicklisp system names.") + + + +(defun slime-read-quicklisp-system-name (&optional prompt default-value) + "Read a Quick system name from the minibuffer, prompting with PROMPT." + (let* ((completion-ignore-case nil) + (prompt (or prompt "Quicklisp system")) + (quicklisp-system-names (slime-eval `(swank:list-quicklisp-systems))) + (prompt (concat prompt (if default-value + (format " (default `%s'): " default-value) + ": ")))) + (completing-read prompt (slime-bogus-completion-alist quicklisp-system-names) + nil nil nil + 'slime-quicklisp-system-history default-value))) + +(defun slime-quicklisp-quickload (system) + "Load a Quicklisp system." + (slime-save-some-lisp-buffers) + (slime-display-output-buffer) + (slime-repl-shortcut-eval-async `(ql:quickload ,system))) + +;;; REPL shortcuts + +(defslime-repl-shortcut slime-repl-quicklisp-quickload ("quicklisp-quickload" "ql") + (:handler (lambda () + (interactive) + (slime-quicklisp-quickload (slime-read-quicklisp-system-name)))) + (:one-liner "Load a system known to Quicklisp.")) + +(provide 'slime-quicklisp) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-references.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-references.el new file mode 100644 index 0000000..93389ae --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-references.el @@ -0,0 +1,156 @@ +(require 'slime) +(require 'advice) +(require 'slime-compiler-notes-tree) ; FIXME: actually only uses the tree bits, so that should be a library. + +(define-slime-contrib slime-references + "Clickable references to documentation (SBCL only)." + (:authors "Christophe Rhodes " + "Luke Gorrie " + "Tobias C. Rittweiler ") + (:license "GPL") + (:on-load + (ad-enable-advice 'slime-note.message 'after 'slime-note.message+references) + (ad-activate 'slime-note.message) + (setq slime-tree-printer 'slime-tree-print-with-references) + (add-hook 'sldb-extras-hooks 'sldb-maybe-insert-references)) + (:on-unload + (ad-disable-advice 'slime-note.message 'after 'slime-note.message+references) + (ad-deactivate 'slime-note.message) + (setq slime-tree-printer 'slime-tree-default-printer) + (remove-hook 'sldb-extras-hooks 'sldb-maybe-insert-references))) + +(defcustom slime-sbcl-manual-root "http://www.sbcl.org/manual/" + "*The base URL of the SBCL manual, for documentation lookup." + :type '(choice (string :tag "HTML Documentation") + (const :tag "Info Documentation" :info)) + :group 'slime-mode) + +(defface sldb-reference-face + (list (list t '(:underline t))) + "Face for references." + :group 'slime-debugger) + + +;;;;; SBCL-style references + +(defvar slime-references-local-keymap + (let ((map (make-sparse-keymap "local keymap for slime references"))) + (define-key map [mouse-2] 'slime-lookup-reference-at-mouse) + (define-key map [return] 'slime-lookup-reference-at-point) + map)) + +(defun slime-reference-properties (reference) + "Return the properties for a reference. +Only add clickability to properties we actually know how to lookup." + (cl-destructuring-bind (where type what) reference + (if (or (and (eq where :sbcl) (eq type :node)) + (and (eq where :ansi-cl) + (memq type '(:function :special-operator :macro + :type :system-class + :section :glossary :issue)))) + `(slime-reference ,reference + font-lock-face sldb-reference-face + follow-link t + mouse-face highlight + help-echo "mouse-2: visit documentation." + keymap ,slime-references-local-keymap)))) + +(defun slime-insert-reference (reference) + "Insert documentation reference from a condition. +See SWANK-BACKEND:CONDITION-REFERENCES for the datatype." + (cl-destructuring-bind (where type what) reference + (insert "\n" (slime-format-reference-source where) ", ") + (slime-insert-propertized (slime-reference-properties reference) + (slime-format-reference-node what)) + (insert (format " [%s]" type)))) + +(defun slime-insert-references (references) + (when references + (insert "\nSee also:") + (slime-with-rigid-indentation 2 + (mapc #'slime-insert-reference references)))) + +(defun slime-format-reference-source (where) + (cl-case where + (:amop "The Art of the Metaobject Protocol") + (:ansi-cl "Common Lisp Hyperspec") + (:sbcl "SBCL Manual") + (t (format "%S" where)))) + +(defun slime-format-reference-node (what) + (if (listp what) + (mapconcat #'prin1-to-string what ".") + what)) + +(defun slime-lookup-reference-at-point () + "Browse the documentation reference at point." + (interactive) + (let ((refs (get-text-property (point) 'slime-reference))) + (if (null refs) + (error "No references at point") + (cl-destructuring-bind (where type what) refs + (cl-case where + (:ansi-cl + (cl-case type + (:section + (browse-url (funcall common-lisp-hyperspec-section-fun what))) + (:glossary + (browse-url (funcall common-lisp-hyperspec-glossary-function what))) + (:issue + (browse-url (common-lisp-issuex what))) + (:special-operator + (browse-url (common-lisp-special-operator (downcase name)))) + (t + (hyperspec-lookup what)))) + (t + (case slime-sbcl-manual-root + (:info + (info (format "(sbcl)%s" what))) + (t + (browse-url + (format "%s#%s" slime-sbcl-manual-root + (subst-char-in-string ?\ ?\- what))))))))))) + +(defun slime-lookup-reference-at-mouse (event) + "Invoke the action pointed at by the mouse." + (interactive "e") + (cl-destructuring-bind (mouse-1 (w pos . _) . _) event + (save-excursion + (goto-char pos) + (slime-lookup-reference-at-point)))) + +;;;;; Hook into *SLIME COMPILATION* + +(defun slime-note.references (note) + (plist-get note :references)) + +;;; FIXME: `compilation-mode' will swallow the `mouse-face' +;;; etc. properties. +(defadvice slime-note.message (after slime-note.message+references) + (setq ad-return-value + (concat ad-return-value + (with-temp-buffer + (slime-insert-references + (slime-note.references (ad-get-arg 0))) + (buffer-string))))) + +;;;;; Hook into slime-compiler-notes-tree + +(defun slime-tree-print-with-references (tree) + ;; for SBCL-style references + (slime-tree-default-printer tree) + (let ((note (plist-get (slime-tree.plist tree) 'note))) + (when note + (let ((references (slime-note.references note))) + (when references + (terpri (current-buffer)) + (slime-insert-references references)))))) + +;;;;; Hook into SLDB + +(defun sldb-maybe-insert-references (extra) + (slime-dcase extra + ((:references references) (slime-insert-references references) t) + (t nil))) + +(provide 'slime-references) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-repl.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-repl.el new file mode 100644 index 0000000..91e7b61 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-repl.el @@ -0,0 +1,1770 @@ +;;; slime-repl.el --- +;; +;; Original Author: Helmut Eller +;; Contributors: too many to mention +;; License: GNU GPL (same license as Emacs) +;; +;;; Description: +;; + +;; +;;; Installation: +;; +;; Call slime-setup and include 'slime-repl as argument: +;; +;; (slime-setup '(slime-repl [others conribs ...])) +;; +(require 'slime) +(require 'slime-parse) +(require 'cl-lib) +(eval-when-compile (require 'cl)) ; slime-def-connection-var, which + ; expands to defsetf not in cl-lib + +(define-slime-contrib slime-repl + "Read-Eval-Print Loop written in Emacs Lisp. + +This contrib implements a Lisp Listener along with some niceties like +a persistent history and various \"shortcut\" commands. Nothing here +depends on comint.el; I/O is multiplexed over SLIME's socket. + +This used to be the default REPL for SLIME, but it was hard to +maintain." + (:authors "too many to mention") + (:license "GPL") + (:on-load + (slime-repl-add-hooks) + (setq slime-find-buffer-package-function 'slime-repl-find-buffer-package)) + (:on-unload (slime-repl-remove-hooks)) + (:swank-dependencies swank-repl)) + +;;;;; slime-repl + +(defgroup slime-repl nil + "The Read-Eval-Print Loop (*slime-repl* buffer)." + :prefix "slime-repl-" + :group 'slime) + +(defcustom slime-repl-shortcut-dispatch-char ?\, + "Character used to distinguish repl commands from lisp forms." + :type '(character) + :group 'slime-repl) + +(defcustom slime-repl-only-save-lisp-buffers t + "When T we only attempt to save lisp-mode file buffers. When + NIL slime will attempt to save all buffers (as per + save-some-buffers). This applies to all ASDF related repl + shortcuts." + :type '(boolean) + :group 'slime-repl) + +(defcustom slime-repl-auto-right-margin nil + "When T we bind CL:*PRINT-RIGHT-MARGIN* to the width of the +current repl's (as per slime-output-buffer) window." + :type '(boolean) + :group 'slime-repl) + +(defface slime-repl-prompt-face + '((t (:inherit font-lock-keyword-face))) + "Face for the prompt in the SLIME REPL." + :group 'slime-repl) + +(defface slime-repl-output-face + '((t (:inherit font-lock-string-face))) + "Face for Lisp output in the SLIME REPL." + :group 'slime-repl) + +(defface slime-repl-input-face + '((t (:bold t))) + "Face for previous input in the SLIME REPL." + :group 'slime-repl) + +(defface slime-repl-result-face + '((t ())) + "Face for the result of an evaluation in the SLIME REPL." + :group 'slime-repl) + +(defcustom slime-repl-history-file "~/.slime-history.eld" + "File to save the persistent REPL history to." + :type 'string + :group 'slime-repl) + +(defcustom slime-repl-history-size 200 + "*Maximum number of lines for persistent REPL history." + :type 'integer + :group 'slime-repl) + +(defcustom slime-repl-history-file-coding-system + (cond ((slime-find-coding-system 'utf-8-unix) 'utf-8-unix) + (t slime-net-coding-system)) + "*The coding system for the history file." + :type 'symbol + :group 'slime-repl) + + +;; dummy defvar for compiler +(defvar slime-repl-read-mode) + +(defun slime-reading-p () + "True if Lisp is currently reading input from the REPL." + (with-current-buffer (slime-output-buffer) + slime-repl-read-mode)) + + +;;;; Stream output + +(slime-def-connection-var slime-connection-output-buffer nil + "The buffer for the REPL. May be nil or a dead buffer.") + +(make-variable-buffer-local + (defvar slime-output-start nil + "Marker for the start of the output for the evaluation.")) + +(make-variable-buffer-local + (defvar slime-output-end nil + "Marker for end of output. New output is inserted at this mark.")) + +;; dummy definitions for the compiler +(defvar slime-repl-package-stack) +(defvar slime-repl-directory-stack) +(defvar slime-repl-input-start-mark) +(defvar slime-repl-prompt-start-mark) + +(defun slime-output-buffer (&optional noprompt) + "Return the output buffer, create it if necessary." + (let ((buffer (slime-connection-output-buffer))) + (or (if (buffer-live-p buffer) buffer) + (setf (slime-connection-output-buffer) + (let ((connection (slime-connection))) + (with-current-buffer (slime-repl-buffer t connection) + (unless (eq major-mode 'slime-repl-mode) + (slime-repl-mode)) + (setq slime-buffer-connection connection) + (setq slime-buffer-package (slime-lisp-package connection)) + (slime-reset-repl-markers) + (unless noprompt + (slime-repl-insert-prompt)) + (current-buffer))))))) + +(defvar slime-repl-banner-function 'slime-repl-insert-banner) + +(defun slime-repl-update-banner () + (funcall slime-repl-banner-function) + (slime-move-point (point-max)) + (slime-mark-output-start) + (slime-mark-input-start) + (slime-repl-insert-prompt)) + +(defun slime-repl-insert-banner () + (when (zerop (buffer-size)) + (let ((welcome (concat "; SLIME " slime-version))) + (insert welcome)))) + +(defun slime-init-output-buffer (connection) + (with-current-buffer (slime-output-buffer t) + (setq slime-buffer-connection connection + slime-repl-directory-stack '() + slime-repl-package-stack '()) + (slime-repl-update-banner))) + +(defun slime-display-output-buffer () + "Display the output buffer and scroll to bottom." + (with-current-buffer (slime-output-buffer) + (goto-char (point-max)) + (unless (get-buffer-window (current-buffer) t) + (display-buffer (current-buffer) t)) + (slime-repl-show-maximum-output))) + +(defun slime-output-filter (process string) + (with-current-buffer (process-buffer process) + (when (and (plusp (length string)) + (eq (process-status slime-buffer-connection) 'open)) + (slime-write-string string)))) + +(defvar slime-open-stream-hooks) + +(defun slime-open-stream-to-lisp (port coding-system) + (let ((stream (open-network-stream "*lisp-output-stream*" + (slime-with-connection-buffer () + (current-buffer)) + (car (process-contact (slime-connection))) + port)) + (emacs-coding-system (car (cl-find coding-system + slime-net-valid-coding-systems + :key #'cl-third)))) + (slime-set-query-on-exit-flag stream) + (set-process-filter stream 'slime-output-filter) + (set-process-coding-system stream emacs-coding-system emacs-coding-system) + (let ((secret (slime-secret))) + (when secret + (slime-net-send secret stream))) + (run-hook-with-args 'slime-open-stream-hooks stream) + stream)) + +(defun slime-io-speed-test (&optional profile) + "A simple minded benchmark for stream performance. +If a prefix argument is given, instrument the slime package for +profiling before running the benchmark." + (interactive "P") + (eval-and-compile + (require 'elp)) + (elp-reset-all) + (elp-restore-all) + (load "slime.el") + ;;(byte-compile-file "slime-net.el" t) + ;;(setq slime-log-events nil) + (setq slime-enable-evaluate-in-emacs t) + ;;(setq slime-repl-enable-presentations nil) + (when profile + (elp-instrument-package "slime-")) + (kill-buffer (slime-output-buffer)) + (switch-to-buffer (slime-output-buffer)) + (delete-other-windows) + (sit-for 0) + (slime-repl-send-string "(swank:io-speed-test 4000 1)") + (let ((proc (slime-inferior-process))) + (when proc + (display-buffer (process-buffer proc) t) + (goto-char (point-max))))) + +(defvar slime-write-string-function 'slime-repl-write-string) + +(defun slime-write-string (string &optional target) + "Insert STRING in the REPL buffer or some other TARGET. +If TARGET is nil, insert STRING as regular process +output. If TARGET is :repl-result, insert STRING as the result of the +evaluation. Other values of TARGET map to an Emacs marker via the +hashtable `slime-output-target-to-marker'; output is inserted at this marker." + (funcall slime-write-string-function string target)) + +(defun slime-repl-write-string (string &optional target) + (case target + ((nil) (slime-repl-emit string)) + (:repl-result (slime-repl-emit-result string t)) + (t (slime-repl-emit-to-target string target)))) + +(defvar slime-repl-popup-on-output nil + "Display the output buffer when some output is written. +This is set to nil after displaying the buffer.") + +(defmacro slime-save-marker (marker &rest body) + (declare (debug (sexp &rest form))) + (let ((pos (cl-gensym "pos"))) + `(let ((,pos (marker-position ,marker))) + (prog1 (progn . ,body) + (set-marker ,marker ,pos))))) + +(put 'slime-save-marker 'lisp-indent-function 1) + +(defun slime-repl-emit (string) + ;; insert the string STRING in the output buffer + (with-current-buffer (slime-output-buffer) + (save-excursion + (goto-char slime-output-end) + (slime-save-marker slime-output-start + (slime-propertize-region '(face slime-repl-output-face + slime-repl-output t + rear-nonsticky (face)) + (let ((inhibit-read-only t)) + (insert-before-markers string) + (when (and (= (point) slime-repl-prompt-start-mark) + (not (bolp))) + (insert-before-markers "\n") + (set-marker slime-output-end (1- (point)))))))) + (when slime-repl-popup-on-output + (setq slime-repl-popup-on-output nil) + (display-buffer (current-buffer))) + (slime-repl-show-maximum-output))) + +(defun slime-repl-emit-result (string &optional bol) + ;; insert STRING and mark it as evaluation result + (with-current-buffer (slime-output-buffer) + (save-excursion + (goto-char slime-repl-input-start-mark) + (slime-save-marker slime-output-start + (goto-char slime-repl-input-start-mark) + (when (and bol (not (bolp))) (insert-before-markers-and-inherit "\n")) + (slime-save-marker slime-output-end + (slime-propertize-region `(face slime-repl-result-face + rear-nonsticky (face)) + (insert-before-markers string))) + (set-marker slime-output-end (point)))) + (slime-repl-show-maximum-output))) + +(defvar slime-last-output-target-id 0 + "The last integer we used as a TARGET id.") + +(defun slime-repl-emit-to-target (string target) + "Insert STRING at target TARGET. +See `slime-output-target-to-marker'." + (let* ((marker (slime-repl-output-target-marker target)) + (buffer (and marker (marker-buffer marker)))) + (when buffer + (with-current-buffer buffer + (save-excursion + ;; Insert STRING at MARKER, then move MARKER behind + ;; the insertion. + (goto-char marker) + (insert-before-markers string) + (set-marker marker (point))))))) + +(defun slime-repl-output-target-marker (target) + (case target + ((nil) + (with-current-buffer (slime-output-buffer) + slime-output-end)) + (:repl-result + (with-current-buffer (slime-output-buffer) + slime-repl-input-start-mark)) + (t + (slime-output-target-marker target)))) + + +(defun slime-switch-to-output-buffer () + "Select the output buffer, when possible in an existing window. + +Hint: You can use `display-buffer-reuse-frames' and +`special-display-buffer-names' to customize the frame in which +the buffer should appear." + (interactive) + (pop-to-buffer (slime-output-buffer)) + (goto-char (point-max))) + + +;;;; REPL +;; +;; The REPL uses some markers to separate input from output. The +;; usual configuration is as follows: +;; +;; ... output ... ... result ... prompt> ... input ... +;; ^ ^ ^ ^ ^ +;; output-start output-end prompt-start input-start point-max +;; +;; input-start is a right inserting marker, because +;; we want it to stay behind when the user inserts text. +;; +;; We maintain the following invariant: +;; +;; output-start <= output-end <= input-start. +;; +;; This invariant is important, because we must be prepared for +;; asynchronous output and asynchronous reads. ("Asynchronous" means, +;; triggered by Lisp and not by Emacs.) +;; +;; All output is inserted at the output-end marker. Some care must be +;; taken when output-end and input-start are at the same position: if +;; we insert at that point, we must move the right markers. We should +;; also not leave (window-)point in the middle of the new output. The +;; idiom we use is a combination to slime-save-marker, +;; insert-before-markers, and manually updating window-point +;; afterwards. +;; +;; A "synchronous" evaluation request proceeds as follows: the user +;; inserts some text between input-start and point-max and then hits +;; return. We send that region to Lisp, move the output and input +;; makers to the line after the input and wait. When we receive the +;; result, we insert it together with a prompt between the output-end +;; and input-start mark. See `slime-repl-insert-prompt'. +;; +;; It is possible that some output for such an evaluation request +;; arrives after the result. This output is inserted before the +;; result (and before the prompt). +;; +;; If we are in "reading" state, e.g., during a call to Y-OR-N-P, +;; there is no prompt between output-end and input-start. +;; + +;; FIXME: slime-lisp-package should be local in a REPL buffer +(slime-def-connection-var slime-lisp-package + "COMMON-LISP-USER" + "The current package name of the Superior lisp. +This is automatically synchronized from Lisp.") + +(slime-def-connection-var slime-lisp-package-prompt-string + "CL-USER" + "The current package name of the Superior lisp. +This is automatically synchronized from Lisp.") + +(slime-make-variables-buffer-local + (defvar slime-repl-package-stack nil + "The stack of packages visited in this repl.") + + (defvar slime-repl-directory-stack nil + "The stack of default directories associated with this repl.") + + (defvar slime-repl-prompt-start-mark) + (defvar slime-repl-input-start-mark) + (defvar slime-repl-old-input-counter 0 + "Counter used to generate unique `slime-repl-old-input' properties. +This property value must be unique to avoid having adjacent inputs be +joined together.")) + +(defun slime-reset-repl-markers () + (dolist (markname '(slime-output-start + slime-output-end + slime-repl-prompt-start-mark + slime-repl-input-start-mark)) + (set markname (make-marker)) + (set-marker (symbol-value markname) (point)))) + +;;;;; REPL mode setup + +(defvar slime-repl-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map lisp-mode-map) + map)) + +(slime-define-keys slime-prefix-map + ("\C-z" 'slime-switch-to-output-buffer) + ("\M-p" 'slime-repl-set-package)) + +(slime-define-keys slime-mode-map + ("\C-c~" 'slime-sync-package-and-default-directory) + ("\C-c\C-y" 'slime-call-defun) + ("\C-c\C-j" 'slime-eval-last-expression-in-repl)) + +(slime-define-keys slime-connection-list-mode-map + ((kbd "RET") 'slime-goto-connection) + ([return] 'slime-goto-connection)) + +(slime-define-keys slime-repl-mode-map + ("\C-m" 'slime-repl-return) + ([return] 'slime-repl-return) + ("\C-j" 'slime-repl-newline-and-indent) + ("\C-\M-m" 'slime-repl-closing-return) + ([(control return)] 'slime-repl-closing-return) + ("\M-p" 'slime-repl-previous-input) + ((kbd "C-") 'slime-repl-backward-input) + ("\M-n" 'slime-repl-next-input) + ((kbd "C-") 'slime-repl-forward-input) + ("\M-r" 'slime-repl-previous-matching-input) + ("\M-s" 'slime-repl-next-matching-input) + ("\C-c\C-c" 'slime-interrupt) + (" " 'slime-space) + ((string slime-repl-shortcut-dispatch-char) 'slime-handle-repl-shortcut) + ("\C-c\C-o" 'slime-repl-clear-output) + ("\C-c\M-o" 'slime-repl-clear-buffer) + ("\C-c\C-u" 'slime-repl-kill-input) + ("\C-c\C-n" 'slime-repl-next-prompt) + ("\C-c\C-p" 'slime-repl-previous-prompt) + ("\C-c\C-z" 'slime-nop) + ("\C-cI" 'slime-repl-inspect) + ("\C-x\C-e" 'slime-eval-last-expression)) + +(slime-define-keys slime-inspector-mode-map + ((kbd "M-RET") 'slime-inspector-copy-down-to-repl)) + +(slime-define-keys sldb-mode-map + ("\C-y" 'sldb-insert-frame-call-to-repl) + ((kbd "M-RET") 'sldb-copy-down-to-repl)) + +(def-slime-selector-method ?r + "SLIME Read-Eval-Print-Loop." + (slime-output-buffer)) + +(define-minor-mode slime-repl-map-mode + "Minor mode which makes slime-repl-mode-map available. +\\{slime-repl-mode-map}" + nil + nil + slime-repl-mode-map) + +(defun slime-repl-mode () + "Major mode for interacting with a superior Lisp. +\\{slime-repl-mode-map}" + (interactive) + (kill-all-local-variables) + (setq major-mode 'slime-repl-mode) + (slime-editing-mode 1) + (slime-repl-map-mode 1) + (lisp-mode-variables t) + (set (make-local-variable 'lisp-indent-function) + 'common-lisp-indent-function) + (slime-setup-completion) + (set (make-local-variable 'tab-always-indent) 'complete) + (setq font-lock-defaults nil) + (setq mode-name "REPL") + (setq slime-current-thread :repl-thread) + (set (make-local-variable 'scroll-conservatively) 20) + (set (make-local-variable 'scroll-margin) 0) + (when slime-repl-history-file + (slime-repl-safe-load-history) + (add-hook 'kill-buffer-hook + 'slime-repl-safe-save-merged-history + 'append t)) + (add-hook 'kill-emacs-hook 'slime-repl-save-all-histories) + ;; At the REPL, we define beginning-of-defun and end-of-defun to be + ;; the start of the previous prompt or next prompt respectively. + ;; Notice the interplay with SLIME-REPL-BEGINNING-OF-DEFUN. + (set (make-local-variable 'beginning-of-defun-function) + 'slime-repl-mode-beginning-of-defun) + (set (make-local-variable 'end-of-defun-function) + 'slime-repl-mode-end-of-defun) + (run-mode-hooks 'slime-repl-mode-hook)) + +(defun slime-repl-buffer (&optional create connection) + "Get the REPL buffer for the current connection; optionally create." + (funcall (if create #'get-buffer-create #'get-buffer) + (format "*slime-repl %s*" (slime-connection-name connection)))) + +(defun slime-repl () + (interactive) + (slime-switch-to-output-buffer) + (current-buffer)) + +(defun slime-repl-mode-beginning-of-defun (&optional arg) + (if (and arg (< arg 0)) + (slime-repl-mode-end-of-defun (- arg)) + (dotimes (i (or arg 1)) + (slime-repl-previous-prompt)))) + +(defun slime-repl-mode-end-of-defun (&optional arg) + (if (and arg (< arg 0)) + (slime-repl-mode-beginning-of-defun (- arg)) + (dotimes (i (or arg 1)) + (slime-repl-next-prompt)))) + +(defun slime-repl-send-string (string &optional command-string) + (cond (slime-repl-read-mode + (slime-repl-return-string string)) + (t (slime-repl-eval-string string)))) + +(defun slime-repl-eval-string (string) + (slime-rex () + ((if slime-repl-auto-right-margin + `(swank-repl:listener-eval + ,string + :window-width + ,(with-current-buffer (slime-output-buffer) + (window-width))) + `(swank-repl:listener-eval ,string)) + (slime-lisp-package)) + ((:ok result) + (slime-repl-insert-result result)) + ((:abort condition) + (slime-repl-show-abort condition)))) + +(defun slime-repl-insert-result (result) + (with-current-buffer (slime-output-buffer) + (save-excursion + (when result + (slime-dcase result + ((:values &rest strings) + (cond ((null strings) + (slime-repl-emit-result "; No value\n" t)) + (t + (dolist (s strings) + (slime-repl-emit-result s t))))))) + (slime-repl-insert-prompt)) + (slime-repl-show-maximum-output))) + +(defun slime-repl-show-abort (condition) + (with-current-buffer (slime-output-buffer) + (save-excursion + (slime-save-marker slime-output-start + (slime-save-marker slime-output-end + (goto-char slime-output-end) + (insert-before-markers (format "; Evaluation aborted on %s.\n" + condition)) + (slime-repl-insert-prompt)))) + (slime-repl-show-maximum-output))) + +(defvar slime-repl-suppress-prompt nil + "Supresses Slime REPL prompt when bound to T.") + +(defun slime-repl-insert-prompt () + "Insert the prompt (before markers!). +Set point after the prompt. +Return the position of the prompt beginning. + +If `slime-repl-suppress-prompt' is true, does nothing and returns nil." + (goto-char slime-repl-input-start-mark) + (unless slime-repl-suppress-prompt + (slime-save-marker slime-output-start + (slime-save-marker slime-output-end + (unless (bolp) (insert-before-markers "\n")) + (let ((prompt-start (point)) + (prompt (format "%s> " (slime-lisp-package-prompt-string)))) + (slime-propertize-region + '(face slime-repl-prompt-face + read-only t slime-repl-prompt t + rear-nonsticky t front-sticky (read-only) + inhibit-line-move-field-capture t + field output) + (insert-before-markers prompt)) + (set-marker slime-repl-prompt-start-mark prompt-start) + (setq buffer-undo-list nil) + prompt-start))))) + +(defun slime-repl-show-maximum-output () + "Put the end of the buffer at the bottom of the window." + (when (eobp) + (let ((win (if (eq (window-buffer) (current-buffer)) + (selected-window) + (get-buffer-window (current-buffer) t)))) + (when win + (with-selected-window win + (set-window-point win (point-max)) + (recenter -1)))))) + +(defvar slime-repl-current-input-hooks) + +(defun slime-repl-current-input (&optional until-point-p) + "Return the current input as string. +The input is the region from after the last prompt to the end of +buffer." + (or (run-hook-with-args-until-success 'slime-repl-current-input-hooks + until-point-p) + (buffer-substring-no-properties slime-repl-input-start-mark + (if until-point-p + (point) + (point-max))))) + +(defun slime-property-position (text-property &optional object) + "Return the first position of TEXT-PROPERTY, or nil." + (if (get-text-property 0 text-property object) + 0 + (next-single-property-change 0 text-property object))) + +(defun slime-mark-input-start () + (set-marker slime-repl-input-start-mark (point) (current-buffer))) + +(defun slime-mark-output-start () + (set-marker slime-output-start (point)) + (set-marker slime-output-end (point))) + +(defun slime-mark-output-end () + ;; Don't put slime-repl-output-face again; it would remove the + ;; special presentation face, for instance in the SBCL inspector. + (add-text-properties slime-output-start slime-output-end + '(;;face slime-repl-output-face + rear-nonsticky (face)))) + +(defun slime-preserve-zmacs-region () + "In XEmacs, ensure that the zmacs-region stays active after this command." + (when (boundp 'zmacs-region-stays) + (set 'zmacs-region-stays t))) + +(defun slime-repl-in-input-area-p () + (<= slime-repl-input-start-mark (point))) + +(defun slime-repl-at-prompt-start-p () + ;; This will not work on non-current prompts. + (= (point) slime-repl-input-start-mark)) + +(defun slime-repl-beginning-of-defun () + "Move to beginning of defun." + (interactive) + ;; We call BEGINNING-OF-DEFUN if we're at the start of a prompt + ;; already, to trigger SLIME-REPL-MODE-BEGINNING-OF-DEFUN by means + ;; of the locally bound BEGINNING-OF-DEFUN-FUNCTION, in order to + ;; jump to the start of the previous prompt. + (if (and (not (slime-repl-at-prompt-start-p)) + (slime-repl-in-input-area-p)) + (goto-char slime-repl-input-start-mark) + (beginning-of-defun)) + t) + +;; FIXME: this looks very strange +(defun slime-repl-end-of-defun () + "Move to next of defun." + (interactive) + ;; C.f. SLIME-REPL-BEGINNING-OF-DEFUN. + (if (and (not (= (point) (point-max))) + (slime-repl-in-input-area-p)) + (goto-char (point-max)) + (end-of-defun)) + t) + +(defun slime-repl-previous-prompt () + "Move backward to the previous prompt." + (interactive) + (slime-repl-find-prompt t)) + +(defun slime-repl-next-prompt () + "Move forward to the next prompt." + (interactive) + (slime-repl-find-prompt)) + +(defun slime-repl-find-prompt (&optional backward) + (let ((origin (point)) + (prop 'slime-repl-prompt)) + (while (progn + (slime-search-property-change prop backward) + (not (or (slime-end-of-proprange-p prop) (bobp) (eobp))))) + (unless (slime-end-of-proprange-p prop) + (goto-char origin)))) + +(defun slime-search-property-change (prop &optional backward) + (cond (backward + (goto-char (or (previous-single-char-property-change (point) prop) + (point-min)))) + (t + (goto-char (or (next-single-char-property-change (point) prop) + (point-max)))))) + +(defun slime-end-of-proprange-p (property) + (and (get-char-property (max 1 (1- (point))) property) + (not (get-char-property (point) property)))) + +(defvar slime-repl-return-hooks) + +(defun slime-repl-return (&optional end-of-input) + "Evaluate the current input string, or insert a newline. +Send the current input only if a whole expression has been entered, +i.e. the parenthesis are matched. + +With prefix argument send the input even if the parenthesis are not +balanced." + (interactive "P") + (slime-check-connected) + (cond (end-of-input + (slime-repl-send-input)) + (slime-repl-read-mode ; bad style? + (slime-repl-send-input t)) + ((and (get-text-property (point) 'slime-repl-old-input) + (< (point) slime-repl-input-start-mark)) + (slime-repl-grab-old-input end-of-input) + (slime-repl-recenter-if-needed)) + ((run-hook-with-args-until-success 'slime-repl-return-hooks end-of-input)) + ((slime-input-complete-p slime-repl-input-start-mark (point-max)) + (slime-repl-send-input t)) + (t + (slime-repl-newline-and-indent) + (message "[input not complete]")))) + +(defun slime-repl-recenter-if-needed () + "Make sure that (point) is visible." + (unless (pos-visible-in-window-p (point-max)) + (save-excursion + (goto-char (point-max)) + (recenter -1)))) + +(defun slime-repl-send-input (&optional newline) + "Goto to the end of the input and send the current input. +If NEWLINE is true then add a newline at the end of the input." + (unless (slime-repl-in-input-area-p) + (error "No input at point.")) + (goto-char (point-max)) + (let ((end (point))) ; end of input, without the newline + (slime-repl-add-to-input-history + (buffer-substring slime-repl-input-start-mark end)) + (when newline + (insert "\n") + (slime-repl-show-maximum-output)) + (let ((inhibit-modification-hooks t)) + (add-text-properties slime-repl-input-start-mark + (point) + `(slime-repl-old-input + ,(incf slime-repl-old-input-counter)))) + (let ((overlay (make-overlay slime-repl-input-start-mark end))) + ;; These properties are on an overlay so that they won't be taken + ;; by kill/yank. + (overlay-put overlay 'face 'slime-repl-input-face))) + (let ((input (slime-repl-current-input))) + (goto-char (point-max)) + (slime-mark-input-start) + (slime-mark-output-start) + (slime-repl-send-string input))) + +(defun slime-repl-grab-old-input (replace) + "Resend the old REPL input at point. +If replace is non-nil the current input is replaced with the old +input; otherwise the new input is appended. The old input has the +text property `slime-repl-old-input'." + (multiple-value-bind (beg end) (slime-property-bounds 'slime-repl-old-input) + (let ((old-input (buffer-substring beg end)) ;;preserve + ;;properties, they will be removed later + (offset (- (point) beg))) + ;; Append the old input or replace the current input + (cond (replace (goto-char slime-repl-input-start-mark)) + (t (goto-char (point-max)) + (unless (eq (char-before) ?\ ) + (insert " ")))) + (delete-region (point) (point-max)) + (save-excursion + (insert old-input) + (when (equal (char-before) ?\n) + (delete-char -1))) + (forward-char offset)))) + +(defun slime-repl-closing-return () + "Evaluate the current input string after closing all open lists." + (interactive) + (goto-char (point-max)) + (save-restriction + (narrow-to-region slime-repl-input-start-mark (point)) + (while (ignore-errors (save-excursion (backward-up-list 1)) t) + (insert ")"))) + (slime-repl-return)) + +(defun slime-repl-newline-and-indent () + "Insert a newline, then indent the next line. +Restrict the buffer from the prompt for indentation, to avoid being +confused by strange characters (like unmatched quotes) appearing +earlier in the buffer." + (interactive) + (save-restriction + (narrow-to-region slime-repl-prompt-start-mark (point-max)) + (insert "\n") + (lisp-indent-line))) + +(defun slime-repl-delete-current-input () + "Delete all text from the prompt." + (interactive) + (delete-region slime-repl-input-start-mark (point-max))) + +(defun slime-eval-last-expression-in-repl (prefix) + "Evaluates last expression in the Slime REPL. + +Switches REPL to current package of the source buffer for the duration. If +used with a prefix argument (C-u), doesn't switch back afterwards." + (interactive "P") + (let ((expr (slime-last-expression)) + (buffer-name (buffer-name (current-buffer))) + (new-package (slime-current-package)) + (old-package (slime-lisp-package)) + (slime-repl-suppress-prompt t) + (yank-back nil)) + (with-current-buffer (slime-output-buffer) + (unless (eq (current-buffer) (window-buffer)) + (pop-to-buffer (current-buffer) t)) + (goto-char (point-max)) + ;; Kill pending input in the REPL + (when (< (marker-position slime-repl-input-start-mark) (point)) + (kill-region slime-repl-input-start-mark (point)) + (setq yank-back t)) + (unwind-protect + (progn + (insert-before-markers (format "\n;;; from %s\n" buffer-name)) + (when new-package + (slime-repl-set-package new-package)) + (let ((slime-repl-suppress-prompt nil)) + (slime-repl-insert-prompt)) + (insert expr) + (slime-repl-return)) + (unless (or prefix (equal (slime-lisp-package) old-package)) + ;; Switch back. + (slime-repl-set-package old-package) + (let ((slime-repl-suppress-prompt nil)) + (slime-repl-insert-prompt)))) + ;; Put pending input back. + (when yank-back + (yank))))) + +(defun slime-repl-kill-input () + "Kill all text from the prompt to point." + (interactive) + (cond ((< (marker-position slime-repl-input-start-mark) (point)) + (kill-region slime-repl-input-start-mark (point))) + ((= (point) (marker-position slime-repl-input-start-mark)) + (slime-repl-delete-current-input)))) + +(defun slime-repl-replace-input (string) + (slime-repl-delete-current-input) + (insert-and-inherit string)) + +(defun slime-repl-input-line-beginning-position () + (save-excursion + (goto-char slime-repl-input-start-mark) + (let ((inhibit-field-text-motion t)) + (line-beginning-position)))) + +(defun slime-clear-repl-variables () + (interactive) + (slime-eval-async `(swank-repl:clear-repl-variables))) + +(defvar slime-repl-clear-buffer-hook) + +(add-hook 'slime-repl-clear-buffer-hook 'slime-clear-repl-variables) + +(defun slime-repl-clear-buffer () + "Delete the output generated by the Lisp process." + (interactive) + (let ((inhibit-read-only t)) + (delete-region (point-min) slime-repl-prompt-start-mark) + (delete-region slime-output-start slime-output-end) + (when (< (point) slime-repl-input-start-mark) + (goto-char slime-repl-input-start-mark)) + (recenter t)) + (run-hooks 'slime-repl-clear-buffer-hook)) + +(defun slime-repl-clear-output () + "Delete the output inserted since the last input." + (interactive) + (let ((start (save-excursion + (when (>= (point) slime-repl-input-start-mark) + (goto-char slime-repl-input-start-mark)) + (slime-repl-previous-prompt) + (ignore-errors (forward-sexp)) + (forward-line) + (point))) + (end (1- (slime-repl-input-line-beginning-position)))) + (when (< start end) + (let ((inhibit-read-only t)) + (delete-region start end) + (save-excursion + (goto-char start) + (insert ";;; output flushed")))))) + +(defun slime-repl-set-package (package) + "Set the package of the REPL buffer to PACKAGE." + (interactive (list (let* ((p (slime-current-package)) + (p (and p (slime-pretty-package-name p))) + (p (and (not (equal p (slime-lisp-package))) p))) + (slime-read-package-name "Package: " p)))) + (with-current-buffer (slime-output-buffer) + (let ((previouse-point (- (point) slime-repl-input-start-mark)) + (previous-prompt (slime-lisp-package-prompt-string))) + (destructuring-bind (name prompt-string) + (slime-repl-shortcut-eval `(swank:set-package ,package)) + (setf (slime-lisp-package) name) + (setf slime-buffer-package name) + (unless (equal previous-prompt prompt-string) + (setf (slime-lisp-package-prompt-string) prompt-string) + (slime-repl-insert-prompt)) + (when (plusp previouse-point) + (goto-char (+ previouse-point slime-repl-input-start-mark))))))) + + +;;;;; History + +(defcustom slime-repl-wrap-history nil + "*T to wrap history around when the end is reached." + :type 'boolean + :group 'slime-repl) + +(make-variable-buffer-local + (defvar slime-repl-input-history '() + "History list of strings read from the REPL buffer.")) + +(defun slime-repl-add-to-input-history (string) + "Add STRING to the input history. +Empty strings and duplicates are ignored." + (setq string (slime-trim-whitespace string)) + (unless (equal string "") + (setq slime-repl-input-history + (remove string slime-repl-input-history)) + (unless (equal string (car slime-repl-input-history)) + (push string slime-repl-input-history)))) + +;; These two vars contain the state of the last history search. We +;; only use them if `last-command' was 'slime-repl-history-replace, +;; otherwise we reinitialize them. + +(defvar slime-repl-input-history-position -1 + "Newer items have smaller indices.") + +(defvar slime-repl-history-pattern nil + "The regexp most recently used for finding input history.") + +(defun slime-repl-history-replace (direction &optional regexp) + "Replace the current input with the next line in DIRECTION. +DIRECTION is 'forward' or 'backward' (in the history list). +If REGEXP is non-nil, only lines matching REGEXP are considered." + (setq slime-repl-history-pattern regexp) + (let* ((min-pos -1) + (max-pos (length slime-repl-input-history)) + (pos0 (cond ((slime-repl-history-search-in-progress-p) + slime-repl-input-history-position) + (t min-pos))) + (pos (slime-repl-position-in-history pos0 direction (or regexp "") + (slime-repl-current-input))) + (msg nil)) + (cond ((and (< min-pos pos) (< pos max-pos)) + (slime-repl-replace-input (nth pos slime-repl-input-history)) + (setq msg (format "History item: %d" pos))) + ((not slime-repl-wrap-history) + (setq msg (cond ((= pos min-pos) "End of history") + ((= pos max-pos) "Beginning of history")))) + (slime-repl-wrap-history + (setq pos (if (= pos min-pos) max-pos min-pos)) + (setq msg "Wrapped history"))) + (when (or (<= pos min-pos) (<= max-pos pos)) + (when regexp + (setq msg (concat msg "; no matching item")))) + ;;(message "%s [%d %d %s]" msg start-pos pos regexp) + (message "%s%s" msg (cond ((not regexp) "") + (t (format "; current regexp: %s" regexp)))) + (setq slime-repl-input-history-position pos) + (setq this-command 'slime-repl-history-replace))) + +(defun slime-repl-history-search-in-progress-p () + (eq last-command 'slime-repl-history-replace)) + +(defun slime-repl-terminate-history-search () + (setq last-command this-command)) + +(defun slime-repl-position-in-history (start-pos direction regexp + &optional exclude-string) + "Return the position of the history item matching REGEXP. +Return -1 resp. the length of the history if no item matches. +If EXCLUDE-STRING is specified then it's excluded from the search." + ;; Loop through the history list looking for a matching line + (let* ((step (ecase direction + (forward -1) + (backward 1))) + (history slime-repl-input-history) + (len (length history))) + (loop for pos = (+ start-pos step) then (+ pos step) + if (< pos 0) return -1 + if (<= len pos) return len + for history-item = (nth pos history) + if (and (string-match regexp history-item) + (not (equal history-item exclude-string))) + return pos))) + +(defun slime-repl-previous-input () + "Cycle backwards through input history. +If the `last-command' was a history navigation command use the +same search pattern for this command. +Otherwise use the current input as search pattern." + (interactive) + (slime-repl-history-replace 'backward (slime-repl-history-pattern t))) + +(defun slime-repl-next-input () + "Cycle forwards through input history. +See `slime-repl-previous-input'." + (interactive) + (slime-repl-history-replace 'forward (slime-repl-history-pattern t))) + +(defun slime-repl-forward-input () + "Cycle forwards through input history." + (interactive) + (slime-repl-history-replace 'forward (slime-repl-history-pattern))) + +(defun slime-repl-backward-input () + "Cycle backwards through input history." + (interactive) + (slime-repl-history-replace 'backward (slime-repl-history-pattern))) + +(defun slime-repl-previous-matching-input (regexp) + (interactive (list (slime-read-from-minibuffer + "Previous element matching (regexp): "))) + (slime-repl-terminate-history-search) + (slime-repl-history-replace 'backward regexp)) + +(defun slime-repl-next-matching-input (regexp) + (interactive (list (slime-read-from-minibuffer + "Next element matching (regexp): "))) + (slime-repl-terminate-history-search) + (slime-repl-history-replace 'forward regexp)) + +(defun slime-repl-history-pattern (&optional use-current-input) + "Return the regexp for the navigation commands." + (cond ((slime-repl-history-search-in-progress-p) + slime-repl-history-pattern) + (use-current-input + (goto-char (max slime-repl-input-start-mark (point))) + (let ((str (slime-repl-current-input t))) + (cond ((string-match "^[ \t\n]*$" str) nil) + (t (concat "^" (regexp-quote str)))))) + (t nil))) + +(defun slime-repl-delete-from-input-history (string) + "Delete STRING from the repl input history. + +When string is not provided then clear the current repl input and +use it as an input. This is useful to get rid of unwanted repl +history entries while navigating the repl history." + (interactive (list (slime-repl-current-input))) + (let ((merged-history + (slime-repl-merge-histories (slime-repl-read-history nil t) + slime-repl-input-history))) + (setq slime-repl-input-history + (cl-delete string merged-history :test #'string=)) + (slime-repl-save-history)) + (slime-repl-delete-current-input)) + +;;;;; Persistent History + +(defun slime-repl-merge-histories (old-hist new-hist) + "Merge entries from OLD-HIST and NEW-HIST." + ;; Newer items in each list are at the beginning. + (let* ((ht (make-hash-table :test #'equal)) + (test (lambda (entry) + (or (gethash entry ht) + (progn (setf (gethash entry ht) t) + nil))))) + (append (cl-remove-if test new-hist) + (cl-remove-if test old-hist)))) + +(defun slime-repl-load-history (&optional filename) + "Set the current SLIME REPL history. +It can be read either from FILENAME or `slime-repl-history-file' or +from a user defined filename." + (interactive (list (slime-repl-read-history-filename))) + (let ((file (or filename slime-repl-history-file))) + (setq slime-repl-input-history (slime-repl-read-history file t)))) + +(defun slime-repl-read-history (&optional filename noerrer) + "Read and return the history from FILENAME. +The default value for FILENAME is `slime-repl-history-file'. +If NOERROR is true return and the file doesn't exits return nil." + (let ((file (or filename slime-repl-history-file))) + (cond ((not (file-readable-p file)) '()) + (t (with-temp-buffer + (insert-file-contents file) + (read (current-buffer))))))) + +(defun slime-repl-read-history-filename () + (read-file-name "Use SLIME REPL history from file: " + slime-repl-history-file)) + +(defun slime-repl-save-merged-history (&optional filename) + "Read the history file, merge the current REPL history and save it. +This tries to be smart in merging the history from the file and the +current history in that it tries to detect the unique entries using +`slime-repl-merge-histories'." + (interactive (list (slime-repl-read-history-filename))) + (let ((file (or filename slime-repl-history-file))) + (with-temp-message "saving history..." + (let ((hist (slime-repl-merge-histories (slime-repl-read-history file t) + slime-repl-input-history))) + (slime-repl-save-history file hist))))) + +(defun slime-repl-save-history (&optional filename history) + "Simply save the current SLIME REPL history to a file. +When SLIME is setup to always load the old history and one uses only +one instance of slime all the time, there is no need to merge the +files and this function is sufficient. + +When the list is longer than `slime-repl-history-size' it will be +truncated. That part is untested, though!" + (interactive (list (slime-repl-read-history-filename))) + (let ((file (or filename slime-repl-history-file)) + (hist (or history slime-repl-input-history))) + (unless (file-writable-p file) + (error (format "History file not writable: %s" file))) + (let ((hist (cl-subseq hist 0 (min (length hist) slime-repl-history-size)))) + ;;(message "saving %s to %s\n" hist file) + (with-temp-file file + (let ((cs slime-repl-history-file-coding-system) + (print-length nil) (print-level nil)) + (setq buffer-file-coding-system cs) + (insert (format ";; -*- coding: %s -*-\n" cs)) + (insert ";; History for SLIME REPL. Automatically written.\n" + ";; Edit only if you know what you're doing\n") + (prin1 (mapcar #'substring-no-properties hist) (current-buffer))))))) + +(defun slime-repl-save-all-histories () + "Save the history in each repl buffer." + (dolist (b (buffer-list)) + (with-current-buffer b + (when (eq major-mode 'slime-repl-mode) + (slime-repl-safe-save-merged-history))))) + +(defun slime-repl-safe-save-merged-history () + (slime-repl-call-with-handler + #'slime-repl-save-merged-history + "%S while saving the history. Continue? ")) + +(defun slime-repl-safe-load-history () + (slime-repl-call-with-handler + #'slime-repl-load-history + "%S while loading the history. Continue? ")) + +(defun slime-repl-call-with-handler (fun query) + "Call FUN in the context of an error handler. +The handler will use qeuery to ask the use if the error should be ingored." + (condition-case err + (funcall fun) + (error + (if (y-or-n-p (format query (error-message-string err))) + nil + (signal (car err) (cdr err)))))) + + +;;;;; REPL Read Mode + +(defvar slime-repl-read-mode-map + (let ((map (make-sparse-keymap))) + (define-key map "\C-m" 'slime-repl-return) + (define-key map [return] 'slime-repl-return) + (define-key map (kbd "TAB") 'self-insert-command) + (define-key map "\C-c\C-b" 'slime-repl-read-break) + (define-key map "\C-c\C-c" 'slime-repl-read-break) + (define-key map [remap slime-indent-and-complete-symbol] 'ignore) + (define-key map [remap slime-handle-repl-shortcut] 'self-insert-command) + map)) + +(define-minor-mode slime-repl-read-mode + "Mode to read input from Emacs +\\{slime-repl-read-mode-map}" + nil + "[read]") + +(make-variable-buffer-local + (defvar slime-read-string-threads nil)) + +(make-variable-buffer-local + (defvar slime-read-string-tags nil)) + +(defun slime-repl-read-string (thread tag) + (slime-switch-to-output-buffer) + (push thread slime-read-string-threads) + (push tag slime-read-string-tags) + (goto-char (point-max)) + (slime-mark-output-end) + (slime-mark-input-start) + (slime-repl-read-mode 1)) + +(defun slime-repl-return-string (string) + (slime-dispatch-event `(:emacs-return-string + ,(pop slime-read-string-threads) + ,(pop slime-read-string-tags) + ,string)) + (slime-repl-read-mode -1)) + +(defun slime-repl-read-break () + (interactive) + (slime-dispatch-event `(:emacs-interrupt ,(car slime-read-string-threads)))) + +(defun slime-repl-abort-read (thread tag) + (with-current-buffer (slime-output-buffer) + (pop slime-read-string-threads) + (pop slime-read-string-tags) + (slime-repl-read-mode -1) + (message "Read aborted"))) + + +;;;;; REPL handlers + +(cl-defstruct (slime-repl-shortcut (:conc-name slime-repl-shortcut.)) + symbol names handler one-liner) + +(defvar slime-repl-shortcut-table nil + "A list of slime-repl-shortcuts") + +(defvar slime-repl-shortcut-history '() + "History list of shortcut command names.") + +(defvar slime-within-repl-shortcut-handler-p nil + "Bound to T if we're in a REPL shortcut handler invoked from the REPL.") + +(defun slime-handle-repl-shortcut () + (interactive) + (if (> (point) slime-repl-input-start-mark) + (insert (string slime-repl-shortcut-dispatch-char)) + (let ((shortcut (slime-lookup-shortcut + (completing-read "Command: " + (slime-bogus-completion-alist + (slime-list-all-repl-shortcuts)) + nil t nil + 'slime-repl-shortcut-history)))) + (with-struct (slime-repl-shortcut. handler) shortcut + (let ((slime-within-repl-shortcut-handler-p t)) + (call-interactively handler)))))) + +(defun slime-list-all-repl-shortcuts () + (loop for shortcut in slime-repl-shortcut-table + append (slime-repl-shortcut.names shortcut))) + +(defun slime-lookup-shortcut (name) + (cl-find-if (lambda (s) (member name (slime-repl-shortcut.names s))) + slime-repl-shortcut-table)) + +(defmacro defslime-repl-shortcut (elisp-name names &rest options) + "Define a new repl shortcut. ELISP-NAME is a symbol specifying +the name of the interactive function to create, or NIL if no +function should be created. + +NAMES is a list of \(full-name . aliases\). + +OPTIONS is an plist specifying the handler doing the actual work +of the shortcut \(`:handler'\), and a help text \(`:one-liner'\)." + `(progn + ,(when elisp-name + `(defun ,elisp-name () + (interactive) + (call-interactively ,(second (assoc :handler options))))) + (let ((new-shortcut (make-slime-repl-shortcut + :symbol ',elisp-name + :names (list ,@names) + ,@(apply #'append options)))) + (setq slime-repl-shortcut-table + (cl-remove-if (lambda (s) + (member ',(car names) (slime-repl-shortcut.names s))) + slime-repl-shortcut-table)) + (push new-shortcut slime-repl-shortcut-table) + ',elisp-name))) + +(defun slime-repl-shortcut-eval (sexp &optional package) + "This function should be used by REPL shortcut handlers instead +of `slime-eval' to evaluate their final expansion. (This +expansion will be added to the REPL's history.)" + (when slime-within-repl-shortcut-handler-p ; were we invoked via ,foo? + (slime-repl-add-to-input-history (prin1-to-string sexp))) + (slime-eval sexp package)) + +(defun slime-repl-shortcut-eval-async (sexp &optional cont package) + "This function should be used by REPL shortcut handlers instead +of `slime-eval-async' to evaluate their final expansion. (This +expansion will be added to the REPL's history.)" + (when slime-within-repl-shortcut-handler-p ; were we invoked via ,foo? + (slime-repl-add-to-input-history (prin1-to-string sexp))) + (slime-eval-async sexp cont package)) + +(defun slime-list-repl-short-cuts () + (interactive) + (slime-with-popup-buffer ((slime-buffer-name :repl-help)) + (let ((table (cl-sort (cl-copy-list slime-repl-shortcut-table) #'string< + :key (lambda (x) + (car (slime-repl-shortcut.names x)))))) + (save-excursion + (dolist (shortcut table) + (let ((names (slime-repl-shortcut.names shortcut))) + (insert (pop names)) ;; first print the "full" name + (when names + ;; we also have aliases + (insert " (aka ") + (while (cdr names) + (insert (pop names) ", ")) + (insert (car names) ")")) + (when (slime-repl-shortcut.one-liner shortcut) + (insert "\n " (slime-repl-shortcut.one-liner shortcut))) + (insert "\n"))))))) + +(defun slime-save-some-lisp-buffers () + (if slime-repl-only-save-lisp-buffers + (save-some-buffers nil (lambda () + (and (memq major-mode slime-lisp-modes) + (not (null buffer-file-name))))) + (save-some-buffers))) + +(defun slime-kill-all-buffers () + "Kill all the SLIME-related buffers." + (dolist (buf (buffer-list)) + (when (or (string= (buffer-name buf) slime-event-buffer-name) + (string-match "^\\*inferior-lisp*" (buffer-name buf)) + (string-match "^\\*slime-repl .*\\*$" (buffer-name buf)) + (string-match "^\\*sldb .*\\*$" (buffer-name buf)) + (string-match "^\\*SLIME.*\\*$" (buffer-name buf))) + (kill-buffer buf)))) + +(defslime-repl-shortcut slime-repl-shortcut-help ("help") + (:handler 'slime-list-repl-short-cuts) + (:one-liner "Display the help.")) + +(defslime-repl-shortcut nil ("change-directory" "!d" "cd") + (:handler 'slime-set-default-directory) + (:one-liner "Change the current directory.")) + +(defslime-repl-shortcut nil ("pwd") + (:handler (lambda () + (interactive) + (let ((dir (slime-eval `(swank:default-directory)))) + (message "Directory %s" dir)))) + (:one-liner "Show the current directory.")) + +(defslime-repl-shortcut slime-repl-push-directory + ("push-directory" "+d" "pushd") + (:handler (lambda (directory) + (interactive + (list (read-directory-name + "Push directory: " + (slime-eval '(swank:default-directory)) + nil nil ""))) + (push (slime-eval '(swank:default-directory)) + slime-repl-directory-stack) + (slime-set-default-directory directory))) + (:one-liner "Save the current directory and set it to a new one.")) + +(defslime-repl-shortcut slime-repl-pop-directory + ("pop-directory" "-d" "popd") + (:handler (lambda () + (interactive) + (if (null slime-repl-directory-stack) + (message "Directory stack is empty.") + (slime-set-default-directory + (pop slime-repl-directory-stack))))) + (:one-liner "Restore the last saved directory.")) + +(defslime-repl-shortcut nil ("change-package" "!p" "in-package" "in") + (:handler 'slime-repl-set-package) + (:one-liner "Change the current package.")) + +(defslime-repl-shortcut slime-repl-push-package ("push-package" "+p") + (:handler (lambda (package) + (interactive (list (slime-read-package-name "Package: "))) + (push (slime-lisp-package) slime-repl-package-stack) + (slime-repl-set-package package))) + (:one-liner "Save the current package and set it to a new one.")) + +(defslime-repl-shortcut slime-repl-pop-package ("pop-package" "-p") + (:handler (lambda () + (interactive) + (if (null slime-repl-package-stack) + (message "Package stack is empty.") + (slime-repl-set-package + (pop slime-repl-package-stack))))) + (:one-liner "Restore the last saved package.")) + +(defslime-repl-shortcut slime-repl-resend ("resend-form") + (:handler (lambda () + (interactive) + (insert (car slime-repl-input-history)) + (insert "\n") + (slime-repl-send-input))) + (:one-liner "Resend the last form.")) + +(defslime-repl-shortcut slime-repl-disconnect ("disconnect") + (:handler 'slime-disconnect) + (:one-liner "Disconnect the current connection.")) + +(defslime-repl-shortcut slime-repl-disconnect-all ("disconnect-all") + (:handler 'slime-disconnect-all) + (:one-liner "Disconnect all connections.")) + +(defslime-repl-shortcut slime-repl-sayoonara ("sayoonara") + (:handler (lambda () + (interactive) + (when (slime-connected-p) + (slime-quit-lisp)) + (slime-kill-all-buffers))) + (:one-liner "Quit all Lisps and close all SLIME buffers.")) + +(defslime-repl-shortcut slime-repl-quit ("quit") + (:handler (lambda () + (interactive) + ;; `slime-quit-lisp' determines the connection to quit + ;; on behalf of the REPL's `slime-buffer-connection'. + (let ((repl-buffer (slime-output-buffer))) + (slime-quit-lisp) + (kill-buffer repl-buffer)))) + (:one-liner "Quit the current Lisp.")) + +(defslime-repl-shortcut slime-repl-defparameter ("defparameter" "!") + (:handler (lambda (name value) + (interactive (list (slime-read-symbol-name "Name (symbol): " t) + (slime-read-from-minibuffer "Value: " "*"))) + (insert "(cl:defparameter " name " " value + " \"REPL generated global variable.\")") + (slime-repl-send-input t))) + (:one-liner "Define a new global, special, variable.")) + +(defslime-repl-shortcut slime-repl-compile-and-load ("compile-and-load" "cl") + (:handler (lambda (filename) + (interactive (list (expand-file-name + (read-file-name "File: " nil nil nil nil)))) + (slime-save-some-lisp-buffers) + (slime-repl-shortcut-eval-async + `(swank:compile-file-if-needed + ,(slime-to-lisp-filename filename) t) + #'slime-compilation-finished))) + (:one-liner "Compile (if neccessary) and load a lisp file.")) + +(defslime-repl-shortcut nil ("restart-inferior-lisp") + (:handler 'slime-restart-inferior-lisp) + (:one-liner "Restart *inferior-lisp* and reconnect SLIME.")) + +(defun slime-redirect-inferior-output (&optional noerror) + "Redirect output of the inferior-process to the REPL buffer." + (interactive) + (let ((proc (slime-inferior-process))) + (cond (proc + (let ((filter (slime-rcurry #'slime-inferior-output-filter + (slime-current-connection)))) + (set-process-filter proc filter))) + (noerror) + (t (error "No inferior lisp process"))))) + +(defun slime-inferior-output-filter (proc string conn) + (cond ((eq (process-status conn) 'closed) + (message "Connection closed. Removing inferior output filter.") + (message "Lost output: %S" string) + (set-process-filter proc nil)) + (t + (slime-output-filter conn string)))) + +(defun slime-redirect-trace-output () + "Redirect the trace output to a separate Emacs buffer." + (interactive) + (let ((buffer (get-buffer-create (slime-buffer-name :trace)))) + (with-current-buffer buffer + (let ((marker (copy-marker (buffer-size))) + (target (incf slime-last-output-target-id))) + (puthash target marker slime-output-target-to-marker) + (slime-eval `(swank-repl:redirect-trace-output ,target)))) + ;; Note: We would like the entries in + ;; slime-output-target-to-marker to disappear when the buffers are + ;; killed. We cannot just make the hash-table ":weakness 'value" + ;; -- there is no reference from the buffers to the markers in the + ;; buffer, so entries would disappear even though the buffers are + ;; alive. Best solution might be to make buffer-local variables + ;; that keep the markers. --mkoeppe + (pop-to-buffer buffer))) + +(defun slime-call-defun () + "Insert a call to the toplevel form defined around point into the REPL." + (interactive) + (cl-labels ((insert-call + (name &key (function t) + defclass) + (let* ((setf (and function + (consp name) + (= (length name) 2) + (eql (car name) 'setf))) + (symbol (if setf + (cadr name) + name)) + (qualified-symbol-name + (slime-qualify-cl-symbol-name symbol)) + (symbol-name (slime-cl-symbol-name qualified-symbol-name)) + (symbol-package (slime-cl-symbol-package + qualified-symbol-name)) + (call (if (cl-equalp (slime-lisp-package) symbol-package) + symbol-name + qualified-symbol-name))) + (slime-switch-to-output-buffer) + (goto-char slime-repl-input-start-mark) + (insert (if function + "(" + " ")) + (when setf + (insert "setf (")) + (if defclass + (insert "make-instance '")) + (insert call) + (cond (setf + (insert " ") + (save-excursion (insert ") )"))) + (function + (insert " ") + (save-excursion (insert ")")))) + (unless function + (goto-char slime-repl-input-start-mark))))) + (let ((toplevel (slime-parse-toplevel-form))) + (if (symbolp toplevel) + (error "Not in a function definition") + (slime-dcase toplevel + (((:defun :defgeneric :defmacro :define-compiler-macro) symbol) + (insert-call symbol)) + ((:defmethod symbol &rest args) + (declare (ignore args)) + (insert-call symbol)) + (((:defparameter :defvar :defconstant) symbol) + (insert-call symbol :function nil)) + (((:defclass) symbol) + (insert-call symbol :defclass t)) + (t + (error "Not in a function definition"))))))) + +(defun slime-repl-copy-down-to-repl (slimefun &rest args) + (slime-eval-async `(swank-repl:listener-save-value ',slimefun ,@args) + #'(lambda (_ignored) + (with-current-buffer (slime-repl) + (slime-eval-async '(swank-repl:listener-get-value) + #'(lambda (_ignored) + (slime-repl-insert-prompt))))))) + +(defun slime-inspector-copy-down-to-repl (number) + "Evaluate the inspector slot at point via the REPL (to set `*')." + (interactive (list (or (get-text-property (point) 'slime-part-number) + (error "No part at point")))) + (slime-repl-copy-down-to-repl 'swank:inspector-nth-part number)) + +(defun sldb-copy-down-to-repl (frame-id var-id) + "Evaluate the frame var at point via the REPL (to set `*')." + (interactive (list (sldb-frame-number-at-point) (sldb-var-number-at-point))) + (slime-repl-copy-down-to-repl 'swank/backend:frame-var-value frame-id var-id)) + +(defun sldb-insert-frame-call-to-repl () + "Insert a call to a frame at point." + (interactive) + (let ((call (slime-eval `(swank/backend::frame-call + ,(sldb-frame-number-at-point))))) + (slime-switch-to-output-buffer) + (if (>= (point) slime-repl-prompt-start-mark) + (insert call) + (save-excursion + (goto-char (point-max)) + (insert call)))) + (slime-repl)) + +(defun slime-set-default-directory (directory) + "Make DIRECTORY become Lisp's current directory." + (interactive (list (read-directory-name "Directory: " nil nil t))) + (let ((dir (expand-file-name directory))) + (message "default-directory: %s" + (slime-from-lisp-filename + (slime-repl-shortcut-eval `(swank:set-default-directory + ,(slime-to-lisp-filename dir))))) + (with-current-buffer (slime-output-buffer) + (setq default-directory dir)))) + +(defun slime-sync-package-and-default-directory () + "Set Lisp's package and directory to the values in current buffer." + (interactive) + (let* ((package (slime-current-package)) + (exists-p (or (null package) + (slime-eval `(cl:packagep + (swank::guess-package ,package))))) + (directory default-directory)) + (when (and package exists-p) + (slime-repl-set-package package)) + (slime-set-default-directory directory) + ;; Sync *inferior-lisp* dir + (let* ((proc (slime-process)) + (buffer (and proc (process-buffer proc)))) + (when (buffer-live-p buffer) + (with-current-buffer buffer + (setq default-directory directory)))) + (message "package: %s%s directory: %s" + (with-current-buffer (slime-output-buffer) + (slime-lisp-package)) + (if exists-p "" (format " (package %s doesn't exist)" package)) + directory))) + +(defun slime-goto-connection () + "Switch to the REPL buffer for the connection at point." + (interactive) + (let ((slime-dispatching-connection (slime-connection-at-point))) + (switch-to-buffer (slime-output-buffer)))) + +(defun slime-repl-inside-string-or-comment-p () + (save-restriction + (when (and (boundp 'slime-repl-input-start-mark) + slime-repl-input-start-mark + (>= (point) slime-repl-input-start-mark)) + (narrow-to-region slime-repl-input-start-mark (point))) + (slime-inside-string-or-comment-p))) + +(defvar slime-repl-easy-menu + (let ((C '(slime-connected-p))) + `("REPL" + [ "Send Input" slime-repl-return ,C ] + [ "Close and Send Input " slime-repl-closing-return ,C ] + [ "Interrupt Lisp process" slime-interrupt ,C ] + "--" + [ "Previous Input" slime-repl-previous-input t ] + [ "Next Input" slime-repl-next-input t ] + [ "Goto Previous Prompt " slime-repl-previous-prompt t ] + [ "Goto Next Prompt " slime-repl-next-prompt t ] + [ "Clear Last Output" slime-repl-clear-output t ] + [ "Clear Buffer " slime-repl-clear-buffer t ] + [ "Kill Current Input" slime-repl-kill-input t ]))) + +(defun slime-repl-add-easy-menu () + (easy-menu-define menubar-slime-repl slime-repl-mode-map + "REPL" slime-repl-easy-menu) + (easy-menu-define menubar-slime slime-repl-mode-map + "SLIME" slime-easy-menu) + (easy-menu-add slime-repl-easy-menu 'slime-repl-mode-map)) + +(add-hook 'slime-repl-mode-hook 'slime-repl-add-easy-menu) + +(defun slime-hide-inferior-lisp-buffer () + "Display the REPL buffer instead of the *inferior-lisp* buffer." + (let* ((buffer (if (slime-process) + (process-buffer (slime-process)))) + (window (if buffer (get-buffer-window buffer t))) + (repl-buffer (slime-output-buffer t)) + (repl-window (get-buffer-window repl-buffer))) + (when buffer + (bury-buffer buffer)) + (cond (repl-window + (when window + (delete-window window))) + (window + (set-window-buffer window repl-buffer)) + (t + (pop-to-buffer repl-buffer) + (goto-char (point-max)))))) + +(defun slime-repl-choose-coding-system () + (let ((candidates (slime-connection-coding-systems))) + (or (cl-find (symbol-name (car default-process-coding-system)) + candidates + :test (lambda (s1 s2) + (if (fboundp 'coding-system-equal) + (coding-system-equal (intern s1) (intern s2))))) + (car candidates) + (error "Can't find suitable coding-system")))) + +(defun slime-repl-connected-hook-function () + (destructuring-bind (package prompt) + (let ((slime-current-thread t) + (cs (slime-repl-choose-coding-system))) + (slime-eval `(swank-repl:create-repl nil :coding-system ,cs))) + (setf (slime-lisp-package) package) + (setf (slime-lisp-package-prompt-string) prompt)) + (slime-hide-inferior-lisp-buffer) + (slime-init-output-buffer (slime-connection))) + +(defun slime-repl-event-hook-function (event) + (slime-dcase event + ((:write-string output &optional target) + (slime-write-string output target) + t) + ((:read-string thread tag) + (assert thread) + (slime-repl-read-string thread tag) + t) + ((:read-aborted thread tag) + (slime-repl-abort-read thread tag) + t) + ((:open-dedicated-output-stream port coding-system) + (slime-open-stream-to-lisp port coding-system) + t) + ((:new-package package prompt-string) + (setf (slime-lisp-package) package) + (setf (slime-lisp-package-prompt-string) prompt-string) + (let ((buffer (slime-connection-output-buffer))) + (when (buffer-live-p buffer) + (with-current-buffer buffer + (setq slime-buffer-package package)))) + t) + (t nil))) + +(defun slime-change-repl-to-default-connection () + "Change current REPL to the REPL of the default connection. +If the current buffer is not a REPL, don't do anything." + (when (equal major-mode 'slime-repl-mode) + (let ((slime-buffer-connection slime-default-connection)) + (pop-to-buffer-same-window (slime-connection-output-buffer))))) + +(defun slime-repl-find-buffer-package () + (or (slime-search-buffer-package) + (slime-lisp-package))) + +(defun slime-repl-add-hooks () + (add-hook 'slime-event-hooks 'slime-repl-event-hook-function) + (add-hook 'slime-connected-hook 'slime-repl-connected-hook-function) + (add-hook 'slime-cycle-connections-hook + 'slime-change-repl-to-default-connection)) + +(defun slime-repl-remove-hooks () + (remove-hook 'slime-event-hooks 'slime-repl-event-hook-function) + (remove-hook 'slime-connected-hook 'slime-repl-connected-hook-function) + (remove-hook 'slime-cycle-connections-hook + 'slime-change-repl-to-default-connection)) + +(defun slime-repl-sexp-at-point () + "Returns the current sexp at point (or NIL if none is found) +while ignoring the repl prompt text." + (if (<= slime-repl-input-start-mark (point)) + (save-restriction + (narrow-to-region slime-repl-input-start-mark (point-max)) + (slime-sexp-at-point)) + (slime-sexp-at-point))) + +(defun slime-repl-inspect (string) + (interactive + (list (slime-read-from-minibuffer "Inspect value (evaluated): " + (slime-repl-sexp-at-point)))) + (slime-inspect string)) + +(require 'bytecomp) + +;; (mapc (lambda (sym) +;; (cond ((fboundp sym) +;; (unless (byte-code-function-p (symbol-function sym)) +;; (byte-compile sym))) +;; (t (error "%S is not fbound" sym)))) +;; '(slime-repl-event-hook-function +;; slime-write-string +;; slime-repl-write-string +;; slime-repl-emit +;; slime-repl-show-maximum-output)) + +(provide 'slime-repl) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-sbcl-exts.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-sbcl-exts.el new file mode 100644 index 0000000..ab1c524 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-sbcl-exts.el @@ -0,0 +1,34 @@ +(require 'slime) +(require 'cl-lib) + +(define-slime-contrib slime-sbcl-exts + "Misc extensions for SBCL" + (:authors "Tobias C. Rittweiler ") + (:license "GPL") + (:slime-dependencies slime-references) + (:swank-dependencies swank-sbcl-exts)) + +(defun slime-sbcl-bug-at-point () + (save-excursion + (save-match-data + (unless (looking-at "#[0-9]\\{6\\}") + (search-backward-regexp "#\\<" (line-beginning-position) t)) + (when (looking-at "#[0-9]\\{6\\}") + (buffer-substring-no-properties (match-beginning 0) (match-end 0)))))) + +(defun slime-read-sbcl-bug (prompt &optional query) + "Either read a sbcl bug or choose the one at point. +The user is prompted if a prefix argument is in effect, if there is no +symbol at point, or if QUERY is non-nil." + (let ((bug (slime-sbcl-bug-at-point))) + (cond ((or current-prefix-arg query (not bug)) + (slime-read-from-minibuffer prompt bug)) + (t bug)))) + +(defun slime-visit-sbcl-bug (bug) + "Visit the Launchpad site that describes `bug' (#nnnnnn)." + (interactive (list (slime-read-sbcl-bug "Bug number (#nnnnnn): "))) + (browse-url (format "http://bugs.launchpad.net/sbcl/+bug/%s" + (substring bug 1)))) + +(provide 'slime-sbcl-exts) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-scheme.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-scheme.el new file mode 100644 index 0000000..9b7abd6 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-scheme.el @@ -0,0 +1,40 @@ +;;; slime-scheme.el --- Support Scheme programs running under Common Lisp +;; +;; Authors: Matthias Koeppe +;; +;; License: GNU GPL (same license as Emacs) +;; +;;; Installation: +;; +;; Add this to your .emacs: +;; +;; (add-to-list 'load-path "") +;; (add-hook 'slime-load-hook (lambda () (require 'slime-scheme))) +;; +(eval-and-compile + (require 'slime)) + +(defun slime-scheme-mode-hook () + (slime-mode 1)) + +(defun slime-scheme-indentation-update (symbol indent packages) + ;; Does the symbol have an indentation value that we set? + (when (equal (get symbol 'scheme-indent-function) + (get symbol 'slime-scheme-indent)) + (put symbol 'slime-scheme-indent indent) + (put symbol 'scheme-indent-function indent))) + + +;;; Initialization + +(defun slime-scheme-init () + (add-hook 'scheme-mode-hook 'slime-scheme-mode-hook) + (add-hook 'slime-indentation-update-hooks 'slime-scheme-indentation-update) + (add-to-list 'slime-lisp-modes 'scheme-mode)) + +(defun slime-scheme-unload () + (remove-hook 'scheme-mode-hook 'slime-scheme-mode-hook) + (remove-hook 'slime-indentation-update-hooks 'slime-scheme-indentation-update) + (setq slime-lisp-modes (remove 'scheme-mode slime-lisp-modes))) + +(provide 'slime-scheme) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-scratch.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-scratch.el new file mode 100644 index 0000000..113fae0 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-scratch.el @@ -0,0 +1,48 @@ +;;; slime-scratch.el + +(require 'slime) +(require 'cl-lib) + +(define-slime-contrib slime-scratch + "Imitate Emacs' *scratch* buffer" + (:authors "Helmut Eller ") + (:license "GPL") + (:on-load + (def-slime-selector-method ?s "*slime-scratch* buffer." + (slime-scratch-buffer)))) + + +;;; Code + +(defvar slime-scratch-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map lisp-mode-map) + map)) + +(defun slime-scratch () + (interactive) + (slime-switch-to-scratch-buffer)) + +(defun slime-switch-to-scratch-buffer () + (set-buffer (slime-scratch-buffer)) + (unless (eq (current-buffer) (window-buffer)) + (pop-to-buffer (current-buffer) t))) + +(defvar slime-scratch-file nil) + +(defun slime-scratch-buffer () + "Return the scratch buffer, create it if necessary." + (or (get-buffer (slime-buffer-name :scratch)) + (with-current-buffer (if slime-scratch-file + (find-file slime-scratch-file) + (get-buffer-create (slime-buffer-name :scratch))) + (rename-buffer (slime-buffer-name :scratch)) + (lisp-mode) + (use-local-map slime-scratch-mode-map) + (slime-mode t) + (current-buffer)))) + +(slime-define-keys slime-scratch-mode-map + ("\C-j" 'slime-eval-print-last-expression)) + +(provide 'slime-scratch) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-snapshot.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-snapshot.el new file mode 100644 index 0000000..1643ecc --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-snapshot.el @@ -0,0 +1,34 @@ +(eval-and-compile + (require 'slime)) + +(define-slime-contrib slime-snapshot + "Save&restore memory images without disconnecting" + (:authors "Helmut Eller ") + (:license "GPL v3") + (:swank-dependencies swank-snapshot)) + +(defun slime-snapshot (filename &optional background) + "Save a memory image to the file FILENAME." + (interactive (list (read-file-name "Image file: ") + current-prefix-arg)) + (let ((file (expand-file-name filename))) + (when (and (file-exists-p file) + (not (yes-or-no-p (format "File exists %s. Overwrite it? " + filename)))) + (signal 'quit nil)) + (slime-eval-with-transcript + `(,(if background + 'swank-snapshot:background-save-snapshot + 'swank-snapshot:save-snapshot) + ,file)))) + +(defun slime-restore (filename) + "Restore a memory image stored in file FILENAME." + (interactive (list (read-file-name "Image file: "))) + ;; bypass event dispatcher because we don't expect a reply. FIXME. + (slime-net-send `(:emacs-rex (swank-snapshot:restore-snapshot + ,(expand-file-name filename)) + nil t nil) + (slime-connection))) + +(provide 'slime-snapshot) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-sprof.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-sprof.el new file mode 100644 index 0000000..8233e7b --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-sprof.el @@ -0,0 +1,224 @@ +(require 'slime) +(require 'cl-lib) +(eval-when-compile (require 'cl)) ; lexical-let* + +(define-slime-contrib slime-sprof + "Integration with SBCL's sb-sprof." + (:authors "Juho Snellman" + "Stas Boukarev") + (:license "MIT") + (:swank-dependencies swank-sprof) + (:on-load + (let ((C '(and (slime-connected-p) + (equal (slime-lisp-implementation-type) "SBCL")))) + (setf (cdr (last (assoc "Profiling" slime-easy-menu))) + `("--" + [ "Start sb-sprof" slime-sprof-start ,C ] + [ "Stop sb-sprof" slime-sprof-stop ,C ] + [ "Report sb-sprof" slime-sprof-report ,C ]))))) + +(defvar slime-sprof-exclude-swank nil + "*Display swank functions in the report.") + +(define-derived-mode slime-sprof-browser-mode fundamental-mode + "slprof" + "Mode for browsing profiler data\ +\\\ +\\{slime-sprof-browser-mode-map}" + :syntax-table lisp-mode-syntax-table + (setq buffer-read-only t)) + +(set-keymap-parent slime-sprof-browser-mode-map slime-parent-map) + +(slime-define-keys slime-sprof-browser-mode-map + ("h" 'describe-mode) + ("d" 'slime-sprof-browser-disassemble-function) + ("g" 'slime-sprof-browser-go-to) + ("v" 'slime-sprof-browser-view-source) + ("s" 'slime-sprof-toggle-swank-exclusion) + ((kbd "RET") 'slime-sprof-browser-toggle)) + +;; Start / stop profiling + +(cl-defun slime-sprof-start (&optional (mode :cpu)) + (interactive) + (slime-eval `(swank:swank-sprof-start :mode ,mode))) + +(defun slime-sprof-start-alloc () + (interactive) + (slime-sprof-start :alloc)) + +(defun slime-sprof-start-time () + (interactive) + (slime-sprof-start :time)) + +(defun slime-sprof-stop () + (interactive) + (slime-eval `(swank:swank-sprof-stop))) + +;; Reporting + +(defun slime-sprof-format (graph) + (with-current-buffer (slime-buffer-name :sprof) + (let ((inhibit-read-only t)) + (erase-buffer) + (insert (format "%4s %-54s %6s %6s %6s\n" + "Rank" + "Name" + "Self%" + "Cumul%" + "Total%")) + (dolist (data graph) + (slime-sprof-browser-insert-line data 54)))) + (forward-line 2)) + +(cl-defun slime-sprof-update (&optional (exclude-swank slime-sprof-exclude-swank)) + (slime-eval-async `(swank:swank-sprof-get-call-graph + :exclude-swank ,exclude-swank) + 'slime-sprof-format)) + +(defalias 'slime-sprof-browser 'slime-sprof-report) + +(defun slime-sprof-report () + (interactive) + (slime-with-popup-buffer ((slime-buffer-name :sprof) + :connection t + :select t + :mode 'slime-sprof-browser-mode) + (slime-sprof-update))) + +(defun slime-sprof-toggle-swank-exclusion () + (interactive) + (setq slime-sprof-exclude-swank + (not slime-sprof-exclude-swank)) + (slime-sprof-update)) + +(defun slime-sprof-browser-insert-line (data name-length) + (cl-destructuring-bind (index name self cumul total) + data + (if index + (insert (format "%-4d " index)) + (insert " ")) + (slime-insert-propertized + (slime-sprof-browser-name-properties) + (format (format "%%-%ds " name-length) + (slime-sprof-abbreviate-name name name-length))) + (insert (format "%6.2f " self)) + (when cumul + (insert (format "%6.2f " cumul)) + (when total + (insert (format "%6.2f" total)))) + (when index + (slime-sprof-browser-add-line-text-properties + `(profile-index ,index expanded nil))) + (insert "\n"))) + +(defun slime-sprof-abbreviate-name (name max-length) + (cl-subseq name 0 (min (length name) max-length))) + +;; Expanding / collapsing + +(defun slime-sprof-browser-toggle () + (interactive) + (let ((index (get-text-property (point) 'profile-index))) + (when index + (save-excursion + (if (slime-sprof-browser-line-expanded-p) + (slime-sprof-browser-collapse) + (slime-sprof-browser-expand)))))) + +(defun slime-sprof-browser-collapse () + (let ((inhibit-read-only t)) + (slime-sprof-browser-add-line-text-properties '(expanded nil)) + (forward-line) + (cl-loop until (or (eobp) + (get-text-property (point) 'profile-index)) + do + (delete-region (point-at-bol) (point-at-eol)) + (unless (eobp) + (delete-char 1))))) + +(defun slime-sprof-browser-expand () + (lexical-let* ((buffer (current-buffer)) + (point (point)) + (index (get-text-property point 'profile-index))) + (slime-eval-async `(swank:swank-sprof-expand-node ,index) + (lambda (data) + (with-current-buffer buffer + (save-excursion + (destructuring-bind (&key callers calls) + data + (slime-sprof-browser-add-expansion callers + "Callers" + 0) + (slime-sprof-browser-add-expansion calls + "Calls" + 0)))))))) + +(defun slime-sprof-browser-add-expansion (data type nesting) + (when data + (let ((inhibit-read-only t)) + (slime-sprof-browser-add-line-text-properties '(expanded t)) + (end-of-line) + (insert (format "\n %s" type)) + (dolist (node data) + (cl-destructuring-bind (index name cumul) node + (insert (format (format "\n%%%ds" (+ 7 (* 2 nesting))) "")) + (slime-insert-propertized + (slime-sprof-browser-name-properties) + (let ((len (- 59 (* 2 nesting)))) + (format (format "%%-%ds " len) + (slime-sprof-abbreviate-name name len)))) + (slime-sprof-browser-add-line-text-properties + `(profile-sub-index ,index)) + (insert (format "%6.2f" cumul))))))) + +(defun slime-sprof-browser-line-expanded-p () + (get-text-property (point) 'expanded)) + +(defun slime-sprof-browser-add-line-text-properties (properties) + (add-text-properties (point-at-bol) + (point-at-eol) + properties)) + +(defun slime-sprof-browser-name-properties () + '(face sldb-restart-number-face)) + +;; "Go to function" + +(defun slime-sprof-browser-go-to () + (interactive) + (let ((sub-index (get-text-property (point) 'profile-sub-index))) + (when sub-index + (let ((pos (text-property-any + (point-min) (point-max) 'profile-index sub-index))) + (when pos (goto-char pos)))))) + +;; Disassembly + +(defun slime-sprof-browser-disassemble-function () + (interactive) + (let ((index (or (get-text-property (point) 'profile-index) + (get-text-property (point) 'profile-sub-index)))) + (when index + (slime-eval-describe `(swank:swank-sprof-disassemble + ,index))))) + +;; View source + +(defun slime-sprof-browser-view-source () + (interactive) + (let ((index (or (get-text-property (point) 'profile-index) + (get-text-property (point) 'profile-sub-index)))) + (when index + (slime-eval-async + `(swank:swank-sprof-source-location ,index) + (lambda (source-location) + (slime-dcase source-location + ((:error message) + (message "%s" message) + (ding)) + (t + (slime-show-source-location source-location)))))))) + +(provide 'slime-sprof) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-trace-dialog.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-trace-dialog.el new file mode 100644 index 0000000..fd25c7b --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-trace-dialog.el @@ -0,0 +1,837 @@ +;;; -*- coding: utf-8; lexical-binding: t -*- +;;; +;;; slime-trace-dialog.el -- a navigable dialog of inspectable trace entries +;;; +;;; TODO: implement better wrap interface for sbcl method, labels and such +;;; TODO: backtrace printing is very slow +;;; +(require 'slime) +(require 'slime-parse) +(require 'slime-repl) +(require 'cl-lib) + +(define-slime-contrib slime-trace-dialog + "Provide an interfactive trace dialog buffer for managing and +inspecting details of traced functions. Invoke this dialog with C-c T." + (:authors "João Távora ") + (:license "GPL") + (:swank-dependencies swank-trace-dialog) + (:on-load (add-hook 'slime-mode-hook 'slime-trace-dialog-enable) + (add-hook 'slime-repl-mode-hook 'slime-trace-dialog-enable)) + (:on-unload (remove-hook 'slime-mode-hook 'slime-trace-dialog-enable) + (remove-hook 'slime-repl-mode-hook 'slime-trace-dialog-enable))) + + +;;;; Variables +;;; +(defvar slime-trace-dialog-flash t + "Non-nil means flash the updated region of the SLIME Trace Dialog. ") + +(defvar slime-trace-dialog--specs-overlay nil) + +(defvar slime-trace-dialog--progress-overlay nil) + +(defvar slime-trace-dialog--tree-overlay nil) + +(defvar slime-trace-dialog--collapse-chars (cons "-" "+")) + + +;;;; Local trace entry model +(defvar slime-trace-dialog--traces nil) + +(cl-defstruct (slime-trace-dialog--trace + (:constructor slime-trace-dialog--make-trace)) + id + parent + spec + args + retlist + depth + beg + end + collapse-button-marker + summary-beg + children-end + collapsed-p) + +(defun slime-trace-dialog--find-trace (id) + (gethash id slime-trace-dialog--traces)) + + +;;;; Modes and mode maps +;;; +(defvar slime-trace-dialog-mode-map + (let ((map (make-sparse-keymap)) + (remaps '((slime-inspector-operate-on-point . nil) + (slime-inspector-operate-on-click . nil) + (slime-inspector-reinspect + . slime-trace-dialog-fetch-status) + (slime-inspector-next-inspectable-object + . slime-trace-dialog-next-button) + (slime-inspector-previous-inspectable-object + . slime-trace-dialog-prev-button)))) + (set-keymap-parent map slime-inspector-mode-map) + (cl-loop for (old . new) in remaps + do (substitute-key-definition old new map)) + (set-keymap-parent map slime-parent-map) + (define-key map (kbd "G") 'slime-trace-dialog-fetch-traces) + (define-key map (kbd "C-k") 'slime-trace-dialog-clear-fetched-traces) + (define-key map (kbd "g") 'slime-trace-dialog-fetch-status) + (define-key map (kbd "M-RET") 'slime-trace-dialog-copy-down-to-repl) + (define-key map (kbd "q") 'quit-window) + map)) + +(define-derived-mode slime-trace-dialog-mode fundamental-mode + "SLIME Trace Dialog" "Mode for controlling SLIME's Trace Dialog" + (set-syntax-table lisp-mode-syntax-table) + (read-only-mode 1) + (add-to-list (make-local-variable 'slime-trace-dialog-after-toggle-hook) + 'slime-trace-dialog-fetch-status)) + +(define-derived-mode slime-trace-dialog--detail-mode slime-inspector-mode + "SLIME Trace Detail" + "Mode for viewing a particular trace from SLIME's Trace Dialog") + +(setq slime-trace-dialog--detail-mode-map + (let ((map (make-sparse-keymap)) + (remaps '((slime-inspector-next-inspectable-object + . slime-trace-dialog-next-button) + (slime-inspector-previous-inspectable-object + . slime-trace-dialog-prev-button)))) + (set-keymap-parent map slime-trace-dialog-mode-map) + (cl-loop for (old . new) in remaps + do (substitute-key-definition old new map)) + map)) + +(defvar slime-trace-dialog-minor-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "C-c T") 'slime-trace-dialog) + (define-key map (kbd "C-c M-t") 'slime-trace-dialog-toggle-trace) + map)) + +(define-minor-mode slime-trace-dialog-minor-mode + "Add keybindings for accessing SLIME's Trace Dialog.") + +(defun slime-trace-dialog-enable () + (slime-trace-dialog-minor-mode 1)) + +(easy-menu-define slime-trace-dialog--menubar (list slime-trace-dialog-minor-mode-map + slime-trace-dialog-mode-map) + "A menu for accessing some features of SLIME's Trace Dialog" + (let* ((in-dialog '(eq major-mode 'slime-trace-dialog-mode)) + (dialog-live `(and ,in-dialog + (memq slime-buffer-connection slime-net-processes))) + (connected '(slime-connected-p))) + `("Trace" + ["Toggle trace" slime-trace-dialog-toggle-trace ,connected] + ["Trace complex spec" slime-trace-dialog-toggle-complex-trace ,connected] + ["Open Trace dialog" slime-trace-dialog (and ,connected (not ,in-dialog))] + "--" + [ "Refresh traces and progress" slime-trace-dialog-fetch-status ,dialog-live] + [ "Fetch next batch" slime-trace-dialog-fetch-traces ,dialog-live] + [ "Clear all fetched traces" slime-trace-dialog-clear-fetched-traces ,dialog-live] + [ "Toggle details" slime-trace-dialog-hide-details-mode ,in-dialog] + [ "Toggle autofollow" slime-trace-dialog-autofollow-mode ,in-dialog]))) + +(define-minor-mode slime-trace-dialog-hide-details-mode + "Hide details in `slime-trace-dialog-mode'" + nil " Brief" + :group 'slime-trace-dialog + (unless (derived-mode-p 'slime-trace-dialog-mode) + (error "Not a SLIME Trace Dialog buffer")) + (slime-trace-dialog--set-hide-details-mode)) + +(define-minor-mode slime-trace-dialog-autofollow-mode + "Automatically open buffers with trace details from `slime-trace-dialog-mode'" + nil " Autofollow" + :group 'slime-trace-dialog + (unless (derived-mode-p 'slime-trace-dialog-mode) + (error "Not a SLIME Trace Dialog buffer"))) + + +;;;; Helper functions +;;; +(defun slime-trace-dialog--call-refreshing (buffer + overlay + dont-erase + recover-point-p + fn) + (with-current-buffer buffer + (let ((inhibit-point-motion-hooks t) + (inhibit-read-only t) + (saved (point))) + (save-restriction + (when overlay + (narrow-to-region (overlay-start overlay) + (overlay-end overlay))) + (unwind-protect + (if dont-erase + (goto-char (point-max)) + (delete-region (point-min) (point-max))) + (funcall fn) + (when recover-point-p + (goto-char saved))) + (when slime-trace-dialog-flash + (slime-flash-region (point-min) (point-max))))) + buffer)) + +(cl-defmacro slime-trace-dialog--refresh ((&key + overlay + dont-erase + recover-point-p + buffer) + &rest body) + (declare (indent 1) + (debug (sexp &rest form))) + `(slime-trace-dialog--call-refreshing ,(or buffer + `(current-buffer)) + ,overlay + ,dont-erase + ,recover-point-p + #'(lambda () ,@body))) + +(defmacro slime-trace-dialog--insert-and-overlay (string overlay) + `(save-restriction + (let ((inhibit-read-only t)) + (narrow-to-region (point) (point)) + (insert ,string "\n") + (set (make-local-variable ',overlay) + (let ((overlay (make-overlay (point-min) + (point-max) + (current-buffer) + nil + t))) + (move-overlay overlay (overlay-start overlay) + (1- (overlay-end overlay))) + ;; (overlay-put overlay 'face '(:background "darkslategrey")) + overlay))))) + +(defun slime-trace-dialog--buffer-name () + (format "*traces for %s*" + (slime-connection-name slime-default-connection))) + +(defun slime-trace-dialog--live-dialog (&optional buffer-or-name) + (let ((buffer-or-name (or buffer-or-name + (slime-trace-dialog--buffer-name)))) + (and (buffer-live-p (get-buffer buffer-or-name)) + (with-current-buffer buffer-or-name + (memq slime-buffer-connection slime-net-processes)) + buffer-or-name))) + +(defun slime-trace-dialog--ensure-buffer () + (let ((name (slime-trace-dialog--buffer-name))) + (or (slime-trace-dialog--live-dialog name) + (with-current-buffer (get-buffer-create name) + (let ((inhibit-read-only t)) + (erase-buffer)) + (slime-trace-dialog-mode) + (save-excursion + (buffer-disable-undo) + (slime-trace-dialog--insert-and-overlay + "[waiting for the traced specs to be available]" + slime-trace-dialog--specs-overlay) + (slime-trace-dialog--insert-and-overlay + "[waiting for some info on trace download progress ]" + slime-trace-dialog--progress-overlay) + (slime-trace-dialog--insert-and-overlay + "[waiting for the actual traces to be available]" + slime-trace-dialog--tree-overlay) + (current-buffer)) + (setq slime-buffer-connection slime-default-connection) + (current-buffer))))) + +(defun slime-trace-dialog--make-autofollow-fn (id) + (let ((requested nil)) + #'(lambda (_before after) + (let ((inhibit-point-motion-hooks t) + (id-after (get-text-property after 'slime-trace-dialog--id))) + (when (and (= after (point)) + slime-trace-dialog-autofollow-mode + id-after + (= id-after id) + (not requested)) + (setq requested t) + (slime-eval-async `(swank-trace-dialog:report-trace-detail + ,id-after) + #'(lambda (detail) + (setq requested nil) + (when detail + (let ((inhibit-point-motion-hooks t)) + (slime-trace-dialog--open-detail detail + 'no-pop)))))))))) + +(defun slime-trace-dialog--set-collapsed (collapsed-p trace button) + (save-excursion + (setf (slime-trace-dialog--trace-collapsed-p trace) collapsed-p) + (slime-trace-dialog--go-replace-char-at + button + (if collapsed-p + (cdr slime-trace-dialog--collapse-chars) + (car slime-trace-dialog--collapse-chars))) + (slime-trace-dialog--hide-unhide + (slime-trace-dialog--trace-summary-beg trace) + (slime-trace-dialog--trace-end trace) + (if collapsed-p 1 -1)) + (slime-trace-dialog--hide-unhide + (slime-trace-dialog--trace-end trace) + (slime-trace-dialog--trace-children-end trace) + (if collapsed-p 1 -1)))) + +(defun slime-trace-dialog--hide-unhide (start-pos end-pos delta) + (cl-loop with inhibit-read-only = t + for pos = start-pos then next + for next = (next-single-property-change + pos + 'slime-trace-dialog--hidden-level + nil + end-pos) + for hidden-level = (+ (or (get-text-property + pos + 'slime-trace-dialog--hidden-level) + 0) + delta) + do (add-text-properties pos next + (list 'slime-trace-dialog--hidden-level + hidden-level + 'invisible + (cl-plusp hidden-level))) + while (< next end-pos))) + +(defun slime-trace-dialog--set-hide-details-mode () + (cl-loop for trace being the hash-values of slime-trace-dialog--traces + do (slime-trace-dialog--hide-unhide + (slime-trace-dialog--trace-summary-beg trace) + (slime-trace-dialog--trace-end trace) + (if slime-trace-dialog-hide-details-mode 1 -1)))) + +(defun slime-trace-dialog--format-part (part-id part-text trace-id type) + (slime-trace-dialog--button + (format "%s" part-text) + #'(lambda (_button) + (slime-eval-async + `(swank-trace-dialog:inspect-trace-part ,trace-id ,part-id ,type) + #'slime-open-inspector)) + 'mouse-face 'highlight + 'slime-trace-dialog--part-id part-id + 'slime-trace-dialog--type type + 'face 'slime-inspector-value-face)) + +(defun slime-trace-dialog--format-trace-entry (id external) + (slime-trace-dialog--button + (format "%s" external) + #'(lambda (_button) + (slime-eval-async + `(swank::inspect-object (swank-trace-dialog::find-trace ,id)) + #'slime-open-inspector)) + 'face 'slime-inspector-value-face)) + +(defun slime-trace-dialog--format (fmt-string &rest args) + (let* ((string (apply #'format fmt-string args)) + (indent (make-string (max 2 + (- 50 (length string))) ? ))) + (format "%s%s" string indent))) + +(defun slime-trace-dialog--button (title lambda &rest props) + (let ((string (format "%s" title))) + (apply #'make-text-button string nil + 'action #'(lambda (button) + (funcall lambda button)) + 'mouse-face 'highlight + 'face 'slime-inspector-action-face + props) + string)) + +(defun slime-trace-dialog--call-maintaining-properties (pos fn) + (save-excursion + (goto-char pos) + (let* ((saved-props (text-properties-at pos)) + (saved-point (point)) + (inhibit-read-only t) + (inhibit-point-motion-hooks t)) + (funcall fn) + (add-text-properties saved-point (point) saved-props) + (if (markerp pos) (set-marker pos saved-point))))) + +(cl-defmacro slime-trace-dialog--maintaining-properties (pos + &body body) + (declare (indent 1)) + `(slime-trace-dialog--call-maintaining-properties ,pos #'(lambda () ,@body))) + +(defun slime-trace-dialog--go-replace-char-at (pos char) + (slime-trace-dialog--maintaining-properties pos + (delete-char 1) + (insert char))) + + +;;;; Handlers for the *trace-dialog* and *trace-detail* buffers +;;; +(defun slime-trace-dialog--open-specs (traced-specs) + (cl-labels ((make-report-spec-fn + (&optional form) + #'(lambda (_button) + (slime-eval-async + `(cl:progn + ,form + (swank-trace-dialog:report-specs)) + #'(lambda (results) + (slime-trace-dialog--open-specs results)))))) + (slime-trace-dialog--refresh + (:overlay slime-trace-dialog--specs-overlay + :recover-point-p t) + (insert + (slime-trace-dialog--format "Traced specs (%s)" (length traced-specs)) + (slime-trace-dialog--button "[refresh]" + (make-report-spec-fn)) + "\n" (make-string 50 ? ) + (slime-trace-dialog--button + "[untrace all]" + (make-report-spec-fn `(swank-trace-dialog:dialog-untrace-all))) + "\n\n") + (cl-loop for spec in traced-specs + do (insert + " " + (slime-trace-dialog--button + "[untrace]" + (make-report-spec-fn + `(swank-trace-dialog:dialog-untrace ',spec))) + (format " %s" spec) + "\n"))))) + +(defvar slime-trace-dialog--fetch-key nil) + +(defvar slime-trace-dialog--stop-fetching nil) + +(defun slime-trace-dialog--update-progress (total &optional show-stop-p remaining-p) + ;; `remaining-p' indicates `total' is the number of remaining traces. + (slime-trace-dialog--refresh + (:overlay slime-trace-dialog--progress-overlay + :recover-point-p t) + (let* ((done (hash-table-count slime-trace-dialog--traces)) + (total (if remaining-p (+ done total) total))) + (insert + (slime-trace-dialog--format "Trace collection status (%d/%s)" + done + (or total "0")) + (slime-trace-dialog--button "[refresh]" + #'(lambda (_button) + (slime-trace-dialog-fetch-progress)))) + + (when (and total (cl-plusp (- total done))) + (insert "\n" (make-string 50 ? ) + (slime-trace-dialog--button + "[fetch next batch]" + #'(lambda (_button) + (slime-trace-dialog-fetch-traces nil))) + "\n" (make-string 50 ? ) + (slime-trace-dialog--button + "[fetch all]" + #'(lambda (_button) + (slime-trace-dialog-fetch-traces t))))) + (when total + (insert "\n" (make-string 50 ? ) + (slime-trace-dialog--button + "[clear]" + #'(lambda (_button) + (slime-trace-dialog-clear-fetched-traces))))) + (when show-stop-p + (insert "\n" (make-string 50 ? ) + (slime-trace-dialog--button + "[stop]" + #'(lambda (_button) + (setq slime-trace-dialog--stop-fetching t))))) + (insert "\n\n")))) + +(defun slime-trace-dialog--open-detail (trace-tuple &optional no-pop) + (slime-with-popup-buffer ("*trace-detail*" :select (not no-pop) + :mode 'slime-trace-dialog--detail-mode) + (cl-destructuring-bind (id _parent-id _spec args retlist backtrace external) + trace-tuple + (let ((headline (slime-trace-dialog--format-trace-entry id external))) + (setq headline (format "%s\n%s\n" + headline + (make-string (length headline) ?-))) + (insert headline)) + (cl-loop for (type objects label) + in `((:arg ,args "Called with args:") + (:retval ,retlist "Returned values:")) + do (insert (format "\n%s\n" label)) + (insert (cl-loop for object in objects + for i from 0 + concat (format " %s: %s\n" i + (slime-trace-dialog--format-part + (cl-first object) + (cl-second object) + id + type))))) + (when backtrace + (insert "\nBacktrace:\n" + (cl-loop for (i spec) in backtrace + concat (format " %s: %s\n" i spec))))))) + + +;;;; Rendering traces +;;; +(defun slime-trace-dialog--draw-tree-lines (start offset direction) + (save-excursion + (let ((inhibit-point-motion-hooks t)) + (goto-char start) + (cl-loop with replace-set = (if (eq direction 'down) + '(? ) + '(? ?`)) + for line-beginning = (line-beginning-position + (if (eq direction 'down) + 2 0)) + for pos = (+ line-beginning offset) + while (and (< (point-min) line-beginning) + (< line-beginning (point-max)) + (memq (char-after pos) replace-set)) + do + (slime-trace-dialog--go-replace-char-at pos "|") + (goto-char pos))))) + +(defun slime-trace-dialog--make-indent (depth suffix) + (concat (make-string (* 3 (max 0 (1- depth))) ? ) + (if (cl-plusp depth) suffix))) + +(defun slime-trace-dialog--make-collapse-button (trace) + (slime-trace-dialog--button (if (slime-trace-dialog--trace-collapsed-p trace) + (cdr slime-trace-dialog--collapse-chars) + (car slime-trace-dialog--collapse-chars)) + #'(lambda (button) + (slime-trace-dialog--set-collapsed + (not (slime-trace-dialog--trace-collapsed-p + trace)) + trace + button)))) + + +(defun slime-trace-dialog--insert-trace (trace) + (let* ((id (slime-trace-dialog--trace-id trace)) + (parent (slime-trace-dialog--trace-parent trace)) + (has-children-p (slime-trace-dialog--trace-children-end trace)) + (indent-spec (slime-trace-dialog--make-indent + (slime-trace-dialog--trace-depth trace) + "`--")) + (indent-summary (slime-trace-dialog--make-indent + (slime-trace-dialog--trace-depth trace) + " ")) + (autofollow-fn (slime-trace-dialog--make-autofollow-fn id)) + (id-string (slime-trace-dialog--button + (format "%4s" id) + #'(lambda (_button) + (slime-eval-async + `(swank-trace-dialog:report-trace-detail + ,id) + #'slime-trace-dialog--open-detail)))) + (spec (slime-trace-dialog--trace-spec trace)) + (summary (cl-loop for (type objects marker) in + `((:arg ,(slime-trace-dialog--trace-args trace) + " > ") + (:retval ,(slime-trace-dialog--trace-retlist trace) + " < ")) + concat (cl-loop for object in objects + concat " " + concat indent-summary + concat marker + concat (slime-trace-dialog--format-part + (cl-first object) + (cl-second object) + id + type) + concat "\n")))) + (puthash id trace slime-trace-dialog--traces) + ;; insert and propertize the text + ;; + (setf (slime-trace-dialog--trace-beg trace) (point-marker)) + (insert id-string " ") + (insert indent-spec) + (if has-children-p + (insert (slime-trace-dialog--make-collapse-button trace)) + (setf (slime-trace-dialog--trace-collapse-button-marker trace) + (point-marker)) + (insert "-")) + (insert (format " %s\n" spec)) + (setf (slime-trace-dialog--trace-summary-beg trace) (point-marker)) + (insert summary) + (setf (slime-trace-dialog--trace-end trace) (point-marker)) + (set-marker-insertion-type (slime-trace-dialog--trace-beg trace) t) + + (add-text-properties (slime-trace-dialog--trace-beg trace) + (slime-trace-dialog--trace-end trace) + (list 'slime-trace-dialog--id id + 'point-entered autofollow-fn + 'point-left autofollow-fn)) + ;; respect brief mode and collapsed state + ;; + (cl-loop for condition in (list slime-trace-dialog-hide-details-mode + (slime-trace-dialog--trace-collapsed-p trace)) + when condition + do (slime-trace-dialog--hide-unhide + (slime-trace-dialog--trace-summary-beg + trace) + (slime-trace-dialog--trace-end trace) + 1)) + (cl-loop for tr = trace then parent + for parent = (slime-trace-dialog--trace-parent tr) + while parent + when (slime-trace-dialog--trace-collapsed-p parent) + do (slime-trace-dialog--hide-unhide + (slime-trace-dialog--trace-beg trace) + (slime-trace-dialog--trace-end trace) + (+ 1 + (or (get-text-property (slime-trace-dialog--trace-beg parent) + 'slime-trace-dialog--hidden-level) + 0))) + (cl-return)) + ;; maybe add the collapse-button to the parent in case it didn't + ;; have one already + ;; + (when (and parent + (slime-trace-dialog--trace-collapse-button-marker parent)) + (slime-trace-dialog--maintaining-properties + (slime-trace-dialog--trace-collapse-button-marker parent) + (delete-char 1) + (insert (slime-trace-dialog--make-collapse-button parent)) + (setf (slime-trace-dialog--trace-collapse-button-marker parent) + nil))) + ;; draw the tree lines + ;; + (when parent + (slime-trace-dialog--draw-tree-lines (slime-trace-dialog--trace-beg trace) + (+ 2 (length indent-spec)) + 'up)) + (when has-children-p + (slime-trace-dialog--draw-tree-lines (slime-trace-dialog--trace-beg trace) + (+ 5 (length indent-spec)) + 'down)) + ;; set the "children-end" slot + ;; + (unless (slime-trace-dialog--trace-children-end trace) + (cl-loop for parent = trace + then (slime-trace-dialog--trace-parent parent) + while parent + do + (setf (slime-trace-dialog--trace-children-end parent) + (slime-trace-dialog--trace-end trace)))))) + +(defun slime-trace-dialog--render-trace (trace) + ;; Render the trace entry in the appropriate place. + ;; + ;; A trace becomes a few lines of slightly propertized text in the + ;; buffer, inserted by `slime-trace-dialog--insert-trace', bound by + ;; point markers that we use here. + ;; + ;; The new trace might be replacing an existing one, or otherwise + ;; must be placed under its existing parent which might or might not + ;; be the last entry inserted. + ;; + (let ((existing (slime-trace-dialog--find-trace + (slime-trace-dialog--trace-id trace))) + (parent (slime-trace-dialog--trace-parent trace))) + (cond (existing + ;; Other traces might already reference `existing' and with + ;; need to maintain that eqness. Best way to do that is + ;; destructively modify `existing' with the new retlist... + ;; + (setf (slime-trace-dialog--trace-retlist existing) + (slime-trace-dialog--trace-retlist trace)) + ;; Now, before deleting and re-inserting `existing' at an + ;; arbitrary point in the tree, note that it's + ;; "children-end" marker is already non-nil, and informs us + ;; about its parenthood status. We want to 1. leave it + ;; alone if it's already a parent, or 2. set it to nil if + ;; it's a leaf, thus forcing the needed update of the + ;; parents' "children-end" marker. + ;; + (when (= (slime-trace-dialog--trace-children-end existing) + (slime-trace-dialog--trace-end existing)) + (setf (slime-trace-dialog--trace-children-end existing) nil)) + (delete-region (slime-trace-dialog--trace-beg existing) + (slime-trace-dialog--trace-end existing)) + (goto-char (slime-trace-dialog--trace-end existing)) + ;; Remember to set `trace' to be `existing' + ;; + (setq trace existing)) + (parent + (goto-char (1+ (slime-trace-dialog--trace-children-end parent)))) + (;; top level trace + t + (goto-char (point-max)))) + (goto-char (line-beginning-position)) + (slime-trace-dialog--insert-trace trace))) + +(defun slime-trace-dialog--update-tree (tuples) + (save-excursion + (slime-trace-dialog--refresh + (:overlay slime-trace-dialog--tree-overlay + :dont-erase t) + (cl-loop for tuple in tuples + for parent = (slime-trace-dialog--find-trace (cl-second tuple)) + for trace = (slime-trace-dialog--make-trace + :id (cl-first tuple) + :parent parent + :spec (cl-third tuple) + :args (cl-fourth tuple) + :retlist (cl-fifth tuple) + :depth (if parent + (1+ (slime-trace-dialog--trace-depth + parent)) + 0)) + do (slime-trace-dialog--render-trace trace))))) + +(defun slime-trace-dialog--clear-local-tree () + (set (make-local-variable 'slime-trace-dialog--fetch-key) + (cl-gensym "slime-trace-dialog-fetch-key-")) + (set (make-local-variable 'slime-trace-dialog--traces) + (make-hash-table)) + (slime-trace-dialog--refresh + (:overlay slime-trace-dialog--tree-overlay)) + (slime-trace-dialog--update-progress nil)) + +(defun slime-trace-dialog--on-new-results (results &optional recurse) + (cl-destructuring-bind (tuples remaining reply-key) + results + (cond ((and slime-trace-dialog--fetch-key + (string= (symbol-name slime-trace-dialog--fetch-key) + (symbol-name reply-key))) + (slime-trace-dialog--update-tree tuples) + (slime-trace-dialog--update-progress + remaining + (and recurse + (cl-plusp remaining)) + t) + (when (and recurse + (not (prog1 slime-trace-dialog--stop-fetching + (setq slime-trace-dialog--stop-fetching nil))) + (cl-plusp remaining)) + (slime-eval-async `(swank-trace-dialog:report-partial-tree + ',reply-key) + #'(lambda (results) (slime-trace-dialog--on-new-results + results + recurse)))))))) + + +;;;; Interactive functions +;;; +(defun slime-trace-dialog-fetch-specs () + "Refresh just list of traced specs." + (interactive) + (slime-eval-async `(swank-trace-dialog:report-specs) + #'slime-trace-dialog--open-specs)) + +(defun slime-trace-dialog-fetch-progress () + (interactive) + (slime-eval-async + '(swank-trace-dialog:report-total) + #'(lambda (total) + (slime-trace-dialog--update-progress + total)))) + +(defun slime-trace-dialog-fetch-status () + "Refresh just the status part of the SLIME Trace Dialog" + (interactive) + (slime-trace-dialog-fetch-specs) + (slime-trace-dialog-fetch-progress)) + +(defun slime-trace-dialog-clear-fetched-traces (&optional interactive) + "Clear local and remote traces collected so far" + (interactive "p") + (when (or (not interactive) + (y-or-n-p "Clear all collected and fetched traces?")) + (slime-eval-async + '(swank-trace-dialog:clear-trace-tree) + #'(lambda (_ignored) + (slime-trace-dialog--clear-local-tree))))) + +(defun slime-trace-dialog-fetch-traces (&optional recurse) + (interactive "P") + (setq slime-trace-dialog--stop-fetching nil) + (slime-eval-async `(swank-trace-dialog:report-partial-tree + ',slime-trace-dialog--fetch-key) + #'(lambda (results) (slime-trace-dialog--on-new-results results + recurse)))) + +(defun slime-trace-dialog-next-button (&optional goback) + (interactive) + (let ((finder (if goback + #'previous-single-property-change + #'next-single-property-change))) + (cl-loop for pos = (funcall finder (point) 'action) + while pos + do (goto-char pos) + until (get-text-property pos 'action)))) + +(defun slime-trace-dialog-prev-button () + (interactive) + (slime-trace-dialog-next-button 'goback)) + +(defvar slime-trace-dialog-after-toggle-hook nil + "Hooks run after toggling a dialog-trace") + +(defun slime-trace-dialog-toggle-trace (&optional using-context-p) + "Toggle the dialog-trace of the spec at point. + +When USING-CONTEXT-P, attempt to decipher lambdas. methods and +other complicated function specs." + (interactive "P") + ;; Notice the use of "spec strings" here as opposed to the + ;; proper cons specs we use on the swank side. + ;; + ;; Notice the conditional use of `slime-trace-query' found in + ;; swank-fancy-trace.el + ;; + (let* ((spec-string (if using-context-p + (slime-extract-context) + (slime-symbol-at-point))) + (spec-string (if (fboundp 'slime-trace-query) + (slime-trace-query spec-string) + spec-string))) + (message "%s" (slime-eval `(swank-trace-dialog:dialog-toggle-trace + (swank::from-string ,spec-string)))) + (run-hooks 'slime-trace-dialog-after-toggle-hook))) + +(defun slime-trace-dialog--update-existing-dialog () + (let ((existing (slime-trace-dialog--live-dialog))) + (when existing + (with-current-buffer existing + (slime-trace-dialog-fetch-status))))) + +(add-hook 'slime-trace-dialog-after-toggle-hook + 'slime-trace-dialog--update-existing-dialog) + +(defun slime-trace-dialog-toggle-complex-trace () + "Toggle the dialog-trace of the complex spec at point. + +See `slime-trace-dialog-toggle-trace'." + (interactive) + (slime-trace-dialog-toggle-trace t)) + +(defun slime-trace-dialog (&optional clear-and-fetch) + "Show trace dialog and refresh trace collection status. + +With optional CLEAR-AND-FETCH prefix arg, clear the current tree +and fetch a first batch of traces." + (interactive "P") + (with-current-buffer + (pop-to-buffer (slime-trace-dialog--ensure-buffer)) + (slime-trace-dialog-fetch-status) + (when (or clear-and-fetch + (null slime-trace-dialog--fetch-key)) + (slime-trace-dialog--clear-local-tree)) + (when clear-and-fetch + (slime-trace-dialog-fetch-traces nil)))) + +(defun slime-trace-dialog-copy-down-to-repl (id part-id type) + "Eval the Trace Dialog entry under point in the REPL (to set *)" + (interactive (cl-loop for prop in '(slime-trace-dialog--id + slime-trace-dialog--part-id + slime-trace-dialog--type) + collect (get-text-property (point) prop))) + (unless (and id part-id type) (error "No trace part at point %s" (point))) + (slime-repl-send-string + (format "%s" `(nth-value 0 + (swank-trace-dialog::find-trace-part + ,id ,part-id ,type)))) + (slime-repl)) + +(provide 'slime-trace-dialog) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-tramp.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-tramp.el new file mode 100644 index 0000000..1e3f14c --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-tramp.el @@ -0,0 +1,121 @@ +(require 'slime) +(require 'tramp) +(eval-when-compile (require 'cl)) ; lexical-let + +(define-slime-contrib slime-tramp + "Filename translations for tramp" + (:authors "Marco Baringer ") + (:license "GPL") + (:on-load + (setq slime-to-lisp-filename-function #'slime-tramp-to-lisp-filename) + (setq slime-from-lisp-filename-function #'slime-tramp-from-lisp-filename))) + +(defcustom slime-filename-translations nil + "Assoc list of hostnames and filename translation functions. +Each element is of the form (HOSTNAME-REGEXP TO-LISP FROM-LISP). + +HOSTNAME-REGEXP is a regexp which is applied to the connection's +slime-machine-instance. If HOSTNAME-REGEXP maches then the +corresponding TO-LISP and FROM-LISP functions will be used to +translate emacs filenames and lisp filenames. + +TO-LISP will be passed the filename of an emacs buffer and must +return a string which the underlying lisp understandas as a +pathname. FROM-LISP will be passed a pathname as returned by the +underlying lisp and must return something that emacs will +understand as a filename (this string will be passed to +find-file). + +This list will be traversed in order, so multiple matching +regexps are possible. + +Example: + +Assuming you run emacs locally and connect to slime running on +the machine 'soren' and you can connect with the username +'animaliter': + + (push (list \"^soren$\" + (lambda (emacs-filename) + (subseq emacs-filename (length \"/ssh:animaliter@soren:\"))) + (lambda (lisp-filename) + (concat \"/ssh:animaliter@soren:\" lisp-filename))) + slime-filename-translations) + +See also `slime-create-filename-translator'." + :type '(repeat (list :tag "Host description" + (regexp :tag "Hostname regexp") + (function :tag "To lisp function") + (function :tag "From lisp function"))) + :group 'slime-lisp) + +(defun slime-find-filename-translators (hostname) + (cond ((cdr (cl-assoc-if (lambda (regexp) (string-match regexp hostname)) + slime-filename-translations))) + (t (list #'identity #'identity)))) + +(defun slime-make-tramp-file-name (username remote-host lisp-filename) + "Tramp compatability function. + +Handles the signature of `tramp-make-tramp-file-name' changing +over time." + (cond + ((>= emacs-major-version 26) + ;; Emacs 26 requires the method to be provided and the signature of + ;; `tramp-make-tramp-file-name' has changed. + (tramp-make-tramp-file-name (tramp-find-method nil username remote-host) + username + nil + remote-host + nil + lisp-filename)) + ((boundp 'tramp-multi-methods) + (tramp-make-tramp-file-name nil nil + username + remote-host + lisp-filename)) + (t + (tramp-make-tramp-file-name nil + username + remote-host + lisp-filename)))) + +(cl-defun slime-create-filename-translator (&key machine-instance + remote-host + username) + "Creates a three element list suitable for push'ing onto +slime-filename-translations which uses Tramp to load files on +hostname using username. MACHINE-INSTANCE is a required +parameter, REMOTE-HOST defaults to MACHINE-INSTANCE and USERNAME +defaults to (user-login-name). + +MACHINE-INSTANCE is the value returned by slime-machine-instance, +which is just the value returned by cl:machine-instance on the +remote lisp. REMOTE-HOST is the fully qualified domain name (or +just the IP) of the remote machine. USERNAME is the username we +should login with. +The functions created here expect your tramp-default-method or + tramp-default-method-alist to be setup correctly." + (lexical-let ((remote-host (or remote-host machine-instance)) + (username (or username (user-login-name)))) + (list (concat "^" machine-instance "$") + (lambda (emacs-filename) + (tramp-file-name-localname + (tramp-dissect-file-name emacs-filename))) + `(lambda (lisp-filename) + (slime-make-tramp-file-name + ,username + ,remote-host + lisp-filename))))) + +(defun slime-tramp-to-lisp-filename (filename) + (funcall (if (slime-connected-p) + (first (slime-find-filename-translators (slime-machine-instance))) + 'identity) + (expand-file-name filename))) + +(defun slime-tramp-from-lisp-filename (filename) + (funcall (second (slime-find-filename-translators (slime-machine-instance))) + filename)) + +(provide 'slime-tramp) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-typeout-frame.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-typeout-frame.el new file mode 100644 index 0000000..7979b19 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-typeout-frame.el @@ -0,0 +1,92 @@ +(require 'slime) +(require 'slime-autodoc) +(require 'cl-lib) + +(defvar slime-typeout-frame-unbind-stack ()) + +(define-slime-contrib slime-typeout-frame + "Display messages in a dedicated frame." + (:authors "Luke Gorrie ") + (:license "GPL") + (:on-load + (unless (slime-typeout-tty-only-p) + (add-hook 'slime-connected-hook 'slime-ensure-typeout-frame) + (add-hook 'slime-autodoc-mode-hook 'slime-typeout-wrap-autodoc) + (cl-loop for (var value) in + '((slime-message-function slime-typeout-message) + (slime-background-message-function slime-typeout-message)) + do (slime-typeout-frame-init-var var value)))) + (:on-unload + (remove-hook 'slime-connected-hook 'slime-ensure-typeout-frame) + (remove-hook 'slime-autodoc-mode-hook 'slime-typeout-wrap-autodoc) + (cl-loop for (var value) in slime-typeout-frame-unbind-stack + do (cond ((eq var 'slime-unbound) (makunbound var)) + (t (set var value)))) + (setq slime-typeout-frame-unbind-stack nil))) + +(defun slime-typeout-frame-init-var (var value) + (push (list var (if (boundp var) (symbol-value var) 'slime-unbound)) + slime-typeout-frame-unbind-stack) + (set var value)) + +(defun slime-typeout-tty-only-p () + (cond ((featurep 'xemacs) + (null (remove 'tty (mapcar #'device-type (console-device-list))))) + (t (not (window-system))))) + + +;;;; Typeout frame + +;; When a "typeout frame" exists it is used to display certain +;; messages instead of the echo area or pop-up windows. + +(defvar slime-typeout-window nil + "The current typeout window.") + +(defvar slime-typeout-frame-properties + '((height . 10) (minibuffer . nil)) + "The typeout frame properties (passed to `make-frame').") + +(defun slime-typeout-buffer () + (with-current-buffer (get-buffer-create (slime-buffer-name :typeout)) + (setq buffer-read-only t) + (current-buffer))) + +(defun slime-typeout-active-p () + (and slime-typeout-window + (window-live-p slime-typeout-window))) + +(defun slime-typeout-message-aux (format-string &rest format-args) + (slime-ensure-typeout-frame) + (with-current-buffer (slime-typeout-buffer) + (let ((inhibit-read-only t) + (msg (apply #'format format-string format-args))) + (unless (string= msg "") + (erase-buffer) + (insert msg))))) + +(defun slime-typeout-message (format-string &rest format-args) + (apply #'slime-typeout-message-aux format-string format-args)) + +(defun slime-make-typeout-frame () + "Create a frame for displaying messages (e.g. arglists)." + (interactive) + (let ((frame (make-frame slime-typeout-frame-properties))) + (save-selected-window + (select-window (frame-selected-window frame)) + (switch-to-buffer (slime-typeout-buffer)) + (setq slime-typeout-window (selected-window))))) + +(defun slime-ensure-typeout-frame () + "Create the typeout frame unless it already exists." + (interactive) + (if (slime-typeout-active-p) + (save-selected-window + (select-window slime-typeout-window) + (switch-to-buffer (slime-typeout-buffer))) + (slime-make-typeout-frame))) + +(defun slime-typeout-wrap-autodoc () + (setq eldoc-message-function 'slime-typeout-message-aux)) + +(provide 'slime-typeout-frame) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-xref-browser.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-xref-browser.el new file mode 100644 index 0000000..45a7ad8 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/slime-xref-browser.el @@ -0,0 +1,99 @@ +(eval-and-compile + (require 'slime)) + +(define-slime-contrib slime-xref-browser + "Xref browsing with tree-widget" + (:authors "Rui Patrocínio ") + (:license "GPL")) + + +;;;; classes browser + +(defun slime-expand-class-node (widget) + (or (widget-get widget :args) + (let ((name (widget-get widget :tag))) + (cl-loop for kid in (slime-eval `(swank:mop :subclasses ,name)) + collect `(tree-widget :tag ,kid + :expander slime-expand-class-node + :has-children t))))) + +(defun slime-browse-classes (name) + "Read the name of a class and show its subclasses." + (interactive (list (slime-read-symbol-name "Class Name: "))) + (slime-call-with-browser-setup + (slime-buffer-name :browser) (slime-current-package) "Class Browser" + (lambda () + (widget-create 'tree-widget :tag name + :expander 'slime-expand-class-node + :has-echildren t)))) + +(defvar slime-browser-map nil + "Keymap for tree widget browsers") + +(require 'tree-widget) +(unless slime-browser-map + (setq slime-browser-map (make-sparse-keymap)) + (set-keymap-parent slime-browser-map widget-keymap) + (define-key slime-browser-map "q" 'bury-buffer)) + +(defun slime-call-with-browser-setup (buffer package title fn) + (switch-to-buffer buffer) + (kill-all-local-variables) + (setq slime-buffer-package package) + (let ((inhibit-read-only t)) (erase-buffer)) + (widget-insert title "\n\n") + (save-excursion + (funcall fn)) + (lisp-mode-variables t) + (slime-mode t) + (use-local-map slime-browser-map) + (widget-setup)) + + +;;;; Xref browser + +(defun slime-fetch-browsable-xrefs (type name) + "Return a list ((LABEL DSPEC)). +LABEL is just a string for display purposes. +DSPEC can be used to expand the node." + (let ((xrefs '())) + (cl-loop for (_file . specs) in (slime-eval `(swank:xref ,type ,name)) do + (cl-loop for (dspec . _location) in specs do + (let ((exp (ignore-errors (read (downcase dspec))))) + (cond ((and (consp exp) (eq 'flet (car exp))) + ;; we can't expand FLET references so they're useless + ) + ((and (consp exp) (eq 'method (car exp))) + ;; this isn't quite right, but good enough for now + (push (list dspec (string (cl-second exp))) xrefs)) + (t + (push (list dspec dspec) xrefs)))))) + xrefs)) + +(defun slime-expand-xrefs (widget) + (or (widget-get widget :args) + (let* ((type (widget-get widget :xref-type)) + (dspec (widget-get widget :xref-dspec)) + (xrefs (slime-fetch-browsable-xrefs type dspec))) + (cl-loop for (label dspec) in xrefs + collect `(tree-widget :tag ,label + :xref-type ,type + :xref-dspec ,dspec + :expander slime-expand-xrefs + :has-children t))))) + +(defun slime-browse-xrefs (name type) + "Show the xref graph of a function in a tree widget." + (interactive + (list (slime-read-from-minibuffer "Name: " + (slime-symbol-at-point)) + (read (completing-read "Type: " (slime-bogus-completion-alist + '(":callers" ":callees" ":calls")) + nil t ":")))) + (slime-call-with-browser-setup + (slime-buffer-name :xref) (slime-current-package) "Xref Browser" + (lambda () + (widget-create 'tree-widget :tag name :xref-type type :xref-dspec name + :expander 'slime-expand-xrefs :has-echildren t)))) + +(provide 'slime-xref-browser) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-arglists.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-arglists.lisp new file mode 100644 index 0000000..9e35add --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-arglists.lisp @@ -0,0 +1,1620 @@ +;;; swank-arglists.lisp --- arglist related code ?? +;; +;; Authors: Matthias Koeppe +;; Tobias C. Rittweiler +;; and others +;; +;; License: Public Domain +;; + +(in-package :swank) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (swank-require :swank-c-p-c)) + +;;;; Utilities + +(defun compose (&rest functions) + "Compose FUNCTIONS right-associatively, returning a function" + #'(lambda (x) + (reduce #'funcall functions :initial-value x :from-end t))) + +(defun length= (seq n) + "Test for whether SEQ contains N number of elements. I.e. it's equivalent + to (= (LENGTH SEQ) N), but besides being more concise, it may also be more + efficiently implemented." + (etypecase seq + (list (do ((i n (1- i)) + (list seq (cdr list))) + ((or (<= i 0) (null list)) + (and (zerop i) (null list))))) + (sequence (= (length seq) n)))) + +(declaim (inline memq)) +(defun memq (item list) + (member item list :test #'eq)) + +(defun exactly-one-p (&rest values) + "If exactly one value in VALUES is non-NIL, this value is returned. +Otherwise NIL is returned." + (let ((found nil)) + (dolist (v values) + (when v (if found + (return-from exactly-one-p nil) + (setq found v)))) + found)) + +(defun valid-operator-symbol-p (symbol) + "Is SYMBOL the name of a function, a macro, or a special-operator?" + (or (fboundp symbol) + (macro-function symbol) + (special-operator-p symbol) + (member symbol '(declare declaim)))) + +(defun function-exists-p (form) + (and (valid-function-name-p form) + (fboundp form) + t)) + +(defmacro multiple-value-or (&rest forms) + (if (null forms) + nil + (let ((first (first forms)) + (rest (rest forms))) + `(let* ((values (multiple-value-list ,first)) + (primary-value (first values))) + (if primary-value + (values-list values) + (multiple-value-or ,@rest)))))) + +(defun arglist-available-p (arglist) + (not (eql arglist :not-available))) + +(defmacro with-available-arglist ((var &rest more-vars) form &body body) + `(multiple-value-bind (,var ,@more-vars) ,form + (if (eql ,var :not-available) + :not-available + (progn ,@body)))) + + +;;;; Arglist Definition + +(defstruct (arglist (:conc-name arglist.) (:predicate arglist-p)) + provided-args ; list of the provided actual arguments + required-args ; list of the required arguments + optional-args ; list of the optional arguments + key-p ; whether &key appeared + keyword-args ; list of the keywords + rest ; name of the &rest or &body argument (if any) + body-p ; whether the rest argument is a &body + allow-other-keys-p ; whether &allow-other-keys appeared + aux-args ; list of &aux variables + any-p ; whether &any appeared + any-args ; list of &any arguments [*] + known-junk ; &whole, &environment + unknown-junk) ; unparsed stuff + +;;; +;;; [*] The &ANY lambda keyword is an extension to ANSI Common Lisp, +;;; and is only used to describe certain arglists that cannot be +;;; described in another way. +;;; +;;; &ANY is very similiar to &KEY but while &KEY is based upon +;;; the idea of a plist (key1 value1 key2 value2), &ANY is a +;;; cross between &OPTIONAL, &KEY and *FEATURES* lists: +;;; +;;; a) (&ANY :A :B :C) means that you can provide any (non-null) +;;; set consisting of the keywords `:A', `:B', or `:C' in +;;; the arglist. E.g. (:A) or (:C :B :A). +;;; +;;; (This is not restricted to keywords only, but any self-evaluating +;;; expression is allowed.) +;;; +;;; b) (&ANY (key1 v1) (key2 v2) (key3 v3)) means that you can +;;; provide any (non-null) set consisting of lists where +;;; the CAR of the list is one of `key1', `key2', or `key3'. +;;; E.g. ((key1 100) (key3 42)), or ((key3 66) (key2 23)) +;;; +;;; +;;; For example, a) let us describe the situations of EVAL-WHEN as +;;; +;;; (EVAL-WHEN (&ANY :compile-toplevel :load-toplevel :execute) &BODY body) +;;; +;;; and b) let us describe the optimization qualifiers that are valid +;;; in the declaration specifier `OPTIMIZE': +;;; +;;; (DECLARE (OPTIMIZE &ANY (compilation-speed 1) (safety 1) ...)) +;;; + +;; This is a wrapper object around anything that came from Slime and +;; could not reliably be read. +(defstruct (arglist-dummy + (:conc-name #:arglist-dummy.) + (:constructor make-arglist-dummy (string-representation))) + string-representation) + +(defun empty-arg-p (dummy) + (and (arglist-dummy-p dummy) + (zerop (length (arglist-dummy.string-representation dummy))))) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defparameter +lambda-list-keywords+ + '(&provided &required &optional &rest &key &any))) + +(defmacro do-decoded-arglist (decoded-arglist &body clauses) + (assert (loop for clause in clauses + thereis (member (car clause) +lambda-list-keywords+))) + (flet ((parse-clauses (clauses) + (let* ((size (length +lambda-list-keywords+)) + (initial (make-hash-table :test #'eq :size size)) + (main (make-hash-table :test #'eq :size size)) + (final (make-hash-table :test #'eq :size size))) + (loop for clause in clauses + for lambda-list-keyword = (first clause) + for clause-parameter = (second clause) + do + (case clause-parameter + (:initially + (setf (gethash lambda-list-keyword initial) clause)) + (:finally + (setf (gethash lambda-list-keyword final) clause)) + (t + (setf (gethash lambda-list-keyword main) clause))) + finally + (return (values initial main final))))) + (generate-main-clause (clause arglist) + (dcase clause + ((&provided (&optional arg) . body) + (let ((gensym (gensym "PROVIDED-ARG+"))) + `(dolist (,gensym (arglist.provided-args ,arglist)) + (declare (ignorable ,gensym)) + (let (,@(when arg `((,arg ,gensym)))) + ,@body)))) + ((&required (&optional arg) . body) + (let ((gensym (gensym "REQUIRED-ARG+"))) + `(dolist (,gensym (arglist.required-args ,arglist)) + (declare (ignorable ,gensym)) + (let (,@(when arg `((,arg ,gensym)))) + ,@body)))) + ((&optional (&optional arg init) . body) + (let ((optarg (gensym "OPTIONAL-ARG+"))) + `(dolist (,optarg (arglist.optional-args ,arglist)) + (declare (ignorable ,optarg)) + (let (,@(when arg + `((,arg (optional-arg.arg-name ,optarg)))) + ,@(when init + `((,init (optional-arg.default-arg ,optarg))))) + ,@body)))) + ((&key (&optional keyword arg init) . body) + (let ((keyarg (gensym "KEY-ARG+"))) + `(dolist (,keyarg (arglist.keyword-args ,arglist)) + (declare (ignorable ,keyarg)) + (let (,@(when keyword + `((,keyword (keyword-arg.keyword ,keyarg)))) + ,@(when arg + `((,arg (keyword-arg.arg-name ,keyarg)))) + ,@(when init + `((,init (keyword-arg.default-arg ,keyarg))))) + ,@body)))) + ((&rest (&optional arg body-p) . body) + `(when (arglist.rest ,arglist) + (let (,@(when arg `((,arg (arglist.rest ,arglist)))) + ,@(when body-p `((,body-p (arglist.body-p ,arglist))))) + ,@body))) + ((&any (&optional arg) . body) + (let ((gensym (gensym "REQUIRED-ARG+"))) + `(dolist (,gensym (arglist.any-args ,arglist)) + (declare (ignorable ,gensym)) + (let (,@(when arg `((,arg ,gensym)))) + ,@body))))))) + (let ((arglist (gensym "DECODED-ARGLIST+"))) + (multiple-value-bind (initially-clauses main-clauses finally-clauses) + (parse-clauses clauses) + `(let ((,arglist ,decoded-arglist)) + (block do-decoded-arglist + ,@(loop for keyword in '(&provided &required + &optional &rest &key &any) + append (cddr (gethash keyword initially-clauses)) + collect (let ((clause (gethash keyword main-clauses))) + (when clause + (generate-main-clause clause arglist))) + append (cddr (gethash keyword finally-clauses))))))))) + +;;;; Arglist Printing + +(defun undummy (x) + (if (typep x 'arglist-dummy) + (arglist-dummy.string-representation x) + (prin1-to-string x))) + +(defun print-decoded-arglist (arglist &key operator provided-args highlight) + (let ((first-space-after-operator (and operator t))) + (macrolet ((space () + ;; Kludge: When OPERATOR is not given, we don't want to + ;; print a space for the first argument. + `(if (not operator) + (setq operator t) + (progn (write-char #\space) + (if first-space-after-operator + (setq first-space-after-operator nil) + (pprint-newline :fill))))) + (with-highlighting ((&key index) &body body) + `(if (eql ,index (car highlight)) + (progn (princ "===> ") ,@body (princ " <===")) + (progn ,@body))) + (print-arglist-recursively (argl &key index) + `(if (eql ,index (car highlight)) + (print-decoded-arglist ,argl :highlight (cdr highlight)) + (print-decoded-arglist ,argl)))) + (let ((index 0)) + (pprint-logical-block (nil nil :prefix "(" :suffix ")") + (when operator + (print-arg operator) + (pprint-indent :current 1)) ; 1 due to possibly added space + (do-decoded-arglist (remove-given-args arglist provided-args) + (&provided (arg) + (space) + (print-arg arg :literal-strings t) + (incf index)) + (&required (arg) + (space) + (if (arglist-p arg) + (print-arglist-recursively arg :index index) + (with-highlighting (:index index) + (print-arg arg))) + (incf index)) + (&optional :initially + (when (arglist.optional-args arglist) + (space) + (princ '&optional))) + (&optional (arg init-value) + (space) + (if (arglist-p arg) + (print-arglist-recursively arg :index index) + (with-highlighting (:index index) + (if (null init-value) + (print-arg arg) + (format t "~:@<~A ~A~@:>" + (undummy arg) (undummy init-value))))) + (incf index)) + (&key :initially + (when (arglist.key-p arglist) + (space) + (princ '&key))) + (&key (keyword arg init) + (space) + (if (arglist-p arg) + (pprint-logical-block (nil nil :prefix "(" :suffix ")") + (prin1 keyword) (space) + (print-arglist-recursively arg :index keyword)) + (with-highlighting (:index keyword) + (cond ((and init (keywordp keyword)) + (format t "~:@<~A ~A~@:>" keyword (undummy init))) + (init + (format t "~:@<(~A ..) ~A~@:>" + (undummy keyword) (undummy init))) + ((not (keywordp keyword)) + (format t "~:@<(~S ..)~@:>" keyword)) + (t + (princ keyword)))))) + (&key :finally + (when (arglist.allow-other-keys-p arglist) + (space) + (princ '&allow-other-keys))) + (&any :initially + (when (arglist.any-p arglist) + (space) + (princ '&any))) + (&any (arg) + (space) + (print-arg arg)) + (&rest (args bodyp) + (space) + (princ (if bodyp '&body '&rest)) + (space) + (if (arglist-p args) + (print-arglist-recursively args :index index) + (with-highlighting (:index index) + (print-arg args)))) + ;; FIXME: add &UNKNOWN-JUNK? + )))))) + +(defun print-arg (arg &key literal-strings) + (let ((arg (if (arglist-dummy-p arg) + (arglist-dummy.string-representation arg) + arg))) + (if (or + (and literal-strings + (stringp arg)) + (keywordp arg)) + (prin1 arg) + (princ arg)))) + +(defun print-decoded-arglist-as-template (decoded-arglist &key + (prefix "(") (suffix ")")) + (let ((first-p t)) + (flet ((space () + (unless first-p + (write-char #\space)) + (setq first-p nil)) + (print-arg-or-pattern (arg) + (etypecase arg + (symbol (if (keywordp arg) (prin1 arg) (princ arg))) + (string (princ arg)) + (list (princ arg)) + (arglist-dummy (princ + (arglist-dummy.string-representation arg))) + (arglist (print-decoded-arglist-as-template arg))) + (pprint-newline :fill))) + (pprint-logical-block (nil nil :prefix prefix :suffix suffix) + (do-decoded-arglist decoded-arglist + (&provided ()) ; do nothing; provided args are in the buffer already. + (&required (arg) + (space) (print-arg-or-pattern arg)) + (&optional (arg) + (space) (princ "[") (print-arg-or-pattern arg) (princ "]")) + (&key (keyword arg) + (space) + (prin1 (if (keywordp keyword) keyword `',keyword)) + (space) + (print-arg-or-pattern arg) + (pprint-newline :linear)) + (&any (arg) + (space) (print-arg-or-pattern arg)) + (&rest (args) + (when (or (not (arglist.keyword-args decoded-arglist)) + (arglist.allow-other-keys-p decoded-arglist)) + (space) + (format t "~A..." args)))))))) + +(defvar *arglist-pprint-bindings* + '((*print-case* . :downcase) + (*print-pretty* . t) + (*print-circle* . nil) + (*print-readably* . nil) + (*print-level* . 10) + (*print-length* . 20) + (*print-escape* . nil))) + +(defvar *arglist-show-packages* t) + +(defmacro with-arglist-io-syntax (&body body) + (let ((package (gensym))) + `(let ((,package *package*)) + (with-standard-io-syntax + (let ((*package* (if *arglist-show-packages* + *package* + ,package))) + (with-bindings *arglist-pprint-bindings* + ,@body)))))) + +(defun decoded-arglist-to-string (decoded-arglist + &key operator highlight + print-right-margin) + (with-output-to-string (*standard-output*) + (with-arglist-io-syntax + (let ((*print-right-margin* print-right-margin)) + (print-decoded-arglist decoded-arglist + :operator operator + :highlight highlight))))) + +(defun decoded-arglist-to-template-string (decoded-arglist + &key (prefix "(") (suffix ")")) + (with-output-to-string (*standard-output*) + (with-arglist-io-syntax + (print-decoded-arglist-as-template decoded-arglist + :prefix prefix + :suffix suffix)))) + +;;;; Arglist Decoding / Encoding + +(defun decode-required-arg (arg) + "ARG can be a symbol or a destructuring pattern." + (etypecase arg + (symbol arg) + (arglist-dummy arg) + (list (decode-arglist arg)))) + +(defun encode-required-arg (arg) + (etypecase arg + (symbol arg) + (arglist (encode-arglist arg)))) + +(defstruct (keyword-arg + (:conc-name keyword-arg.) + (:constructor %make-keyword-arg)) + keyword + arg-name + default-arg) + +(defun canonicalize-default-arg (form) + (if (equalp ''nil form) + nil + form)) + +(defun make-keyword-arg (keyword arg-name default-arg) + (%make-keyword-arg :keyword keyword + :arg-name arg-name + :default-arg (canonicalize-default-arg default-arg))) + +(defun decode-keyword-arg (arg) + "Decode a keyword item of formal argument list. +Return three values: keyword, argument name, default arg." + (flet ((intern-as-keyword (arg) + (intern (etypecase arg + (symbol (symbol-name arg)) + (arglist-dummy (arglist-dummy.string-representation arg))) + keyword-package))) + (cond ((or (symbolp arg) (arglist-dummy-p arg)) + (make-keyword-arg (intern-as-keyword arg) arg nil)) + ((and (consp arg) + (consp (car arg))) + (make-keyword-arg (caar arg) + (decode-required-arg (cadar arg)) + (cadr arg))) + ((consp arg) + (make-keyword-arg (intern-as-keyword (car arg)) + (car arg) (cadr arg))) + (t + (error "Bad keyword item of formal argument list"))))) + +(defun encode-keyword-arg (arg) + (cond + ((arglist-p (keyword-arg.arg-name arg)) + ;; Destructuring pattern + (let ((keyword/name (list (keyword-arg.keyword arg) + (encode-required-arg + (keyword-arg.arg-name arg))))) + (if (keyword-arg.default-arg arg) + (list keyword/name + (keyword-arg.default-arg arg)) + (list keyword/name)))) + ((eql (intern (symbol-name (keyword-arg.arg-name arg)) + keyword-package) + (keyword-arg.keyword arg)) + (if (keyword-arg.default-arg arg) + (list (keyword-arg.arg-name arg) + (keyword-arg.default-arg arg)) + (keyword-arg.arg-name arg))) + (t + (let ((keyword/name (list (keyword-arg.keyword arg) + (keyword-arg.arg-name arg)))) + (if (keyword-arg.default-arg arg) + (list keyword/name + (keyword-arg.default-arg arg)) + (list keyword/name)))))) + +(progn + (assert (equalp (decode-keyword-arg 'x) + (make-keyword-arg :x 'x nil))) + (assert (equalp (decode-keyword-arg '(x t)) + (make-keyword-arg :x 'x t))) + (assert (equalp (decode-keyword-arg '((:x y))) + (make-keyword-arg :x 'y nil))) + (assert (equalp (decode-keyword-arg '((:x y) t)) + (make-keyword-arg :x 'y t)))) + +;;; FIXME suppliedp? +(defstruct (optional-arg + (:conc-name optional-arg.) + (:constructor %make-optional-arg)) + arg-name + default-arg) + +(defun make-optional-arg (arg-name default-arg) + (%make-optional-arg :arg-name arg-name + :default-arg (canonicalize-default-arg default-arg))) + +(defun decode-optional-arg (arg) + "Decode an optional item of a formal argument list. +Return an OPTIONAL-ARG structure." + (etypecase arg + (symbol (make-optional-arg arg nil)) + (arglist-dummy (make-optional-arg arg nil)) + (list (make-optional-arg (decode-required-arg (car arg)) + (cadr arg))))) + +(defun encode-optional-arg (optional-arg) + (if (or (optional-arg.default-arg optional-arg) + (arglist-p (optional-arg.arg-name optional-arg))) + (list (encode-required-arg + (optional-arg.arg-name optional-arg)) + (optional-arg.default-arg optional-arg)) + (optional-arg.arg-name optional-arg))) + +(progn + (assert (equalp (decode-optional-arg 'x) + (make-optional-arg 'x nil))) + (assert (equalp (decode-optional-arg '(x t)) + (make-optional-arg 'x t)))) + +(define-modify-macro nreversef () nreverse "Reverse the list in PLACE.") + +(defun decode-arglist (arglist) + "Parse the list ARGLIST and return an ARGLIST structure." + (etypecase arglist + ((eql :not-available) (return-from decode-arglist + :not-available)) + (list)) + (loop + with mode = nil + with result = (make-arglist) + for arg = (if (consp arglist) + (pop arglist) + (progn + (prog1 arglist + (setf mode '&rest + arglist nil)))) + do (cond + ((eql mode '&unknown-junk) + ;; don't leave this mode -- we don't know how the arglist + ;; after unknown lambda-list keywords is interpreted + (push arg (arglist.unknown-junk result))) + ((eql arg '&allow-other-keys) + (setf (arglist.allow-other-keys-p result) t)) + ((eql arg '&key) + (setf (arglist.key-p result) t + mode arg)) + ((memq arg '(&optional &rest &body &aux)) + (setq mode arg)) + ((memq arg '(&whole &environment)) + (setq mode arg) + (push arg (arglist.known-junk result))) + ((and (symbolp arg) + (string= (symbol-name arg) (string '#:&any))) ; may be interned + (setf (arglist.any-p result) t) ; in any *package*. + (setq mode '&any)) + ((memq arg lambda-list-keywords) + (setq mode '&unknown-junk) + (push arg (arglist.unknown-junk result))) + (t + (ecase mode + (&key + (push (decode-keyword-arg arg) + (arglist.keyword-args result))) + (&optional + (push (decode-optional-arg arg) + (arglist.optional-args result))) + (&body + (setf (arglist.body-p result) t + (arglist.rest result) arg)) + (&rest + (setf (arglist.rest result) arg)) + (&aux + (push (decode-optional-arg arg) + (arglist.aux-args result))) + ((nil) + (push (decode-required-arg arg) + (arglist.required-args result))) + ((&whole &environment) + (setf mode nil) + (push arg (arglist.known-junk result))) + (&any + (push arg (arglist.any-args result)))))) + until (null arglist) + finally (nreversef (arglist.required-args result)) + finally (nreversef (arglist.optional-args result)) + finally (nreversef (arglist.keyword-args result)) + finally (nreversef (arglist.aux-args result)) + finally (nreversef (arglist.any-args result)) + finally (nreversef (arglist.known-junk result)) + finally (nreversef (arglist.unknown-junk result)) + finally (assert (or (and (not (arglist.key-p result)) + (not (arglist.any-p result))) + (exactly-one-p (arglist.key-p result) + (arglist.any-p result)))) + finally (return result))) + +(defun encode-arglist (decoded-arglist) + (append (mapcar #'encode-required-arg + (arglist.required-args decoded-arglist)) + (when (arglist.optional-args decoded-arglist) + '(&optional)) + (mapcar #'encode-optional-arg + (arglist.optional-args decoded-arglist)) + (when (arglist.key-p decoded-arglist) + '(&key)) + (mapcar #'encode-keyword-arg + (arglist.keyword-args decoded-arglist)) + (when (arglist.allow-other-keys-p decoded-arglist) + '(&allow-other-keys)) + (when (arglist.any-args decoded-arglist) + `(&any ,@(arglist.any-args decoded-arglist))) + (cond ((not (arglist.rest decoded-arglist)) + '()) + ((arglist.body-p decoded-arglist) + `(&body ,(arglist.rest decoded-arglist))) + (t + `(&rest ,(arglist.rest decoded-arglist)))) + (when (arglist.aux-args decoded-arglist) + `(&aux ,(arglist.aux-args decoded-arglist))) + (arglist.known-junk decoded-arglist) + (arglist.unknown-junk decoded-arglist))) + +;;;; Arglist Enrichment + +(defun arglist-keywords (lambda-list) + "Return the list of keywords in ARGLIST. +As a secondary value, return whether &allow-other-keys appears." + (let ((decoded-arglist (decode-arglist lambda-list))) + (values (arglist.keyword-args decoded-arglist) + (arglist.allow-other-keys-p decoded-arglist)))) + + +(defun methods-keywords (methods) + "Collect all keywords in the arglists of METHODS. +As a secondary value, return whether &allow-other-keys appears somewhere." + (let ((keywords '()) + (allow-other-keys nil)) + (dolist (method methods) + (multiple-value-bind (kw aok) + (arglist-keywords + (swank-mop:method-lambda-list method)) + (setq keywords (remove-duplicates (append keywords kw) + :key #'keyword-arg.keyword) + allow-other-keys (or allow-other-keys aok)))) + (values keywords allow-other-keys))) + +(defun generic-function-keywords (generic-function) + "Collect all keywords in the methods of GENERIC-FUNCTION. +As a secondary value, return whether &allow-other-keys appears somewhere." + (methods-keywords + (swank-mop:generic-function-methods generic-function))) + +(defun applicable-methods-keywords (generic-function arguments) + "Collect all keywords in the methods of GENERIC-FUNCTION that are +applicable for argument of CLASSES. As a secondary value, return +whether &allow-other-keys appears somewhere." + (methods-keywords + (multiple-value-bind (amuc okp) + (swank-mop:compute-applicable-methods-using-classes + generic-function (mapcar #'class-of arguments)) + (if okp + amuc + (compute-applicable-methods generic-function arguments))))) + +(defgeneric extra-keywords (operator args) + (:documentation "Return a list of extra keywords of OPERATOR (a +symbol) when applied to the (unevaluated) ARGS. +As a secondary value, return whether other keys are allowed. +As a tertiary value, return the initial sublist of ARGS that was needed +to determine the extra keywords.")) + +;;; We make sure that symbol-from-KEYWORD-using keywords come before +;;; symbol-from-arbitrary-package-using keywords. And we sort the +;;; latter according to how their home-packages relate to *PACKAGE*. +;;; +;;; Rationale is to show those key parameters first which make most +;;; sense in the current context. And in particular: to put +;;; implementation-internal stuff last. +;;; +;;; This matters tremendeously on Allegro in combination with +;;; AllegroCache as that does some evil tinkering with initargs, +;;; obfuscating the arglist of MAKE-INSTANCE. +;;; + +(defmethod extra-keywords :around (op args) + (declare (ignorable op args)) + (multiple-value-bind (keywords aok enrichments) (call-next-method) + (values (sort-extra-keywords keywords) aok enrichments))) + +(defun make-package-comparator (reference-packages) + "Returns a two-argument test function which compares packages +according to their used-by relation with REFERENCE-PACKAGES. Packages +will be sorted first which appear first in the PACKAGE-USE-LIST of the +reference packages." + (let ((package-use-table (make-hash-table :test 'eq))) + ;; Walk the package dependency graph breadth-fist, and fill + ;; PACKAGE-USE-TABLE accordingly. + (loop with queue = (copy-list reference-packages) + with bfn = 0 ; Breadth-First Number + for p = (pop queue) + unless (gethash p package-use-table) + do (setf (gethash p package-use-table) (shiftf bfn (1+ bfn))) + and do (setf queue (nconc queue (copy-list (package-use-list p)))) + while queue) + #'(lambda (p1 p2) + (let ((bfn1 (gethash p1 package-use-table)) + (bfn2 (gethash p2 package-use-table))) + (cond ((and bfn1 bfn2) (<= bfn1 bfn2)) + (bfn1 bfn1) + (bfn2 nil) ; p2 is used, p1 not + (t (string<= (package-name p1) (package-name p2)))))))) + +(defun sort-extra-keywords (kwds) + (stable-sort kwds (make-package-comparator (list keyword-package *package*)) + :key (compose #'symbol-package #'keyword-arg.keyword))) + +(defun keywords-of-operator (operator) + "Return a list of KEYWORD-ARGs that OPERATOR accepts. +This function is useful for writing EXTRA-KEYWORDS methods for +user-defined functions which are declared &ALLOW-OTHER-KEYS and which +forward keywords to OPERATOR." + (with-available-arglist (arglist) (arglist-from-form (ensure-list operator)) + (values (arglist.keyword-args arglist) + (arglist.allow-other-keys-p arglist)))) + +(defmethod extra-keywords (operator args) + ;; default method + (declare (ignore args)) + (let ((symbol-function (symbol-function operator))) + (if (typep symbol-function 'generic-function) + (generic-function-keywords symbol-function) + nil))) + +(defun class-from-class-name-form (class-name-form) + (when (and (listp class-name-form) + (= (length class-name-form) 2) + (eq (car class-name-form) 'quote)) + (let* ((class-name (cadr class-name-form)) + (class (find-class class-name nil))) + (when (and class + (not (swank-mop:class-finalized-p class))) + ;; Try to finalize the class, which can fail if + ;; superclasses are not defined yet + (ignore-errors (swank-mop:finalize-inheritance class))) + class))) + +(defun extra-keywords/slots (class) + (multiple-value-bind (slots allow-other-keys-p) + (if (swank-mop:class-finalized-p class) + (values (swank-mop:class-slots class) nil) + (values (swank-mop:class-direct-slots class) t)) + (let ((slot-init-keywords + (loop for slot in slots append + (mapcar (lambda (initarg) + (make-keyword-arg + initarg + (swank-mop:slot-definition-name slot) + (and (swank-mop:slot-definition-initfunction slot) + (swank-mop:slot-definition-initform slot)))) + (swank-mop:slot-definition-initargs slot))))) + (values slot-init-keywords allow-other-keys-p)))) + +(defun extra-keywords/make-instance (operator args) + (declare (ignore operator)) + (unless (null args) + (let* ((class-name-form (car args)) + (class (class-from-class-name-form class-name-form))) + (when class + (multiple-value-bind (slot-init-keywords class-aokp) + (extra-keywords/slots class) + (multiple-value-bind (allocate-instance-keywords ai-aokp) + (applicable-methods-keywords + #'allocate-instance (list class)) + (multiple-value-bind (initialize-instance-keywords ii-aokp) + (ignore-errors + (applicable-methods-keywords + #'initialize-instance + (list (swank-mop:class-prototype class)))) + (multiple-value-bind (shared-initialize-keywords si-aokp) + (ignore-errors + (applicable-methods-keywords + #'shared-initialize + (list (swank-mop:class-prototype class) t))) + (values (append slot-init-keywords + allocate-instance-keywords + initialize-instance-keywords + shared-initialize-keywords) + (or class-aokp ai-aokp ii-aokp si-aokp) + (list class-name-form)))))))))) + +(defun extra-keywords/change-class (operator args) + (declare (ignore operator)) + (unless (null args) + (let* ((class-name-form (car args)) + (class (class-from-class-name-form class-name-form))) + (when class + (multiple-value-bind (slot-init-keywords class-aokp) + (extra-keywords/slots class) + (declare (ignore class-aokp)) + (multiple-value-bind (shared-initialize-keywords si-aokp) + (ignore-errors + (applicable-methods-keywords + #'shared-initialize + (list (swank-mop:class-prototype class) t))) + ;; FIXME: much as it would be nice to include the + ;; applicable keywords from + ;; UPDATE-INSTANCE-FOR-DIFFERENT-CLASS, I don't really see + ;; how to do it: so we punt, always declaring + ;; &ALLOW-OTHER-KEYS. + (declare (ignore si-aokp)) + (values (append slot-init-keywords shared-initialize-keywords) + t + (list class-name-form)))))))) + +(defmethod extra-keywords ((operator (eql 'make-instance)) + args) + (multiple-value-or (extra-keywords/make-instance operator args) + (call-next-method))) + +(defmethod extra-keywords ((operator (eql 'make-condition)) + args) + (multiple-value-or (extra-keywords/make-instance operator args) + (call-next-method))) + +(defmethod extra-keywords ((operator (eql 'error)) + args) + (multiple-value-or (extra-keywords/make-instance operator args) + (call-next-method))) + +(defmethod extra-keywords ((operator (eql 'signal)) + args) + (multiple-value-or (extra-keywords/make-instance operator args) + (call-next-method))) + +(defmethod extra-keywords ((operator (eql 'warn)) + args) + (multiple-value-or (extra-keywords/make-instance operator args) + (call-next-method))) + +(defmethod extra-keywords ((operator (eql 'cerror)) + args) + (multiple-value-bind (keywords aok determiners) + (extra-keywords/make-instance operator (cdr args)) + (if keywords + (values keywords aok + (cons (car args) determiners)) + (call-next-method)))) + +(defmethod extra-keywords ((operator (eql 'change-class)) + args) + (multiple-value-bind (keywords aok determiners) + (extra-keywords/change-class operator (cdr args)) + (if keywords + (values keywords aok + (cons (car args) determiners)) + (call-next-method)))) + +(defun enrich-decoded-arglist-with-keywords (decoded-arglist keywords + allow-other-keys-p) + "Modify DECODED-ARGLIST using KEYWORDS and ALLOW-OTHER-KEYS-P." + (when keywords + (setf (arglist.key-p decoded-arglist) t) + (setf (arglist.keyword-args decoded-arglist) + (remove-duplicates + (append (arglist.keyword-args decoded-arglist) + keywords) + :key #'keyword-arg.keyword))) + (setf (arglist.allow-other-keys-p decoded-arglist) + (or (arglist.allow-other-keys-p decoded-arglist) + allow-other-keys-p))) + +(defun enrich-decoded-arglist-with-extra-keywords (decoded-arglist form) + "Determine extra keywords from the function call FORM, and modify +DECODED-ARGLIST to include them. As a secondary return value, return +the initial sublist of ARGS that was needed to determine the extra +keywords. As a tertiary return value, return whether any enrichment +was done." + (multiple-value-bind (extra-keywords extra-aok determining-args) + (extra-keywords (car form) (cdr form)) + ;; enrich the list of keywords with the extra keywords + (enrich-decoded-arglist-with-keywords decoded-arglist + extra-keywords extra-aok) + (values decoded-arglist + determining-args + (or extra-keywords extra-aok)))) + +(defgeneric compute-enriched-decoded-arglist (operator-form argument-forms) + (:documentation + "Return three values: DECODED-ARGLIST, DETERMINING-ARGS, and +ANY-ENRICHMENT, just like enrich-decoded-arglist-with-extra-keywords. +If the arglist is not available, return :NOT-AVAILABLE.")) + +(defmethod compute-enriched-decoded-arglist (operator-form argument-forms) + (with-available-arglist (decoded-arglist) + (decode-arglist (arglist operator-form)) + (enrich-decoded-arglist-with-extra-keywords decoded-arglist + (cons operator-form + argument-forms)))) + +(defmethod compute-enriched-decoded-arglist + ((operator-form (eql 'with-open-file)) argument-forms) + (declare (ignore argument-forms)) + (multiple-value-bind (decoded-arglist determining-args) + (call-next-method) + (let ((first-arg (first (arglist.required-args decoded-arglist))) + (open-arglist (compute-enriched-decoded-arglist 'open nil))) + (when (and (arglist-p first-arg) (arglist-p open-arglist)) + (enrich-decoded-arglist-with-keywords + first-arg + (arglist.keyword-args open-arglist) + nil))) + (values decoded-arglist determining-args t))) + +(defmethod compute-enriched-decoded-arglist ((operator-form (eql 'apply)) + argument-forms) + (let ((function-name-form (car argument-forms))) + (when (and (listp function-name-form) + (length= function-name-form 2) + (memq (car function-name-form) '(quote function))) + (let ((function-name (cadr function-name-form))) + (when (valid-operator-symbol-p function-name) + (let ((function-arglist + (compute-enriched-decoded-arglist function-name + (cdr argument-forms)))) + (return-from compute-enriched-decoded-arglist + (values + (make-arglist :required-args + (list 'function) + :optional-args + (append + (mapcar #'(lambda (arg) + (make-optional-arg arg nil)) + (arglist.required-args function-arglist)) + (arglist.optional-args function-arglist)) + :key-p + (arglist.key-p function-arglist) + :keyword-args + (arglist.keyword-args function-arglist) + :rest + 'args + :allow-other-keys-p + (arglist.allow-other-keys-p function-arglist)) + (list function-name-form) + t))))))) + (call-next-method)) + +(defmethod compute-enriched-decoded-arglist + ((operator-form (eql 'multiple-value-call)) argument-forms) + (compute-enriched-decoded-arglist 'apply argument-forms)) + +(defun delete-given-args (decoded-arglist args) + "Delete given ARGS from DECODED-ARGLIST." + (macrolet ((pop-or-return (list) + `(if (null ,list) + (return-from do-decoded-arglist) + (pop ,list)))) + (do-decoded-arglist decoded-arglist + (&provided () + (assert (eq (pop-or-return args) + (pop (arglist.provided-args decoded-arglist))))) + (&required () + (pop-or-return args) + (pop (arglist.required-args decoded-arglist))) + (&optional () + (pop-or-return args) + (pop (arglist.optional-args decoded-arglist))) + (&key (keyword) + ;; N.b. we consider a keyword to be given only when the keyword + ;; _and_ a value has been given for it. + (loop for (key value) on args by #'cddr + when (and (eq keyword key) value) + do (setf (arglist.keyword-args decoded-arglist) + (remove keyword (arglist.keyword-args decoded-arglist) + :key #'keyword-arg.keyword)))))) + decoded-arglist) + +(defun remove-given-args (decoded-arglist args) + ;; FIXME: We actually needa deep copy here. + (delete-given-args (copy-arglist decoded-arglist) args)) + +;;;; Arglist Retrieval + +(defun arglist-from-form (form) + (if (null form) + :not-available + (arglist-dispatch (car form) (cdr form)))) + +(export 'arglist-dispatch) +(defgeneric arglist-dispatch (operator arguments) + ;; Default method + (:method (operator arguments) + (unless (and (symbolp operator) (valid-operator-symbol-p operator)) + (return-from arglist-dispatch :not-available)) + (when (equalp (package-name (symbol-package operator)) "closer-mop") + (let ((standard-symbol (or (find-symbol (symbol-name operator) :cl) + (find-symbol (symbol-name operator) :swank-mop)))) + (when standard-symbol + (return-from arglist-dispatch + (arglist-dispatch standard-symbol arguments))))) + + (multiple-value-bind (decoded-arglist determining-args) + (compute-enriched-decoded-arglist operator arguments) + (with-available-arglist (arglist) decoded-arglist + ;; replace some formal args by determining actual args + (setf arglist (delete-given-args arglist determining-args)) + (setf (arglist.provided-args arglist) determining-args) + arglist)))) + +(defmethod arglist-dispatch ((operator (eql 'defmethod)) arguments) + (match (cons operator arguments) + (('defmethod (#'function-exists-p gf-name) . rest) + (let ((gf (fdefinition gf-name))) + (when (typep gf 'generic-function) + (with-available-arglist (arglist) (decode-arglist (arglist gf)) + (let ((qualifiers (loop for x in rest + until (or (listp x) (empty-arg-p x)) + collect x))) + (return-from arglist-dispatch + (make-arglist :provided-args (cons gf-name qualifiers) + :required-args (list arglist) + :rest "body" :body-p t))))))) + (_)) ; Fall through + (call-next-method)) + +(defmethod arglist-dispatch ((operator (eql 'define-compiler-macro)) arguments) + (match (cons operator arguments) + (('define-compiler-macro (#'function-exists-p gf-name) . _) + (let ((gf (fdefinition gf-name))) + (with-available-arglist (arglist) (decode-arglist (arglist gf)) + (return-from arglist-dispatch + (make-arglist :provided-args (list gf-name) + :required-args (list arglist) + :rest "body" :body-p t))))) + (_)) ; Fall through + (call-next-method)) + + +(defmethod arglist-dispatch ((operator (eql 'eval-when)) arguments) + (declare (ignore arguments)) + (let ((eval-when-args '(:compile-toplevel :load-toplevel :execute))) + (make-arglist + :required-args (list (make-arglist :any-p t :any-args eval-when-args)) + :rest '#:body :body-p t))) + + +(defmethod arglist-dispatch ((operator (eql 'declare)) arguments) + (let* ((declaration (cons operator (last arguments))) + (typedecl-arglist (arglist-for-type-declaration declaration))) + (if (arglist-available-p typedecl-arglist) + typedecl-arglist + (match declaration + (('declare ((#'consp typespec) . decl-args)) + (with-available-arglist (typespec-arglist) + (decoded-arglist-for-type-specifier typespec) + (make-arglist + :required-args (list (make-arglist + :required-args (list typespec-arglist) + :rest '#:variables))))) + (('declare (decl-identifier . decl-args)) + (decoded-arglist-for-declaration decl-identifier decl-args)) + (_ (make-arglist :rest '#:declaration-specifiers)))))) + +(defmethod arglist-dispatch ((operator (eql 'declaim)) arguments) + (arglist-dispatch 'declare arguments)) + + +(defun arglist-for-type-declaration (declaration) + (flet ((%arglist-for-type-declaration (identifier typespec rest-var-name) + (with-available-arglist (typespec-arglist) + (decoded-arglist-for-type-specifier typespec) + (make-arglist + :required-args (list (make-arglist + :provided-args (list identifier) + :required-args (list typespec-arglist) + :rest rest-var-name)))))) + (match declaration + (('declare ('type (#'consp typespec) . decl-args)) + (%arglist-for-type-declaration 'type typespec '#:variables)) + (('declare ('ftype (#'consp typespec) . decl-args)) + (%arglist-for-type-declaration 'ftype typespec '#:function-names)) + (('declare ((#'consp typespec) . decl-args)) + (with-available-arglist (typespec-arglist) + (decoded-arglist-for-type-specifier typespec) + (make-arglist + :required-args (list (make-arglist + :required-args (list typespec-arglist) + :rest '#:variables))))) + (_ :not-available)))) + +(defun decoded-arglist-for-declaration (decl-identifier decl-args) + (declare (ignore decl-args)) + (with-available-arglist (arglist) + (decode-arglist (declaration-arglist decl-identifier)) + (setf (arglist.provided-args arglist) (list decl-identifier)) + (make-arglist :required-args (list arglist)))) + +(defun decoded-arglist-for-type-specifier (type-specifier) + (etypecase type-specifier + (arglist-dummy :not-available) + (cons (decoded-arglist-for-type-specifier (car type-specifier))) + (symbol + (with-available-arglist (arglist) + (decode-arglist (type-specifier-arglist type-specifier)) + (setf (arglist.provided-args arglist) (list type-specifier)) + arglist)))) + +;;; Slimefuns + +;;; We work on a RAW-FORM, or BUFFER-FORM, which represent the form at +;;; user's point in Emacs. A RAW-FORM looks like +;;; +;;; ("FOO" ("BAR" ...) "QUUX" ("ZURP" SWANK::%CURSOR-MARKER%)) +;;; +;;; The expression before the cursor marker is the expression where +;;; user's cursor points at. An explicit marker is necessary to +;;; disambiguate between +;;; +;;; ("IF" ("PRED") +;;; ("F" "X" "Y" %CURSOR-MARKER%)) +;;; +;;; and +;;; ("IF" ("PRED") +;;; ("F" "X" "Y") %CURSOR-MARKER%) + +;;; Notice that for a form like (FOO (BAR |) QUUX), where | denotes +;;; user's point, the following should be sent ("FOO" ("BAR" "" +;;; %CURSOR-MARKER%)). Only the forms up to point should be +;;; considered. + +(defslimefun autodoc (raw-form &key print-right-margin) + "Return a list of two elements. +First, a string representing the arglist for the deepest subform in +RAW-FORM that does have an arglist. The highlighted parameter is +wrapped in ===> X <===. + +Second, a boolean value telling whether the returned string can be cached." + (handler-bind ((serious-condition + #'(lambda (c) + (unless (debug-on-swank-error) + (let ((*print-right-margin* print-right-margin)) + (return-from autodoc + (format nil "Arglist Error: \"~A\"" c))))))) + (with-buffer-syntax () + (multiple-value-bind (form arglist obj-at-cursor form-path) + (find-subform-with-arglist (parse-raw-form raw-form)) + (cond ((boundp-and-interesting obj-at-cursor) + (list (print-variable-to-string obj-at-cursor) nil)) + (t + (list + (with-available-arglist (arglist) arglist + (decoded-arglist-to-string + arglist + :print-right-margin print-right-margin + :operator (car form) + :highlight (form-path-to-arglist-path form-path + form + arglist))) + t))))))) + +(defun boundp-and-interesting (symbol) + (and symbol + (symbolp symbol) + (boundp symbol) + (not (memq symbol '(cl:t cl:nil))) + (not (keywordp symbol)))) + +(defun print-variable-to-string (symbol) + "Return a short description of VARIABLE-NAME, or NIL." + (let ((*print-pretty* t) (*print-level* 4) + (*print-length* 10) (*print-lines* 1) + (*print-readably* nil) + (value (symbol-value symbol))) + (call/truncated-output-to-string + 75 (lambda (s) + (without-printing-errors (:object value :stream s) + (format s "~A ~A~S" symbol *echo-area-prefix* value)))))) + + +(defslimefun complete-form (raw-form) + "Read FORM-STRING in the current buffer package, then complete it + by adding a template for the missing arguments." + ;; We do not catch errors here because COMPLETE-FORM is an + ;; interactive command, not automatically run in the background like + ;; ARGLIST-FOR-ECHO-AREA. + (with-buffer-syntax () + (multiple-value-bind (arglist provided-args) + (find-immediately-containing-arglist (parse-raw-form raw-form)) + (with-available-arglist (arglist) arglist + (decoded-arglist-to-template-string + (delete-given-args arglist + (remove-if #'empty-arg-p provided-args + :from-end t :count 1)) + :prefix "" :suffix ""))))) + +(defslimefun completions-for-keyword (keyword-string raw-form) + "Return a list of possible completions for KEYWORD-STRING relative +to the context provided by RAW-FORM." + (with-buffer-syntax () + (let ((arglist (find-immediately-containing-arglist + (parse-raw-form raw-form)))) + (when (arglist-available-p arglist) + ;; It would be possible to complete keywords only if we are in + ;; a keyword position, but it is not clear if we want that. + (let* ((keywords + (append (mapcar #'keyword-arg.keyword + (arglist.keyword-args arglist)) + (remove-if-not #'keywordp (arglist.any-args arglist)))) + (keyword-name + (tokenize-symbol keyword-string)) + (matching-keywords + (find-matching-symbols-in-list + keyword-name keywords (make-compound-prefix-matcher #\-))) + (converter (completion-output-symbol-converter keyword-string)) + (strings + (mapcar converter + (mapcar #'symbol-name matching-keywords))) + (completion-set + (format-completion-set strings nil ""))) + (list completion-set + (longest-compound-prefix completion-set))))))) + +(defparameter +cursor-marker+ '%cursor-marker%) + +(defun find-subform-with-arglist (form) + "Returns four values: + + The appropriate subform of `form' which is closest to the + +CURSOR-MARKER+ and whose operator is valid and has an + arglist. The +CURSOR-MARKER+ is removed from that subform. + + Second value is the arglist. Local function and macro definitions + appearing in `form' into account. + + Third value is the object in front of +CURSOR-MARKER+. + + Fourth value is a form path to that object." + (labels + ((yield-success (form local-ops) + (multiple-value-bind (form obj-at-cursor form-path) + (extract-cursor-marker form) + (values form + (let ((entry (assoc (car form) local-ops :test #'op=))) + (if entry + (decode-arglist (cdr entry)) + (arglist-from-form form))) + obj-at-cursor + form-path))) + (yield-failure () + (values nil :not-available)) + (operator-p (operator local-ops) + (or (and (symbolp operator) (valid-operator-symbol-p operator)) + (assoc operator local-ops :test #'op=))) + (op= (op1 op2) + (cond ((and (symbolp op1) (symbolp op2)) + (eq op1 op2)) + ((and (arglist-dummy-p op1) (arglist-dummy-p op2)) + (string= (arglist-dummy.string-representation op1) + (arglist-dummy.string-representation op2))))) + (grovel-form (form local-ops) + "Descend FORM top-down, always taking the rightest branch, + until +CURSOR-MARKER+." + (assert (listp form)) + (destructuring-bind (operator . args) form + ;; N.b. the user's cursor is at the rightmost, deepest + ;; subform right before +CURSOR-MARKER+. + (let ((last-subform (car (last form))) + (new-ops)) + (cond + ((eq last-subform +cursor-marker+) + (if (operator-p operator local-ops) + (yield-success form local-ops) + (yield-failure))) + ((not (operator-p operator local-ops)) + (grovel-form last-subform local-ops)) + ;; Make sure to pick up the arglists of local + ;; function/macro definitions. + ((setq new-ops (extract-local-op-arglists operator args)) + (multiple-value-or (grovel-form last-subform + (nconc new-ops local-ops)) + (yield-success form local-ops))) + ;; Some typespecs clash with function names, so we make + ;; sure to bail out early. + ((member operator '(cl:declare cl:declaim)) + (yield-success form local-ops)) + ;; Mostly uninteresting, hence skip. + ((memq operator '(cl:quote cl:function)) + (yield-failure)) + (t + (multiple-value-or (grovel-form last-subform local-ops) + (yield-success form local-ops)))))))) + (if (null form) + (yield-failure) + (grovel-form form '())))) + +(defun extract-cursor-marker (form) + "Returns three values: normalized `form' without +CURSOR-MARKER+, +the object in front of +CURSOR-MARKER+, and a form path to that +object." + (labels ((grovel (form last path) + (let ((result-form)) + (loop for (car . cdr) on form do + (cond ((eql car +cursor-marker+) + (decf (first path)) + (return-from grovel + (values (nreconc result-form cdr) + last + (nreverse path)))) + ((consp car) + (multiple-value-bind (new-car new-last new-path) + (grovel car last (cons 0 path)) + (when new-path ; CAR contained cursor-marker? + (return-from grovel + (values (nreconc + (cons new-car result-form) cdr) + new-last + new-path)))))) + (push car result-form) + (setq last car) + (incf (first path)) + finally + (return-from grovel + (values (nreverse result-form) nil nil)))))) + (grovel form nil (list 0)))) + +(defgeneric extract-local-op-arglists (operator args) + (:documentation + "If the form `(OPERATOR ,@ARGS) is a local operator binding form, + return a list of pairs (OP . ARGLIST) for each locally bound op.") + (:method (operator args) + (declare (ignore operator args)) + nil) + ;; FLET + (:method ((operator (eql 'cl:flet)) args) + (let ((defs (first args)) + (body (rest args))) + (cond ((null body) nil) ; `(flet ((foo (x) |' + ((atom defs) nil) ; `(flet ,foo (|' + (t (%collect-op/argl-alist defs))))) + ;; LABELS + (:method ((operator (eql 'cl:labels)) args) + ;; Notice that we only have information to "look backward" and + ;; show arglists of previously occuring local functions. + (destructuring-bind (defs . body) args + (unless (or (atom defs) (null body)) ; `(labels ,foo (|' + (let ((current-def (car (last defs)))) + (cond ((atom current-def) nil) ; `(labels ((foo (x) ...)|' + ((not (null body)) + (extract-local-op-arglists 'cl:flet args)) + (t + (let ((def.body (cddr current-def))) + (when def.body + (%collect-op/argl-alist defs))))))))) + ;; MACROLET + (:method ((operator (eql 'cl:macrolet)) args) + (extract-local-op-arglists 'cl:labels args))) + +(defun %collect-op/argl-alist (defs) + (setq defs (remove-if-not #'(lambda (x) + ;; Well-formed FLET/LABELS def? + (and (consp x) (second x))) + defs)) + (loop for (name arglist . nil) in defs + collect (cons name arglist))) + +(defun find-immediately-containing-arglist (form) + "Returns the arglist of the subform _immediately_ containing ++CURSOR-MARKER+ in `form'. Notice, however, that +CURSOR-MARKER+ may +be in a nested arglist \(e.g. `(WITH-OPEN-FILE ('\), and the +arglist of the appropriate parent form \(WITH-OPEN-FILE\) will be +returned in that case." + (flet ((try (form-path form arglist) + (let* ((arglist-path (form-path-to-arglist-path form-path + form + arglist)) + (argl (apply #'arglist-ref + arglist + arglist-path)) + (args (apply #'provided-arguments-ref + (cdr form) + arglist + arglist-path))) + (when (and (arglist-p argl) (listp args)) + (values argl args))))) + (multiple-value-bind (form arglist obj form-path) + (find-subform-with-arglist form) + (declare (ignore obj)) + (with-available-arglist (arglist) arglist + ;; First try the form the cursor is in (in case of a normal + ;; form), then try the surrounding form (in case of a nested + ;; macro form). + (multiple-value-or (try form-path form arglist) + (try (butlast form-path) form arglist) + :not-available))))) + +(defun form-path-to-arglist-path (form-path form arglist) + "Convert a form path to an arglist path consisting of arglist +indices." + (labels ((convert (path args arglist) + (if (null path) + nil + (let* ((idx (car path)) + (idx* (arglist-index idx args arglist)) + (arglist* (and idx* (arglist-ref arglist idx*))) + (args* (and idx* (provided-arguments-ref args + arglist + idx*)))) + ;; The FORM-PATH may be more detailed than ARGLIST; + ;; consider (defun foo (x y) ...), a form path may + ;; point into the function's lambda-list, but the + ;; arglist of DEFUN won't contain as much information. + ;; So we only recurse if possible. + (cond ((null idx*) + nil) + ((arglist-p arglist*) + (cons idx* (convert (cdr path) args* arglist*))) + (t + (list idx*))))))) + (convert + ;; FORM contains irrelevant operator. Adjust FORM-PATH. + (cond ((null form-path) nil) + ((equal form-path '(0)) nil) + (t + (destructuring-bind (car . cdr) form-path + (cons (1- car) cdr)))) + (cdr form) + arglist))) + +(defun arglist-index (provided-argument-index provided-arguments arglist) + "Return the arglist index into `arglist' for the parameter belonging +to the argument (NTH `provided-argument-index' `provided-arguments')." + (let ((positional-args# (positional-args-number arglist)) + (arg-index provided-argument-index)) + (with-struct (arglist. key-p rest) arglist + (cond + ((< arg-index positional-args#) ; required + optional + arg-index) + ((and (not key-p) (not rest)) ; more provided than allowed + nil) + ((not key-p) ; rest + body + (assert (arglist.rest arglist)) + positional-args#) + (t ; key + ;; Find last provided &key parameter + (let* ((argument (nth arg-index provided-arguments)) + (provided-keys (subseq provided-arguments positional-args#))) + (loop for (key value) on provided-keys by #'cddr + when (eq value argument) + return (match key + (('quote symbol) symbol) + (_ key))))))))) + +(defun arglist-ref (arglist &rest indices) + "Returns the parameter in ARGLIST along the INDICIES path. Numbers +represent positional parameters (required, optional), keywords +represent key parameters." + (flet ((ref-positional-arg (arglist index) + (check-type index (integer 0 *)) + (with-struct (arglist. provided-args required-args + optional-args rest) + arglist + (loop for args in (list provided-args required-args + (mapcar #'optional-arg.arg-name + optional-args)) + for args# = (length args) + if (< index args#) + return (nth index args) + else + do (decf index args#) + finally (return (or rest nil))))) + (ref-keyword-arg (arglist keyword) + ;; keyword argument may be any symbol, + ;; not only from the KEYWORD package. + (let ((keyword (match keyword + (('quote symbol) symbol) + (_ keyword)))) + (do-decoded-arglist arglist + (&key (kw arg) (when (eq kw keyword) + (return-from ref-keyword-arg arg))))) + nil)) + (dolist (index indices) + (assert (arglist-p arglist)) + (setq arglist (if (numberp index) + (ref-positional-arg arglist index) + (ref-keyword-arg arglist index)))) + arglist)) + +(defun provided-arguments-ref (provided-args arglist &rest indices) + "Returns the argument in PROVIDED-ARGUMENT along the INDICES path +relative to ARGLIST." + (check-type arglist arglist) + (flet ((ref (provided-args arglist index) + (if (numberp index) + (nth index provided-args) + (let ((provided-keys (subseq provided-args + (positional-args-number arglist)))) + (loop for (key value) on provided-keys + when (eq key index) + return value))))) + (dolist (idx indices) + (setq provided-args (ref provided-args arglist idx)) + (setq arglist (arglist-ref arglist idx))) + provided-args)) + +(defun positional-args-number (arglist) + (+ (length (arglist.provided-args arglist)) + (length (arglist.required-args arglist)) + (length (arglist.optional-args arglist)))) + +(defun parse-raw-form (raw-form) + "Parse a RAW-FORM into a Lisp form. I.e. substitute strings by +symbols if already interned. For strings not already interned, use +ARGLIST-DUMMY." + (unless (null raw-form) + (loop for element in raw-form + collect (etypecase element + (string (read-conversatively element)) + (list (parse-raw-form element)) + (symbol (prog1 element + ;; Comes after list, so ELEMENT can't be NIL. + (assert (eq element +cursor-marker+)))))))) + +(defun read-conversatively (string) + "Tries to find the symbol that's represented by STRING. + +If it can't, this either means that STRING does not represent a +symbol, or that the symbol behind STRING would have to be freshly +interned. Because this function is supposed to be called from the +automatic arglist display stuff from Slime, interning freshly +symbols is a big no-no. + +In such a case (that no symbol could be found), an object of type +ARGLIST-DUMMY is returned instead, which works as a placeholder +datum for subsequent logics to rely on." + (let* ((string (string-left-trim '(#\Space #\Tab #\Newline) string)) + (length (length string)) + (type (cond ((zerop length) nil) + ((eql (aref string 0) #\') + :quoted-symbol) + ((search "#'" string :end2 (min length 2)) + :sharpquoted-symbol) + ((char= (char string 0) (char string (1- length)) + #\") + :string) + (t + :symbol)))) + (multiple-value-bind (symbol found?) + (case type + (:symbol (parse-symbol string)) + (:quoted-symbol (parse-symbol (subseq string 1))) + (:sharpquoted-symbol (parse-symbol (subseq string 2))) + (:string (values string t)) + (t (values string nil))) + (if found? + (ecase type + (:symbol symbol) + (:quoted-symbol `(quote ,symbol)) + (:sharpquoted-symbol `(function ,symbol)) + (:string (if (> length 1) + (subseq string 1 (1- length)) + string))) + (make-arglist-dummy string))))) + +(defun test-print-arglist () + (flet ((test (arglist &rest strings) + (let* ((*package* (find-package :swank)) + (actual (decoded-arglist-to-string + (decode-arglist arglist) + :print-right-margin 1000))) + (unless (loop for string in strings + thereis (string= actual string)) + (warn "Test failed: ~S => ~S~% Expected: ~A" + arglist actual + (if (cdr strings) + (format nil "One of: ~{~S~^, ~}" strings) + (format nil "~S" (first strings)))))))) + (test '(function cons) "(function cons)") + (test '(quote cons) "(quote cons)") + (test '(&key (function #'+)) + "(&key (function #'+))" "(&key (function (function +)))") + (test '(&whole x y z) "(y z)") + (test '(x &aux y z) "(x)") + (test '(x &environment env y) "(x y)") + (test '(&key ((function f))) "(&key ((function ..)))") + (test + '(eval-when (&any :compile-toplevel :load-toplevel :execute) &body body) + "(eval-when (&any :compile-toplevel :load-toplevel :execute) &body body)") + (test '(declare (optimize &any (speed 1) (safety 1))) + "(declare (optimize &any (speed 1) (safety 1)))"))) + +(defun test-arglist-ref () + (macrolet ((soft-assert (form) + `(unless ,form + (warn "Assertion failed: ~S~%" ',form)))) + (let ((sample (decode-arglist '(x &key ((:k (y z))))))) + (soft-assert (eq (arglist-ref sample 0) 'x)) + (soft-assert (eq (arglist-ref sample :k 0) 'y)) + (soft-assert (eq (arglist-ref sample :k 1) 'z)) + + (soft-assert (eq (provided-arguments-ref '(a :k (b c)) sample 0) + 'a)) + (soft-assert (eq (provided-arguments-ref '(a :k (b c)) sample :k 0) + 'b)) + (soft-assert (eq (provided-arguments-ref '(a :k (b c)) sample :k 1) + 'c))))) + +(test-print-arglist) +(test-arglist-ref) + +(provide :swank-arglists) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-asdf.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-asdf.lisp new file mode 100644 index 0000000..0fdd901 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-asdf.lisp @@ -0,0 +1,541 @@ +;;; swank-asdf.lisp -- ASDF support +;; +;; Authors: Daniel Barlow +;; Marco Baringer +;; Edi Weitz +;; Francois-Rene Rideau +;; and others +;; License: Public Domain +;; + +(in-package :swank) + +(eval-when (:compile-toplevel :load-toplevel :execute) +;;; The best way to load ASDF is from an init file of an +;;; implementation. If ASDF is not loaded at the time swank-asdf is +;;; loaded, it will be tried first with (require "asdf"), if that +;;; doesn't help and *asdf-path* is set, it will be loaded from that +;;; file. +;;; To set *asdf-path* put the following into ~/.swank.lisp: +;;; (defparameter swank::*asdf-path* #p"/path/to/asdf/asdf.lisp") + (defvar *asdf-path* nil + "Path to asdf.lisp file, to be loaded in case (require \"asdf\") fails.")) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (unless (member :asdf *features*) + (ignore-errors (funcall 'require "asdf")))) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (unless (member :asdf *features*) + (handler-bind ((warning #'muffle-warning)) + (when *asdf-path* + (load *asdf-path* :if-does-not-exist nil))))) + +;; If still not found, error out. +(eval-when (:compile-toplevel :load-toplevel :execute) + (unless (member :asdf *features*) + (error "Could not load ASDF. +Please update your implementation or +install a recent release of ASDF and in your ~~/.swank.lisp specify: + (defparameter swank::*asdf-path* #p\"/path/containing/asdf/asdf.lisp\")"))) + +;;; If ASDF is too old, punt. +;; As of January 2014, Quicklisp has been providing 2.26 for a year +;; (and previously had 2.014.6 for over a year), whereas +;; all SLIME-supported implementations provide ASDF3 (i.e. 2.27 or later) +;; except LispWorks (stuck with 2.019) and SCL (which hasn't been released +;; in years and doesn't provide ASDF at all, but is fully supported by ASDF). +;; If your implementation doesn't provide ASDF, or provides an old one, +;; install an upgrade yourself and configure *asdf-path*. +;; It's just not worth the hassle supporting something +;; that doesn't even have COERCE-PATHNAME. +;; +;; NB: this version check is duplicated in swank-loader.lisp so that we don't +;; try to load this contrib when ASDF is too old since that will abort the SLIME +;; connection. +#-asdf3 +(eval-when (:compile-toplevel :load-toplevel :execute) + (unless (and #+asdf2 (asdf:version-satisfies (asdf:asdf-version) "2.14.6")) + (error "Your ASDF is too old. ~ + The oldest version supported by swank-asdf is 2.014.6."))) +;;; Import functionality from ASDF that isn't available in all ASDF versions. +;;; Please do NOT depend on any of the below as reference: +;;; they are sometimes stripped down versions, for compatibility only. +;;; Indeed, they are supposed to work on *OLDER*, not *NEWER* versions of ASDF. +;;; +;;; The way I got these is usually by looking at the current definition, +;;; using git blame in one screen to locate which commit last modified it, +;;; and git log in another to determine which release that made it in. +;;; It is OK for some of the below definitions to be or become obsolete, +;;; as long as it will make do with versions older than the tagged version: +;;; if ASDF is more recent, its more recent version will win. +;;; +;;; If your software is hacking ASDF, use its internals. +;;; If you want ASDF utilities in user software, please use ASDF-UTILS. + +(defun asdf-at-least (version) + (asdf:version-satisfies (asdf:asdf-version) version)) + +(defmacro asdefs (version &rest defs) + (flet ((defun* (version name aname rest) + `(progn + (defun ,name ,@rest) + (declaim (notinline ,name)) + (when (asdf-at-least ,version) + (setf (fdefinition ',name) (fdefinition ',aname))))) + (defmethod* (version aname rest) + `(unless (asdf-at-least ,version) + (defmethod ,aname ,@rest))) + (defvar* (name aname rest) + `(progn + (define-symbol-macro ,name ,aname) + (defvar ,aname ,@rest)))) + `(progn + ,@(loop :for (def name . args) :in defs + :for aname = (intern (string name) :asdf) + :collect + (ecase def + ((defun) (defun* version name aname args)) + ((defmethod) (defmethod* version aname args)) + ((defvar) (defvar* name aname args))))))) + +(asdefs "2.15" + (defvar *wild* #-cormanlisp :wild #+cormanlisp "*") + + (defun collect-asds-in-directory (directory collect) + (map () collect (directory-asd-files directory))) + + (defun register-asd-directory (directory &key recurse exclude collect) + (if (not recurse) + (collect-asds-in-directory directory collect) + (collect-sub*directories-asd-files + directory :exclude exclude :collect collect)))) + +(asdefs "2.16" + (defun load-sysdef (name pathname) + (declare (ignore name)) + (let ((package (asdf::make-temporary-package))) + (unwind-protect + (let ((*package* package) + (*default-pathname-defaults* + (asdf::pathname-directory-pathname + (translate-logical-pathname pathname)))) + (asdf::asdf-message + "~&; Loading system definition from ~A into ~A~%" ; + pathname package) + (load pathname)) + (delete-package package)))) + + (defun directory* (pathname-spec &rest keys &key &allow-other-keys) + (apply 'directory pathname-spec + (append keys + '#.(or #+allegro + '(:directories-are-files nil + :follow-symbolic-links nil) + #+clozure + '(:follow-links nil) + #+clisp + '(:circle t :if-does-not-exist :ignore) + #+(or cmu scl) + '(:follow-links nil :truenamep nil) + #+sbcl + (when (find-symbol "RESOLVE-SYMLINKS" '#:sb-impl) + '(:resolve-symlinks nil))))))) +(asdefs "2.17" + (defun collect-sub*directories-asd-files + (directory &key + (exclude asdf::*default-source-registry-exclusions*) + collect) + (asdf::collect-sub*directories + directory + (constantly t) + (lambda (x) (not (member (car (last (pathname-directory x))) + exclude :test #'equal))) + (lambda (dir) (collect-asds-in-directory dir collect)))) + + (defun system-source-directory (system-designator) + (asdf::pathname-directory-pathname + (asdf::system-source-file system-designator))) + + (defun filter-logical-directory-results (directory entries merger) + (if (typep directory 'logical-pathname) + (loop for f in entries + when + (if (typep f 'logical-pathname) + f + (let ((u (ignore-errors (funcall merger f)))) + (and u + (equal (ignore-errors (truename u)) + (truename f)) + u))) + collect it) + entries)) + + (defun directory-asd-files (directory) + (directory-files directory asdf::*wild-asd*))) + +(asdefs "2.19" + (defun subdirectories (directory) + (let* ((directory (asdf::ensure-directory-pathname directory)) + #-(or abcl cormanlisp xcl) + (wild (asdf::merge-pathnames* + #-(or abcl allegro cmu lispworks sbcl scl xcl) + asdf::*wild-directory* + #+(or abcl allegro cmu lispworks sbcl scl xcl) "*.*" + directory)) + (dirs + #-(or abcl cormanlisp xcl) + (ignore-errors + (directory* wild . #.(or #+clozure '(:directories t :files nil) + #+mcl '(:directories t)))) + #+(or abcl xcl) (system:list-directory directory) + #+cormanlisp (cl::directory-subdirs directory)) + #+(or abcl allegro cmu lispworks sbcl scl xcl) + (dirs (loop for x in dirs + for d = #+(or abcl xcl) (extensions:probe-directory x) + #+allegro (excl:probe-directory x) + #+(or cmu sbcl scl) (asdf::directory-pathname-p x) + #+lispworks (lw:file-directory-p x) + when d collect #+(or abcl allegro xcl) d + #+(or cmu lispworks sbcl scl) x))) + (filter-logical-directory-results + directory dirs + (let ((prefix (or (normalize-pathname-directory-component + (pathname-directory directory)) + ;; because allegro 8.x returns NIL for #p"FOO:" + '(:absolute)))) + (lambda (d) + (let ((dir (normalize-pathname-directory-component + (pathname-directory d)))) + (and (consp dir) (consp (cdr dir)) + (make-pathname + :defaults directory :name nil :type nil :version nil + :directory + (append prefix + (make-pathname-component-logical + (last dir)))))))))))) + +(asdefs "2.21" + (defun component-loaded-p (c) + (and (gethash 'load-op (asdf::component-operation-times + (asdf::find-component c nil))) t)) + + (defun normalize-pathname-directory-component (directory) + (cond + #-(or cmu sbcl scl) + ((stringp directory) `(:absolute ,directory) directory) + ((or (null directory) + (and (consp directory) + (member (first directory) '(:absolute :relative)))) + directory) + (t + (error "Unrecognized pathname directory component ~S" directory)))) + + (defun make-pathname-component-logical (x) + (typecase x + ((eql :unspecific) nil) + #+clisp (string (string-upcase x)) + #+clisp (cons (mapcar 'make-pathname-component-logical x)) + (t x))) + + (defun make-pathname-logical (pathname host) + (make-pathname + :host host + :directory (make-pathname-component-logical (pathname-directory pathname)) + :name (make-pathname-component-logical (pathname-name pathname)) + :type (make-pathname-component-logical (pathname-type pathname)) + :version (make-pathname-component-logical (pathname-version pathname))))) + +(asdefs "2.22" + (defun directory-files (directory &optional (pattern asdf::*wild-file*)) + (let ((dir (pathname directory))) + (when (typep dir 'logical-pathname) + (when (wild-pathname-p dir) + (error "Invalid wild pattern in logical directory ~S" directory)) + (unless (member (pathname-directory pattern) + '(() (:relative)) :test 'equal) + (error "Invalid file pattern ~S for logical directory ~S" + pattern directory)) + (setf pattern (make-pathname-logical pattern (pathname-host dir)))) + (let ((entries (ignore-errors + (directory* (asdf::merge-pathnames* pattern dir))))) + (filter-logical-directory-results + directory entries + (lambda (f) + (make-pathname :defaults dir + :name (make-pathname-component-logical + (pathname-name f)) + :type (make-pathname-component-logical + (pathname-type f)) + :version (make-pathname-component-logical + (pathname-version f))))))))) + +(asdefs "2.26.149" + (defmethod component-relative-pathname ((system asdf:system)) + (asdf::coerce-pathname + (and (slot-boundp system 'asdf::relative-pathname) + (slot-value system 'asdf::relative-pathname)) + :type :directory + :defaults (system-source-directory system))) + (defun load-asd (pathname &key name &allow-other-keys) + (asdf::load-sysdef (or name (string-downcase (pathname-name pathname))) + pathname))) + + +;;; Taken from ASDF 1.628 +(defmacro while-collecting ((&rest collectors) &body body) + `(asdf::while-collecting ,collectors ,@body)) + +;;; Now for SLIME-specific stuff + +(defun asdf-operation (operation) + (or (asdf::find-symbol* operation :asdf) + (error "Couldn't find ASDF operation ~S" operation))) + +(defun map-system-components (fn system) + (map-component-subcomponents fn (asdf:find-system system))) + +(defun map-component-subcomponents (fn component) + (when component + (funcall fn component) + (when (typep component 'asdf:module) + (dolist (c (asdf:module-components component)) + (map-component-subcomponents fn c))))) + +;;; Maintaining a pathname to component table + +(defvar *pathname-component* (make-hash-table :test 'equal)) + +(defun clear-pathname-component-table () + (clrhash *pathname-component*)) + +(defun register-system-pathnames (system) + (map-system-components 'register-component-pathname system)) + +(defun recompute-pathname-component-table () + (clear-pathname-component-table) + (asdf::map-systems 'register-system-pathnames)) + +(defun pathname-component (x) + (gethash (pathname x) *pathname-component*)) + +(defmethod asdf:component-pathname :around ((component asdf:component)) + (let ((p (call-next-method))) + (when (pathnamep p) + (setf (gethash p *pathname-component*) component)) + p)) + +(defun register-component-pathname (component) + (asdf:component-pathname component)) + +(recompute-pathname-component-table) + +;;; This is a crude hack, see ASDF's LP #481187. +(defslimefun who-depends-on (system) + (flet ((system-dependencies (op system) + (mapcar (lambda (dep) + (asdf::coerce-name (if (consp dep) (second dep) dep))) + (cdr (assoc op (asdf:component-depends-on op system)))))) + (let ((system-name (asdf::coerce-name system)) + (result)) + (asdf::map-systems + (lambda (system) + (when (member system-name + (system-dependencies 'asdf:load-op system) + :test #'string=) + (push (asdf:component-name system) result)))) + result))) + +(defmethod xref-doit ((type (eql :depends-on)) thing) + (when (typep thing '(or string symbol)) + (loop for dependency in (who-depends-on thing) + for asd-file = (asdf:system-definition-pathname dependency) + when asd-file + collect (list dependency + (swank/backend:make-location + `(:file ,(namestring asd-file)) + `(:position 1) + `(:snippet ,(format nil "(defsystem :~A" dependency) + :align t)))))) + +(defslimefun operate-on-system-for-emacs (system-name operation &rest keywords) + "Compile and load SYSTEM using ASDF. +Record compiler notes signalled as `compiler-condition's." + (collect-notes + (lambda () + (apply #'operate-on-system system-name operation keywords)))) + +(defun operate-on-system (system-name operation-name &rest keyword-args) + "Perform OPERATION-NAME on SYSTEM-NAME using ASDF. +The KEYWORD-ARGS are passed on to the operation. +Example: +\(operate-on-system \"cl-ppcre\" 'compile-op :force t)" + (handler-case + (with-compilation-hooks () + (apply #'asdf:operate (asdf-operation operation-name) + system-name keyword-args) + t) + ((or asdf:compile-error #+asdf3 asdf/lisp-build:compile-file-error) + () nil))) + +(defun unique-string-list (&rest lists) + (sort (delete-duplicates (apply #'append lists) :test #'string=) #'string<)) + +(defslimefun list-all-systems-in-central-registry () + "Returns a list of all systems in ASDF's central registry +AND in its source-registry. (legacy name)" + (unique-string-list + (mapcar + #'pathname-name + (while-collecting (c) + (loop for dir in asdf:*central-registry* + for defaults = (eval dir) + when defaults + do (collect-asds-in-directory defaults #'c)) + (asdf:ensure-source-registry) + (if (or #+asdf3 t + #-asdf3 (asdf:version-satisfies (asdf:asdf-version) "2.15")) + (loop :for k :being :the :hash-keys :of asdf::*source-registry* + :do (c k)) + #-asdf3 + (dolist (entry (asdf::flatten-source-registry)) + (destructuring-bind (directory &key recurse exclude) entry + (register-asd-directory + directory + :recurse recurse :exclude exclude :collect #'c)))))))) + +(defslimefun list-all-systems-known-to-asdf () + "Returns a list of all systems ASDF knows already." + (while-collecting (c) + (asdf::map-systems (lambda (system) (c (asdf:component-name system)))))) + +(defslimefun list-asdf-systems () + "Returns the systems in ASDF's central registry and those which ASDF +already knows." + (unique-string-list + (list-all-systems-known-to-asdf) + (list-all-systems-in-central-registry))) + +(defun asdf-component-source-files (component) + (while-collecting (c) + (labels ((f (x) + (typecase x + (asdf:source-file (c (asdf:component-pathname x))) + (asdf:module (map () #'f (asdf:module-components x)))))) + (f component)))) + +(defun make-operation (x) + #+#.(swank/backend:with-symbol 'make-operation 'asdf) + (asdf:make-operation x) + #-#.(swank/backend:with-symbol 'make-operation 'asdf) + (make-instance x)) + +(defun asdf-component-output-files (component) + (while-collecting (c) + (labels ((f (x) + (typecase x + (asdf:source-file + (map () #'c + (asdf:output-files (make-operation 'asdf:compile-op) x))) + (asdf:module (map () #'f (asdf:module-components x)))))) + (f component)))) + +(defslimefun asdf-system-files (name) + (let* ((system (asdf:find-system name)) + (files (mapcar #'namestring + (cons + (asdf:system-definition-pathname system) + (asdf-component-source-files system)))) + (main-file (find name files + :test #'equalp :key #'pathname-name :start 1))) + (if main-file + (cons main-file (remove main-file files + :test #'equal :count 1)) + files))) + +(defslimefun asdf-system-loaded-p (name) + (component-loaded-p name)) + +(defslimefun asdf-system-directory (name) + (namestring (translate-logical-pathname (asdf:system-source-directory name)))) + +(defun pathname-system (pathname) + (let ((component (pathname-component pathname))) + (when component + (asdf:component-name (asdf:component-system component))))) + +(defslimefun asdf-determine-system (file buffer-package-name) + (or + (and file + (pathname-system file)) + (and file + (progn + ;; If not found, let's rebuild the table first + (recompute-pathname-component-table) + (pathname-system file))) + ;; If we couldn't find an already defined system, + ;; try finding a system that's named like BUFFER-PACKAGE-NAME. + (loop with package = (guess-buffer-package buffer-package-name) + for name in (package-names package) + for system = (asdf:find-system (asdf::coerce-name name) nil) + when (and system + (or (not file) + (pathname-system file))) + return (asdf:component-name system)))) + +(defslimefun delete-system-fasls (name) + (let ((removed-count + (loop for file in (asdf-component-output-files + (asdf:find-system name)) + when (probe-file file) + count it + and + do (delete-file file)))) + (format nil "~d file~:p ~:*~[were~;was~:;were~] removed" removed-count))) + +(defvar *recompile-system* nil) + +(defmethod asdf:operation-done-p :around + ((operation asdf:compile-op) + component) + (unless (eql *recompile-system* + (asdf:component-system component)) + (call-next-method))) + +(defslimefun reload-system (name) + (let ((*recompile-system* (asdf:find-system name))) + (operate-on-system-for-emacs name 'asdf:load-op))) + +;; Doing list-all-systems-in-central-registry might be quite slow +;; since it accesses a file-system, so run it once at the background +;; to initialize caches. +(when (eql *communication-style* :spawn) + (spawn (lambda () + (ignore-errors (list-all-systems-in-central-registry))) + :name "init-asdf-fs-caches")) + +;;; Hook for compile-file-for-emacs + +(defun try-compile-file-with-asdf (pathname load-p &rest options) + (declare (ignore options)) + (let ((component (pathname-component pathname))) + (when component + ;;(format t "~&Compiling ASDF component ~S~%" component) + (let ((op (make-operation 'asdf:compile-op))) + (with-compilation-hooks () + (asdf:perform op component)) + (when load-p + (asdf:perform (make-operation 'asdf:load-op) component)) + (values t t nil (first (asdf:output-files op component))))))) + +(defun try-compile-asd-file (pathname load-p &rest options) + (declare (ignore load-p options)) + (when (equalp (pathname-type pathname) "asd") + (load-asd pathname) + (values t t nil pathname))) + +(pushnew 'try-compile-asd-file *compile-file-for-emacs-hook*) + +;;; (pushnew 'try-compile-file-with-asdf *compile-file-for-emacs-hook*) + +(provide :swank-asdf) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-buffer-streams.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-buffer-streams.lisp new file mode 100644 index 0000000..4d901e2 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-buffer-streams.lisp @@ -0,0 +1,39 @@ +;;; swank-buffer-streams.lisp --- Streams that output to a buffer +;;; +;;; Authors: Ed Langley +;;; +;;; License: This code has been placed in the Public Domain. All warranties +;;; are disclaimed. + +(in-package :swank) + +(defpackage :swank-buffer-streams + (:use :cl) + (:import-from :swank + defslimefun + add-hook + encode-message + send-event + find-thread + dcase + current-socket-io + send-to-emacs + current-thread-id + wait-for-event + + *emacs-connection* + *event-hook*) + (:export make-buffer-output-stream)) + +(in-package :swank-buffer-streams) + +(defun get-temporary-identifier () + (intern (symbol-name (gensym "BUFFER")) + :keyword)) + +(defun make-buffer-output-stream (&optional (target-identifier (get-temporary-identifier))) + (swank:ed-rpc '#:slime-make-buffer-stream-target (current-thread-id) target-identifier) + (values (swank:make-output-stream-for-target *emacs-connection* target-identifier) + target-identifier)) + +(provide :swank-buffer-streams) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-c-p-c.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-c-p-c.lisp new file mode 100644 index 0000000..6a766fb --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-c-p-c.lisp @@ -0,0 +1,298 @@ +;;; swank-c-p-c.lisp -- ILISP style Compound Prefix Completion +;; +;; Author: Luke Gorrie +;; Edi Weitz +;; Matthias Koeppe +;; Tobias C. Rittweiler +;; and others +;; +;; License: Public Domain +;; + + +(in-package :swank) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (swank-require :swank-util)) + +(defslimefun completions (string default-package-name) + "Return a list of completions for a symbol designator STRING. + +The result is the list (COMPLETION-SET COMPLETED-PREFIX), where +COMPLETION-SET is the list of all matching completions, and +COMPLETED-PREFIX is the best (partial) completion of the input +string. + +Simple compound matching is supported on a per-hyphen basis: + + (completions \"m-v-\" \"COMMON-LISP\") + ==> ((\"multiple-value-bind\" \"multiple-value-call\" + \"multiple-value-list\" \"multiple-value-prog1\" + \"multiple-value-setq\" \"multiple-values-limit\") + \"multiple-value\") + +\(For more advanced compound matching, see FUZZY-COMPLETIONS.) + +If STRING is package qualified the result list will also be +qualified. If string is non-qualified the result strings are +also not qualified and are considered relative to +DEFAULT-PACKAGE-NAME. + +The way symbols are matched depends on the symbol designator's +format. The cases are as follows: + FOO - Symbols with matching prefix and accessible in the buffer package. + PKG:FOO - Symbols with matching prefix and external in package PKG. + PKG::FOO - Symbols with matching prefix and accessible in package PKG. +" + (multiple-value-bind (name package-name package internal-p) + (parse-completion-arguments string default-package-name) + (let* ((symbol-set (symbol-completion-set + name package-name package internal-p + (make-compound-prefix-matcher #\-))) + (package-set (package-completion-set + name package-name package internal-p + (make-compound-prefix-matcher '(#\. #\-)))) + (completion-set + (format-completion-set (nconc symbol-set package-set) + internal-p package-name))) + (when completion-set + (list completion-set (longest-compound-prefix completion-set)))))) + + +;;;;; Find completion set + +(defun symbol-completion-set (name package-name package internal-p matchp) + "Return the set of completion-candidates as strings." + (mapcar (completion-output-symbol-converter name) + (and package + (mapcar #'symbol-name + (find-matching-symbols name + package + (and (not internal-p) + package-name) + matchp))))) + +(defun package-completion-set (name package-name package internal-p matchp) + (declare (ignore package internal-p)) + (mapcar (completion-output-package-converter name) + (and (not package-name) + (find-matching-packages name matchp)))) + +(defun find-matching-symbols (string package external test) + "Return a list of symbols in PACKAGE matching STRING. +TEST is called with two strings. If EXTERNAL is true, only external +symbols are returned." + (let ((completions '()) + (converter (completion-output-symbol-converter string))) + (flet ((symbol-matches-p (symbol) + (and (or (not external) + (symbol-external-p symbol package)) + (funcall test string + (funcall converter (symbol-name symbol)))))) + (do-symbols* (symbol package) + (when (symbol-matches-p symbol) + (push symbol completions)))) + completions)) + +(defun find-matching-symbols-in-list (string list test) + "Return a list of symbols in LIST matching STRING. +TEST is called with two strings." + (let ((completions '()) + (converter (completion-output-symbol-converter string))) + (flet ((symbol-matches-p (symbol) + (funcall test string + (funcall converter (symbol-name symbol))))) + (dolist (symbol list) + (when (symbol-matches-p symbol) + (push symbol completions)))) + (remove-duplicates completions))) + +(defun find-matching-packages (name matcher) + "Return a list of package names matching NAME with MATCHER. +MATCHER is a two-argument predicate." + (let ((converter (completion-output-package-converter name))) + (remove-if-not (lambda (x) + (funcall matcher name (funcall converter x))) + (mapcar (lambda (pkgname) + (concatenate 'string pkgname ":")) + (loop for package in (list-all-packages) + nconcing (package-names package)))))) + + +;; PARSE-COMPLETION-ARGUMENTS return table: +;; +;; user behaviour | NAME | PACKAGE-NAME | PACKAGE +;; ----------------+--------+--------------+----------------------------------- +;; asdf [tab] | "asdf" | NIL | # +;; | | | or *BUFFER-PACKAGE* +;; asdf: [tab] | "" | "asdf" | # +;; | | | +;; asdf:foo [tab] | "foo" | "asdf" | # +;; | | | +;; as:fo [tab] | "fo" | "as" | NIL +;; | | | +;; : [tab] | "" | "" | # +;; | | | +;; :foo [tab] | "foo" | "" | # +;; +(defun parse-completion-arguments (string default-package-name) + "Parse STRING as a symbol designator. +Return these values: + SYMBOL-NAME + PACKAGE-NAME, or nil if the designator does not include an explicit package. + PACKAGE, generally the package to complete in. (However, if PACKAGE-NAME is + NIL, return the respective package of DEFAULT-PACKAGE-NAME instead; + if PACKAGE is non-NIL but a package cannot be found under that name, + return NIL.) + INTERNAL-P, if the symbol is qualified with `::'." + (multiple-value-bind (name package-name internal-p) + (tokenize-symbol string) + (flet ((default-package () + (or (guess-package default-package-name) *buffer-package*))) + (let ((package (cond + ((not package-name) + (default-package)) + ((equal package-name "") + (guess-package (symbol-name :keyword))) + ((find-locally-nicknamed-package + package-name (default-package))) + (t + (guess-package package-name))))) + (values name package-name package internal-p))))) + +(defun completion-output-case-converter (input &optional with-escaping-p) + "Return a function to convert strings for the completion output. +INPUT is used to guess the preferred case." + (ecase (readtable-case *readtable*) + (:upcase (cond ((or with-escaping-p + (and (plusp (length input)) + (not (some #'lower-case-p input)))) + #'identity) + (t #'string-downcase))) + (:invert (lambda (output) + (multiple-value-bind (lower upper) (determine-case output) + (cond ((and lower upper) output) + (lower (string-upcase output)) + (upper (string-downcase output)) + (t output))))) + (:downcase (cond ((or with-escaping-p + (and (zerop (length input)) + (not (some #'upper-case-p input)))) + #'identity) + (t #'string-upcase))) + (:preserve #'identity))) + +(defun completion-output-package-converter (input) + "Return a function to convert strings for the completion output. +INPUT is used to guess the preferred case." + (completion-output-case-converter input)) + +(defun completion-output-symbol-converter (input) + "Return a function to convert strings for the completion output. +INPUT is used to guess the preferred case. Escape symbols when needed." + (let ((case-converter (completion-output-case-converter input)) + (case-converter-with-escaping (completion-output-case-converter input t))) + (lambda (str) + (if (or (multiple-value-bind (lowercase uppercase) + (determine-case str) + ;; In these readtable cases, symbols with letters from + ;; the wrong case need escaping + (case (readtable-case *readtable*) + (:upcase lowercase) + (:downcase uppercase) + (t nil))) + (some (lambda (el) + (or (member el '(#\: #\Space #\Newline #\Tab)) + (multiple-value-bind (macrofun nonterminating) + (get-macro-character el) + (and macrofun + (not nonterminating))))) + str)) + (concatenate 'string "|" (funcall case-converter-with-escaping str) "|") + (funcall case-converter str))))) + + +(defun determine-case (string) + "Return two booleans LOWER and UPPER indicating whether STRING +contains lower or upper case characters." + (values (some #'lower-case-p string) + (some #'upper-case-p string))) + + +;;;;; Compound-prefix matching + +(defun make-compound-prefix-matcher (delimiter &key (test #'char=)) + "Returns a matching function that takes a `prefix' and a +`target' string and which returns T if `prefix' is a +compound-prefix of `target', and otherwise NIL. + +Viewing each of `prefix' and `target' as a series of substrings +delimited by DELIMITER, if each substring of `prefix' is a prefix +of the corresponding substring in `target' then we call `prefix' +a compound-prefix of `target'. + +DELIMITER may be a character, or a list of characters." + (let ((delimiters (etypecase delimiter + (character (list delimiter)) + (cons (assert (every #'characterp delimiter)) + delimiter)))) + (lambda (prefix target) + (declare (type simple-string prefix target)) + (loop with tpos = 0 + for ch across prefix + always (and (< tpos (length target)) + (let ((delimiter (car (member ch delimiters :test test)))) + (if delimiter + (setf tpos (position delimiter target :start tpos)) + (funcall test ch (aref target tpos))))) + do (incf tpos))))) + + +;;;;; Extending the input string by completion + +(defun longest-compound-prefix (completions &optional (delimiter #\-)) + "Return the longest compound _prefix_ for all COMPLETIONS." + (flet ((tokenizer (string) (tokenize-completion string delimiter))) + (untokenize-completion + (loop for token-list in (transpose-lists (mapcar #'tokenizer completions)) + if (notevery #'string= token-list (rest token-list)) + ;; Note that we possibly collect the "" here as well, so that + ;; UNTOKENIZE-COMPLETION will append a delimiter for us. + collect (longest-common-prefix token-list) + and do (loop-finish) + else collect (first token-list)) + delimiter))) + +(defun tokenize-completion (string delimiter) + "Return all substrings of STRING delimited by DELIMITER." + (loop with end + for start = 0 then (1+ end) + until (> start (length string)) + do (setq end (or (position delimiter string :start start) (length string))) + collect (subseq string start end))) + +(defun untokenize-completion (tokens &optional (delimiter #\-)) + (format nil (format nil "~~{~~A~~^~a~~}" delimiter) tokens)) + +(defun transpose-lists (lists) + "Turn a list-of-lists on its side. +If the rows are of unequal length, truncate uniformly to the shortest. + +For example: +\(transpose-lists '((ONE TWO THREE) (1 2))) + => ((ONE 1) (TWO 2))" + (cond ((null lists) '()) + ((some #'null lists) '()) + (t (cons (mapcar #'car lists) + (transpose-lists (mapcar #'cdr lists)))))) + + +;;;; Completion for character names + +(defslimefun completions-for-character (prefix) + (let* ((matcher (make-compound-prefix-matcher #\_ :test #'char-equal)) + (completion-set (character-completion-set prefix matcher)) + (completions (sort completion-set #'string<))) + (list completions (longest-compound-prefix completions #\_)))) + +(provide :swank-c-p-c) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-clipboard.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-clipboard.lisp new file mode 100644 index 0000000..52b1085 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-clipboard.lisp @@ -0,0 +1,71 @@ +;;; swank-clipboard.lisp --- Object clipboard +;; +;; Written by Helmut Eller in 2008. +;; License: Public Domain + +(defpackage :swank-clipboard + (:use :cl) + (:import-from :swank :defslimefun :with-buffer-syntax :dcase) + (:export :add :delete-entry :entries :entry-to-ref :ref)) + +(in-package :swank-clipboard) + +(defstruct clipboard entries (counter 0)) + +(defvar *clipboard* (make-clipboard)) + +(defslimefun add (datum) + (let ((value (dcase datum + ((:string string package) + (with-buffer-syntax (package) + (eval (read-from-string string)))) + ((:inspector part) + (swank:inspector-nth-part part)) + ((:sldb frame var) + (swank/backend:frame-var-value frame var))))) + (clipboard-add value) + (format nil "Added: ~a" + (entry-to-string (1- (length (clipboard-entries *clipboard*))))))) + +(defslimefun entries () + (loop for (ref . value) in (clipboard-entries *clipboard*) + collect `(,ref . ,(to-line value)))) + +(defslimefun delete-entry (entry) + (let ((msg (format nil "Deleted: ~a" (entry-to-string entry)))) + (clipboard-delete-entry entry) + msg)) + +(defslimefun entry-to-ref (entry) + (destructuring-bind (ref . value) (clipboard-entry entry) + (list ref (to-line value 5)))) + +(defun clipboard-add (value) + (setf (clipboard-entries *clipboard*) + (append (clipboard-entries *clipboard*) + (list (cons (incf (clipboard-counter *clipboard*)) + value))))) + +(defun clipboard-ref (ref) + (let ((tail (member ref (clipboard-entries *clipboard*) :key #'car))) + (cond (tail (cdr (car tail))) + (t (error "Invalid clipboard ref: ~s" ref))))) + +(defun clipboard-entry (entry) + (elt (clipboard-entries *clipboard*) entry)) + +(defun clipboard-delete-entry (index) + (let* ((list (clipboard-entries *clipboard*)) + (tail (nthcdr index list))) + (setf (clipboard-entries *clipboard*) + (append (ldiff list tail) (cdr tail))))) + +(defun entry-to-string (entry) + (destructuring-bind (ref . value) (clipboard-entry entry) + (format nil "#@~d(~a)" ref (to-line value)))) + +(defun to-line (object &optional (width 75)) + (with-output-to-string (*standard-output*) + (write object :right-margin width :lines 1))) + +(provide :swank-clipboard) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-fancy-inspector.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-fancy-inspector.lisp new file mode 100644 index 0000000..c2201a8 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-fancy-inspector.lisp @@ -0,0 +1,1006 @@ +;;; swank-fancy-inspector.lisp --- Fancy inspector for CLOS objects +;; +;; Author: Marco Baringer and others +;; License: Public Domain +;; + +(in-package :swank) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (swank-require :swank-util)) + +(defmethod emacs-inspect ((symbol symbol)) + (let ((package (symbol-package symbol))) + (multiple-value-bind (_symbol status) + (and package (find-symbol (string symbol) package)) + (declare (ignore _symbol)) + (append + (label-value-line "Its name is" (symbol-name symbol)) + ;; + ;; Value + (cond ((boundp symbol) + (append + (label-value-line (if (constantp symbol) + "It is a constant of value" + "It is a global variable bound to") + (symbol-value symbol) :newline nil) + ;; unbinding constants might be not a good idea, but + ;; implementations usually provide a restart. + `(" " (:action "[unbind]" + ,(lambda () (makunbound symbol)))) + '((:newline)))) + (t '("It is unbound." (:newline)))) + (docstring-ispec "Documentation" symbol 'variable) + (multiple-value-bind (expansion definedp) (macroexpand symbol) + (if definedp + (label-value-line "It is a symbol macro with expansion" + expansion))) + ;; + ;; Function + (if (fboundp symbol) + (append (if (macro-function symbol) + `("It a macro with macro-function: " + (:value ,(macro-function symbol))) + `("It is a function: " + (:value ,(symbol-function symbol)))) + `(" " (:action "[unbind]" + ,(lambda () (fmakunbound symbol)))) + `((:newline))) + `("It has no function value." (:newline))) + (docstring-ispec "Function documentation" symbol 'function) + (when (compiler-macro-function symbol) + (append + (label-value-line "It also names the compiler macro" + (compiler-macro-function symbol) :newline nil) + `(" " (:action "[remove]" + ,(lambda () + (setf (compiler-macro-function symbol) nil))) + (:newline)))) + (docstring-ispec "Compiler macro documentation" + symbol 'compiler-macro) + ;; + ;; Package + (if package + `("It is " ,(string-downcase (string status)) + " to the package: " + (:value ,package ,(package-name package)) + ,@(if (eq :internal status) + `(" " + (:action "[export]" + ,(lambda () (export symbol package))))) + " " + (:action "[unintern]" + ,(lambda () (unintern symbol package))) + (:newline)) + '("It is a non-interned symbol." (:newline))) + ;; + ;; Plist + (label-value-line "Property list" (symbol-plist symbol)) + ;; + ;; Class + (if (find-class symbol nil) + `("It names the class " + (:value ,(find-class symbol) ,(string symbol)) + " " + (:action "[remove]" + ,(lambda () (setf (find-class symbol) nil))) + (:newline))) + ;; + ;; More package + (if (find-package symbol) + (label-value-line "It names the package" (find-package symbol))) + (inspect-type-specifier symbol))))) + +#-sbcl +(defun inspect-type-specifier (symbol) + (declare (ignore symbol))) + +#+sbcl +(defun inspect-type-specifier (symbol) + (let* ((kind (sb-int:info :type :kind symbol)) + (fun (case kind + (:defined + (or (sb-int:info :type :expander symbol) t)) + (:primitive + (or #.(if (swank/sbcl::sbcl-version>= 1 3 1) + '(let ((x (sb-int:info :type :expander symbol))) + (if (consp x) + (car x) + x)) + '(sb-int:info :type :translator symbol)) + t))))) + (when fun + (append + (list + (format nil "It names a ~@[primitive~* ~]type-specifier." + (eq kind :primitive)) + '(:newline)) + (docstring-ispec "Type-specifier documentation" symbol 'type) + (unless (eq t fun) + (let ((arglist (arglist fun))) + (append + `("Type-specifier lambda-list: " + ;; Could use ~:s, but inspector-princ does a bit more, + ;; and not all NILs in the arglist should be printed that way. + ,(if arglist + (inspector-princ arglist) + "()") + (:newline)) + (multiple-value-bind (expansion ok) + (handler-case (sb-ext:typexpand-1 symbol) + (error () (values nil nil))) + (when ok + (list "Type-specifier expansion: " + (princ-to-string expansion))))))))))) + +(defun docstring-ispec (label object kind) + "Return a inspector spec if OBJECT has a docstring of kind KIND." + (let ((docstring (documentation object kind))) + (cond ((not docstring) nil) + ((< (+ (length label) (length docstring)) + 75) + (list label ": " docstring '(:newline))) + (t + (list label ":" '(:newline) " " docstring '(:newline)))))) + +(unless (find-method #'emacs-inspect '() (list (find-class 'function)) nil) + (defmethod emacs-inspect ((f function)) + (inspect-function f))) + +(defun inspect-function (f) + (append + (label-value-line "Name" (function-name f)) + `("Its argument list is: " + ,(inspector-princ (arglist f)) (:newline)) + (docstring-ispec "Documentation" f t) + (if (function-lambda-expression f) + (label-value-line "Lambda Expression" + (function-lambda-expression f))))) + +(defun method-specializers-for-inspect (method) + "Return a \"pretty\" list of the method's specializers. Normal + specializers are replaced by the name of the class, eql + specializers are replaced by `(eql ,object)." + (mapcar (lambda (spec) + (typecase spec + (swank-mop:eql-specializer + `(eql ,(swank-mop:eql-specializer-object spec))) + #-sbcl + (t + (swank-mop:class-name spec)) + #+sbcl + (t + ;; SBCL has extended specializers + (let ((gf (sb-mop:method-generic-function method))) + (cond (gf + (sb-pcl:unparse-specializer-using-class gf spec)) + ((typep spec 'class) + (class-name spec)) + (t + spec)))))) + (swank-mop:method-specializers method))) + +(defun method-for-inspect-value (method) + "Returns a \"pretty\" list describing METHOD. The first element + of the list is the name of generic-function method is + specialiazed on, the second element is the method qualifiers, + the rest of the list is the method's specialiazers (as per + method-specializers-for-inspect)." + (append (list (swank-mop:generic-function-name + (swank-mop:method-generic-function method))) + (swank-mop:method-qualifiers method) + (method-specializers-for-inspect method))) + +(defmethod emacs-inspect ((object standard-object)) + (let ((class (class-of object))) + `("Class: " (:value ,class) (:newline) + ,@(all-slots-for-inspector object)))) + +(defvar *gf-method-getter* 'methods-by-applicability + "This function is called to get the methods of a generic function. +The default returns the method sorted by applicability. +See `methods-by-applicability'.") + +(defun specializer< (specializer1 specializer2) + "Return true if SPECIALIZER1 is more specific than SPECIALIZER2." + (let ((s1 specializer1) (s2 specializer2) ) + (cond ((typep s1 'swank-mop:eql-specializer) + (not (typep s2 'swank-mop:eql-specializer))) + ((typep s1 'class) + (flet ((cpl (class) + (and (swank-mop:class-finalized-p class) + (swank-mop:class-precedence-list class)))) + (member s2 (cpl s1))))))) + +(defun methods-by-applicability (gf) + "Return methods ordered by most specific argument types. + +`method-specializer<' is used for sorting." + ;; FIXME: argument-precedence-order and qualifiers are ignored. + (labels ((method< (meth1 meth2) + (loop for s1 in (swank-mop:method-specializers meth1) + for s2 in (swank-mop:method-specializers meth2) + do (cond ((specializer< s2 s1) (return nil)) + ((specializer< s1 s2) (return t)))))) + (stable-sort (copy-seq (swank-mop:generic-function-methods gf)) + #'method<))) + +(defun abbrev-doc (doc &optional (maxlen 80)) + "Return the first sentence of DOC, but not more than MAXLAN characters." + (subseq doc 0 (min (1+ (or (position #\. doc) (1- maxlen))) + maxlen + (length doc)))) + +(defstruct (inspector-checklist (:conc-name checklist.) + (:constructor %make-checklist (buttons))) + (buttons nil :type (or null simple-vector)) + (count 0)) + +(defun make-checklist (n) + (%make-checklist (make-array n :initial-element nil))) + +(defun reinitialize-checklist (checklist) + ;; Along this counter the buttons are created, so we have to + ;; initialize it to 0 everytime the inspector page is redisplayed. + (setf (checklist.count checklist) 0) + checklist) + +(defun make-checklist-button (checklist) + (let ((buttons (checklist.buttons checklist)) + (i (checklist.count checklist))) + (incf (checklist.count checklist)) + `(:action ,(if (svref buttons i) + "[X]" + "[ ]") + ,#'(lambda () + (setf (svref buttons i) (not (svref buttons i)))) + :refreshp t))) + +(defmacro do-checklist ((idx checklist) &body body) + "Iterate over all set buttons in CHECKLIST." + (let ((buttons (gensym "buttons"))) + `(let ((,buttons (checklist.buttons ,checklist))) + (dotimes (,idx (length ,buttons)) + (when (svref ,buttons ,idx) + ,@body))))) + +(defun box (thing) (cons :box thing)) +(defun ref (box) + (assert (eq (car box) :box)) + (cdr box)) +(defun (setf ref) (value box) + (assert (eq (car box) :box)) + (setf (cdr box) value)) + +(defvar *inspector-slots-default-order* :alphabetically + "Accepted values: :alphabetically and :unsorted") + +(defvar *inspector-slots-default-grouping* :all + "Accepted values: :inheritance and :all") + +(defgeneric all-slots-for-inspector (object)) + +(defmethod all-slots-for-inspector ((object standard-object)) + (let* ((class (class-of object)) + (direct-slots (swank-mop:class-direct-slots class)) + (effective-slots (swank-mop:class-slots class)) + (longest-slot-name-length + (loop for slot :in effective-slots + maximize (length (symbol-name + (swank-mop:slot-definition-name slot))))) + (checklist + (reinitialize-checklist + (ensure-istate-metadata object :checklist + (make-checklist (length effective-slots))))) + (grouping-kind + ;; We box the value so we can re-set it. + (ensure-istate-metadata object :grouping-kind + (box *inspector-slots-default-grouping*))) + (sort-order + (ensure-istate-metadata object :sort-order + (box *inspector-slots-default-order*))) + (sort-predicate (ecase (ref sort-order) + (:alphabetically #'string<) + (:unsorted (constantly nil)))) + (sorted-slots (sort (copy-seq effective-slots) + sort-predicate + :key #'swank-mop:slot-definition-name)) + (effective-slots + (ecase (ref grouping-kind) + (:all sorted-slots) + (:inheritance (stable-sort-by-inheritance sorted-slots + class sort-predicate))))) + `("--------------------" + (:newline) + " Group slots by inheritance " + (:action ,(ecase (ref grouping-kind) + (:all "[ ]") + (:inheritance "[X]")) + ,(lambda () + ;; We have to do this as the order of slots will + ;; be sorted differently. + (fill (checklist.buttons checklist) nil) + (setf (ref grouping-kind) + (ecase (ref grouping-kind) + (:all :inheritance) + (:inheritance :all)))) + :refreshp t) + (:newline) + " Sort slots alphabetically " + (:action ,(ecase (ref sort-order) + (:unsorted "[ ]") + (:alphabetically "[X]")) + ,(lambda () + (fill (checklist.buttons checklist) nil) + (setf (ref sort-order) + (ecase (ref sort-order) + (:unsorted :alphabetically) + (:alphabetically :unsorted)))) + :refreshp t) + (:newline) + ,@ (case (ref grouping-kind) + (:all + `((:newline) + "All Slots:" + (:newline) + ,@(make-slot-listing checklist object class + effective-slots direct-slots + longest-slot-name-length))) + (:inheritance + (list-all-slots-by-inheritance checklist object class + effective-slots direct-slots + longest-slot-name-length))) + (:newline) + (:action "[set value]" + ,(lambda () + (do-checklist (idx checklist) + (query-and-set-slot class object + (nth idx effective-slots)))) + :refreshp t) + " " + (:action "[make unbound]" + ,(lambda () + (do-checklist (idx checklist) + (swank-mop:slot-makunbound-using-class + class object (nth idx effective-slots)))) + :refreshp t) + (:newline)))) + +(defun list-all-slots-by-inheritance (checklist object class effective-slots + direct-slots longest-slot-name-length) + (flet ((slot-home-class (slot) + (slot-home-class-using-class slot class))) + (let ((current-slots '())) + (append + (loop for slot in effective-slots + for previous-home-class = (slot-home-class slot) then home-class + for home-class = previous-home-class then (slot-home-class slot) + if (eq home-class previous-home-class) + do (push slot current-slots) + else + collect '(:newline) + and collect (format nil "~A:" (class-name previous-home-class)) + and collect '(:newline) + and append (make-slot-listing checklist object class + (nreverse current-slots) + direct-slots + longest-slot-name-length) + and do (setf current-slots (list slot))) + (and current-slots + `((:newline) + ,(format nil "~A:" + (class-name (slot-home-class-using-class + (car current-slots) class))) + (:newline) + ,@(make-slot-listing checklist object class + (nreverse current-slots) direct-slots + longest-slot-name-length))))))) + +(defun make-slot-listing (checklist object class effective-slots direct-slots + longest-slot-name-length) + (flet ((padding-for (slot-name) + (make-string (- longest-slot-name-length (length slot-name)) + :initial-element #\Space))) + (loop + for effective-slot :in effective-slots + for direct-slot = (find (swank-mop:slot-definition-name effective-slot) + direct-slots + :key #'swank-mop:slot-definition-name) + for slot-name = (inspector-princ + (swank-mop:slot-definition-name effective-slot)) + collect (make-checklist-button checklist) + collect " " + collect `(:value ,(if direct-slot + (list direct-slot effective-slot) + effective-slot) + ,slot-name) + collect (padding-for slot-name) + collect " = " + collect (slot-value-for-inspector class object effective-slot) + collect '(:newline)))) + +(defgeneric slot-value-for-inspector (class object slot) + (:method (class object slot) + (let ((boundp (swank-mop:slot-boundp-using-class class object slot))) + (if boundp + `(:value ,(swank-mop:slot-value-using-class class object slot)) + "#")))) + +(defun slot-home-class-using-class (slot class) + (let ((slot-name (swank-mop:slot-definition-name slot))) + (loop for class in (reverse (swank-mop:class-precedence-list class)) + thereis (and (member slot-name (swank-mop:class-direct-slots class) + :key #'swank-mop:slot-definition-name + :test #'eq) + class)))) + +(defun stable-sort-by-inheritance (slots class predicate) + (stable-sort slots predicate + :key #'(lambda (s) + (class-name (slot-home-class-using-class s class))))) + +(defun query-and-set-slot (class object slot) + (let* ((slot-name (swank-mop:slot-definition-name slot)) + (value-string (read-from-minibuffer-in-emacs + (format nil "Set slot ~S to (evaluated) : " + slot-name)))) + (when (and value-string (not (string= value-string ""))) + (with-simple-restart (abort "Abort setting slot ~S" slot-name) + (setf (swank-mop:slot-value-using-class class object slot) + (eval (read-from-string value-string))))))) + + +(defmethod emacs-inspect ((gf standard-generic-function)) + (flet ((lv (label value) (label-value-line label value))) + (append + (lv "Name" (swank-mop:generic-function-name gf)) + (lv "Arguments" (swank-mop:generic-function-lambda-list gf)) + (docstring-ispec "Documentation" gf t) + (lv "Method class" (swank-mop:generic-function-method-class gf)) + (lv "Method combination" + (swank-mop:generic-function-method-combination gf)) + `("Methods: " (:newline)) + (loop for method in (funcall *gf-method-getter* gf) append + `((:value ,method ,(inspector-princ + ;; drop the name of the GF + (cdr (method-for-inspect-value method)))) + " " + (:action "[remove method]" + ,(let ((m method)) ; LOOP reassigns method + (lambda () + (remove-method gf m)))) + (:newline))) + `((:newline)) + (all-slots-for-inspector gf)))) + +(defmethod emacs-inspect ((method standard-method)) + `(,@(if (swank-mop:method-generic-function method) + `("Method defined on the generic function " + (:value ,(swank-mop:method-generic-function method) + ,(inspector-princ + (swank-mop:generic-function-name + (swank-mop:method-generic-function method))))) + '("Method without a generic function")) + (:newline) + ,@(docstring-ispec "Documentation" method t) + "Lambda List: " (:value ,(swank-mop:method-lambda-list method)) + (:newline) + "Specializers: " (:value ,(swank-mop:method-specializers method) + ,(inspector-princ + (method-specializers-for-inspect method))) + (:newline) + "Qualifiers: " (:value ,(swank-mop:method-qualifiers method)) + (:newline) + "Method function: " (:value ,(swank-mop:method-function method)) + (:newline) + ,@(all-slots-for-inspector method))) + +(defun specializer-direct-methods (class) + (sort (copy-seq (swank-mop:specializer-direct-methods class)) + #'string< + :key + (lambda (x) + (symbol-name + (let ((name (swank-mop::generic-function-name + (swank-mop::method-generic-function x)))) + (if (symbolp name) + name + (second name))))))) + +(defmethod emacs-inspect ((class standard-class)) + `("Name: " + (:value ,(class-name class)) + (:newline) + "Super classes: " + ,@(common-seperated-spec (swank-mop:class-direct-superclasses class)) + (:newline) + "Direct Slots: " + ,@(common-seperated-spec + (swank-mop:class-direct-slots class) + (lambda (slot) + `(:value ,slot ,(inspector-princ + (swank-mop:slot-definition-name slot))))) + (:newline) + "Effective Slots: " + ,@(if (swank-mop:class-finalized-p class) + (common-seperated-spec + (swank-mop:class-slots class) + (lambda (slot) + `(:value ,slot ,(inspector-princ + (swank-mop:slot-definition-name slot))))) + `("# " + (:action "[finalize]" + ,(lambda () (swank-mop:finalize-inheritance class))))) + (:newline) + ,@(let ((doc (documentation class t))) + (when doc + `("Documentation:" (:newline) ,(inspector-princ doc) (:newline)))) + "Sub classes: " + ,@(common-seperated-spec (swank-mop:class-direct-subclasses class) + (lambda (sub) + `(:value ,sub + ,(inspector-princ (class-name sub))))) + (:newline) + "Precedence List: " + ,@(if (swank-mop:class-finalized-p class) + (common-seperated-spec + (swank-mop:class-precedence-list class) + (lambda (class) + `(:value ,class ,(inspector-princ (class-name class))))) + '("#")) + (:newline) + ,@(when (swank-mop:specializer-direct-methods class) + `("It is used as a direct specializer in the following methods:" + (:newline) + ,@(loop + for method in (specializer-direct-methods class) + collect " " + collect `(:value ,method + ,(inspector-princ + (method-for-inspect-value method))) + collect '(:newline) + if (documentation method t) + collect " Documentation: " and + collect (abbrev-doc (documentation method t)) and + collect '(:newline)))) + "Prototype: " ,(if (swank-mop:class-finalized-p class) + `(:value ,(swank-mop:class-prototype class)) + '"#") + (:newline) + ,@(all-slots-for-inspector class))) + +(defmethod emacs-inspect ((slot swank-mop:standard-slot-definition)) + `("Name: " + (:value ,(swank-mop:slot-definition-name slot)) + (:newline) + ,@(when (swank-mop:slot-definition-documentation slot) + `("Documentation:" (:newline) + (:value ,(swank-mop:slot-definition-documentation + slot)) + (:newline))) + "Init args: " + (:value ,(swank-mop:slot-definition-initargs slot)) + (:newline) + "Init form: " + ,(if (swank-mop:slot-definition-initfunction slot) + `(:value ,(swank-mop:slot-definition-initform slot)) + "#") + (:newline) + "Init function: " + (:value ,(swank-mop:slot-definition-initfunction slot)) + (:newline) + ,@(all-slots-for-inspector slot))) + + +;; Wrapper structure over the list of symbols of a package that should +;; be displayed with their respective classification flags. This is +;; because we need a unique type to dispatch on in EMACS-INSPECT. +;; Used by the Inspector for packages. +(defstruct (%package-symbols-container + (:conc-name %container.) + (:constructor %%make-package-symbols-container)) + title ;; A string; the title of the inspector page in Emacs. + description ;; A list of renderable objects; used as description. + symbols ;; A list of symbols. Supposed to be sorted alphabetically. + grouping-kind) ;; Either :SYMBOL or :CLASSIFICATION. Cf. MAKE-SYMBOLS-LISTING + + +(defun %make-package-symbols-container (&key title description symbols) + (%%make-package-symbols-container :title title :description description + :symbols symbols :grouping-kind :symbol)) + +(defgeneric make-symbols-listing (grouping-kind symbols)) + +(defmethod make-symbols-listing ((grouping-kind (eql :symbol)) symbols) + "Returns an object renderable by Emacs' inspector side that +alphabetically lists all the symbols in SYMBOLS together with a +concise string representation of what each symbol +represents (see SYMBOL-CLASSIFICATION-STRING)" + (let ((max-length (loop for s in symbols + maximizing (length (symbol-name s)))) + (distance 10)) ; empty distance between name and classification + (flet ((string-representations (symbol) + (let* ((name (symbol-name symbol)) + (length (length name)) + (padding (- max-length length))) + (values + (concatenate 'string + name + (make-string (+ padding distance) + :initial-element #\Space)) + (symbol-classification-string symbol))))) + `("" ; 8 is (length "Symbols:") + "Symbols:" ,(make-string (+ -8 max-length distance) + :initial-element #\Space) + "Flags:" + (:newline) + ,(concatenate 'string ; underlining dashes + (make-string (+ max-length distance -1) + :initial-element #\-) + " " + (symbol-classification-string '#:foo)) + (:newline) + ,@(loop for symbol in symbols appending + (multiple-value-bind (symbol-string classification-string) + (string-representations symbol) + `((:value ,symbol ,symbol-string) ,classification-string + (:newline) + ))))))) + +(defmethod make-symbols-listing ((grouping-kind (eql :classification)) symbols) + "For each possible classification (cf. CLASSIFY-SYMBOL), group +all the symbols in SYMBOLS to all of their respective +classifications. (If a symbol is, for instance, boundp and a +generic-function, it'll appear both below the BOUNDP group and +the GENERIC-FUNCTION group.) As macros and special-operators are +specified to be FBOUNDP, there is no general FBOUNDP group, +instead there are the three explicit FUNCTION, MACRO and +SPECIAL-OPERATOR groups." + (let ((table (make-hash-table :test #'eq)) + (+default-classification+ :misc)) + (flet ((normalize-classifications (classifications) + (cond ((null classifications) `(,+default-classification+)) + ;; Convert an :FBOUNDP in CLASSIFICATIONS to + ;; :FUNCTION if possible. + ((and (member :fboundp classifications) + (not (member :macro classifications)) + (not (member :special-operator classifications))) + (substitute :function :fboundp classifications)) + (t (remove :fboundp classifications))))) + (loop for symbol in symbols do + (loop for classification in + (normalize-classifications (classify-symbol symbol)) + ;; SYMBOLS are supposed to be sorted alphabetically; + ;; this property is preserved here except for reversing. + do (push symbol (gethash classification table))))) + (let* ((classifications (loop for k being each hash-key in table + collect k)) + (classifications (sort classifications + ;; Sort alphabetically, except + ;; +DEFAULT-CLASSIFICATION+ which + ;; sort to the end. + (lambda (a b) + (cond ((eql a +default-classification+) + nil) + ((eql b +default-classification+) + t) + (t (string< a b))))))) + (loop for classification in classifications + for symbols = (gethash classification table) + appending`(,(symbol-name classification) + (:newline) + ,(make-string 64 :initial-element #\-) + (:newline) + ,@(mapcan (lambda (symbol) + `((:value ,symbol ,(symbol-name symbol)) + (:newline))) + ;; restore alphabetic order. + (nreverse symbols)) + (:newline)))))) + +(defmethod emacs-inspect ((%container %package-symbols-container)) + (with-struct (%container. title description symbols grouping-kind) %container + `(,title (:newline) (:newline) + ,@description + (:newline) + " " ,(ecase grouping-kind + (:symbol + `(:action "[Group by classification]" + ,(lambda () + (setf grouping-kind :classification)) + :refreshp t)) + (:classification + `(:action "[Group by symbol]" + ,(lambda () (setf grouping-kind :symbol)) + :refreshp t))) + (:newline) (:newline) + ,@(make-symbols-listing grouping-kind symbols)))) + +(defun display-link (type symbols length &key title description) + (if (null symbols) + (format nil "0 ~A symbols." type) + `(:value ,(%make-package-symbols-container :title title + :description description + :symbols symbols) + ,(format nil "~D ~A symbol~P." length type length)))) + +(defmethod emacs-inspect ((package package)) + (let ((package-name (package-name package)) + (package-nicknames (package-nicknames package)) + (package-use-list (package-use-list package)) + (package-used-by-list (package-used-by-list package)) + (shadowed-symbols (package-shadowing-symbols package)) + (present-symbols '()) (present-symbols-length 0) + (internal-symbols '()) (internal-symbols-length 0) + (inherited-symbols '()) (inherited-symbols-length 0) + (external-symbols '()) (external-symbols-length 0)) + + (do-symbols* (sym package) + (let ((status (symbol-status sym package))) + (when (eq status :inherited) + (push sym inherited-symbols) (incf inherited-symbols-length) + (go :continue)) + (push sym present-symbols) (incf present-symbols-length) + (cond ((eq status :internal) + (push sym internal-symbols) (incf internal-symbols-length)) + (t + (push sym external-symbols) (incf external-symbols-length)))) + :continue) + + (setf package-nicknames (sort (copy-list package-nicknames) + #'string<) + package-use-list (sort (copy-list package-use-list) + #'string< :key #'package-name) + package-used-by-list (sort (copy-list package-used-by-list) + #'string< :key #'package-name) + shadowed-symbols (sort (copy-list shadowed-symbols) + #'string<)) + ;;; SORT + STRING-LESSP conses on at least SBCL 0.9.18. + (setf present-symbols (sort present-symbols #'string<) + internal-symbols (sort internal-symbols #'string<) + external-symbols (sort external-symbols #'string<) + inherited-symbols (sort inherited-symbols #'string<)) + `("" ;; dummy to preserve indentation. + "Name: " (:value ,package-name) (:newline) + + "Nick names: " ,@(common-seperated-spec package-nicknames) (:newline) + + ,@(when (documentation package t) + `("Documentation:" (:newline) + ,(documentation package t) (:newline))) + + "Use list: " ,@(common-seperated-spec + package-use-list + (lambda (package) + `(:value ,package ,(package-name package)))) + (:newline) + + "Used by list: " ,@(common-seperated-spec + package-used-by-list + (lambda (package) + `(:value ,package ,(package-name package)))) + (:newline) + + ,(display-link "present" present-symbols present-symbols-length + :title + (format nil "All present symbols of package \"~A\"" + package-name) + :description + '("A symbol is considered present in a package if it's" + (:newline) + "\"accessible in that package directly, rather than" + (:newline) + "being inherited from another package.\"" + (:newline) + "(CLHS glossary entry for `present')" + (:newline))) + + (:newline) + ,(display-link "external" external-symbols external-symbols-length + :title + (format nil "All external symbols of package \"~A\"" + package-name) + :description + '("A symbol is considered external of a package if it's" + (:newline) + "\"part of the `external interface' to the package and" + (:newline) + "[is] inherited by any other package that uses the" + (:newline) + "package.\" (CLHS glossary entry of `external')" + (:newline))) + (:newline) + ,(display-link "internal" internal-symbols internal-symbols-length + :title + (format nil "All internal symbols of package \"~A\"" + package-name) + :description + '("A symbol is considered internal of a package if it's" + (:newline) + "present and not external---that is if the package is" + (:newline) + "the home package of the symbol, or if the symbol has" + (:newline) + "been explicitly imported into the package." + (:newline) + (:newline) + "Notice that inherited symbols will thus not be listed," + (:newline) + "which deliberately deviates from the CLHS glossary" + (:newline) + "entry of `internal' because it's assumed to be more" + (:newline) + "useful this way." + (:newline))) + (:newline) + ,(display-link "inherited" inherited-symbols inherited-symbols-length + :title + (format nil "All inherited symbols of package \"~A\"" + package-name) + :description + '("A symbol is considered inherited in a package if it" + (:newline) + "was made accessible via USE-PACKAGE." + (:newline))) + (:newline) + ,(display-link "shadowed" shadowed-symbols (length shadowed-symbols) + :title + (format nil "All shadowed symbols of package \"~A\"" + package-name) + :description nil)))) + + +(defmethod emacs-inspect ((pathname pathname)) + `(,(if (wild-pathname-p pathname) + "A wild pathname." + "A pathname.") + (:newline) + ,@(label-value-line* + ("Namestring" (namestring pathname)) + ("Host" (pathname-host pathname)) + ("Device" (pathname-device pathname)) + ("Directory" (pathname-directory pathname)) + ("Name" (pathname-name pathname)) + ("Type" (pathname-type pathname)) + ("Version" (pathname-version pathname))) + ,@ (unless (or (wild-pathname-p pathname) + (not (probe-file pathname))) + (label-value-line "Truename" (truename pathname))))) + +(defmethod emacs-inspect ((pathname logical-pathname)) + (append + (label-value-line* + ("Namestring" (namestring pathname)) + ("Physical pathname: " (translate-logical-pathname pathname))) + `("Host: " + (:value ,(pathname-host pathname)) + " (" + (:value ,(logical-pathname-translations + (pathname-host pathname))) + " other translations)" + (:newline)) + (label-value-line* + ("Directory" (pathname-directory pathname)) + ("Name" (pathname-name pathname)) + ("Type" (pathname-type pathname)) + ("Version" (pathname-version pathname)) + ("Truename" (if (not (wild-pathname-p pathname)) + (probe-file pathname)))))) + +(defmethod emacs-inspect ((n number)) + `("Value: " ,(princ-to-string n))) + +(defun format-iso8601-time (time-value &optional include-timezone-p) + "Formats a universal time TIME-VALUE in ISO 8601 format, with + the time zone included if INCLUDE-TIMEZONE-P is non-NIL" + ;; Taken from http://www.pvv.ntnu.no/~nsaa/ISO8601.html + ;; Thanks, Nikolai Sandved and Thomas Russ! + (flet ((format-iso8601-timezone (zone) + (if (zerop zone) + "Z" + (multiple-value-bind (h m) (truncate (abs zone) 1.0) + ;; Tricky. Sign of time zone is reversed in ISO 8601 + ;; relative to Common Lisp convention! + (format nil "~:[+~;-~]~2,'0D:~2,'0D" + (> zone 0) h (round (* 60 m))))))) + (multiple-value-bind (second minute hour day month year dow dst zone) + (decode-universal-time time-value) + (declare (ignore dow)) + (format nil "~4,'0D-~2,'0D-~2,'0DT~2,'0D:~2,'0D:~2,'0D~:[~*~;~A~]" + year month day hour minute second + include-timezone-p (format-iso8601-timezone (if dst + (+ zone 1) + zone)))))) + +(defmethod emacs-inspect ((i integer)) + (append + `(,(format nil "Value: ~D = #x~8,'0X = #o~O = #b~,,' ,8:B~@[ = ~E~]" + i i i i (ignore-errors (coerce i 'float))) + (:newline)) + (when (< -1 i char-code-limit) + (label-value-line "Code-char" (code-char i))) + (label-value-line "Integer-length" (integer-length i)) + (ignore-errors + (label-value-line "Universal-time" (format-iso8601-time i t))))) + +(defmethod emacs-inspect ((c complex)) + (label-value-line* + ("Real part" (realpart c)) + ("Imaginary part" (imagpart c)))) + +(defmethod emacs-inspect ((r ratio)) + (label-value-line* + ("Numerator" (numerator r)) + ("Denominator" (denominator r)) + ("As float" (float r)))) + +(defmethod emacs-inspect ((f float)) + (cond + ((float-nan-p f) + ;; try NaN first because the next tests may perform operations + ;; that are undefined for NaNs. + (list "Not a Number.")) + ((not (float-infinity-p f)) + (multiple-value-bind (significand exponent sign) (decode-float f) + (append + `("Scientific: " ,(format nil "~E" f) (:newline) + "Decoded: " + (:value ,sign) " * " + (:value ,significand) " * " + (:value ,(float-radix f)) "^" + (:value ,exponent) (:newline)) + (label-value-line "Digits" (float-digits f)) + (label-value-line "Precision" (float-precision f))))) + ((> f 0) + (list "Positive infinity.")) + ((< f 0) + (list "Negative infinity.")))) + +(defun make-pathname-ispec (pathname position) + `("Pathname: " + (:value ,pathname) + (:newline) " " + ,@(when position + `((:action "[visit file and show current position]" + ,(lambda () + (ed-in-emacs `(,pathname :position ,position :bytep t))) + :refreshp nil) + (:newline))))) + +(defun make-file-stream-ispec (stream) + ;; SBCL's socket stream are file-stream but are not associated to + ;; any pathname. + (let ((pathname (ignore-errors (pathname stream)))) + (when pathname + (make-pathname-ispec pathname (and (open-stream-p stream) + (file-position stream)))))) + +(defmethod emacs-inspect ((stream file-stream)) + (multiple-value-bind (content) + (call-next-method) + (append (make-file-stream-ispec stream) content))) + +(defmethod emacs-inspect ((condition stream-error)) + (multiple-value-bind (content) + (call-next-method) + (let ((stream (stream-error-stream condition))) + (append (when (typep stream 'file-stream) + (make-file-stream-ispec stream)) + content)))) + +(defun common-seperated-spec (list &optional (callback (lambda (v) + `(:value ,v)))) + (butlast + (loop + for i in list + collect (funcall callback i) + collect ", "))) + +(defun inspector-princ (list) + "Like princ-to-string, but don't rewrite (function foo) as #'foo. +Do NOT pass circular lists to this function." + (let ((*print-pprint-dispatch* (copy-pprint-dispatch))) + (set-pprint-dispatch '(cons (member function)) nil) + (princ-to-string list))) + +(provide :swank-fancy-inspector) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-fuzzy.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-fuzzy.lisp new file mode 100644 index 0000000..bfd274f --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-fuzzy.lisp @@ -0,0 +1,706 @@ +;;; swank-fuzzy.lisp --- fuzzy symbol completion +;; +;; Authors: Brian Downing +;; Tobias C. Rittweiler +;; and others +;; +;; License: Public Domain +;; + + +(in-package :swank) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (swank-require :swank-util) + (swank-require :swank-c-p-c)) + +(defvar *fuzzy-duplicate-symbol-filter* :nearest-package + "Specifies how fuzzy-matching handles \"duplicate\" symbols. +Possible values are :NEAREST-PACKAGE, :HOME-PACKAGE, :ALL, or a custom +function. See Fuzzy Completion in the manual for details.") + +(export '*fuzzy-duplicate-symbol-filter*) + +;;; For nomenclature of the fuzzy completion section, please read +;;; through the following docstring. + +(defslimefun fuzzy-completions (string default-package-name + &key limit time-limit-in-msec) +"Returns a list of two values: + + An (optionally limited to LIMIT best results) list of fuzzy + completions for a symbol designator STRING. The list will be + sorted by score, most likely match first. + + A flag that indicates whether or not TIME-LIMIT-IN-MSEC has + been exhausted during computation. If that parameter's value is + NIL or 0, no time limit is assumed. + +The main result is a list of completion objects, where a completion +object is: + + (COMPLETED-STRING SCORE (&rest CHUNKS) CLASSIFICATION-STRING) + +where a CHUNK is a description of a matched substring: + + (OFFSET SUBSTRING) + +and FLAGS is short string describing properties of the symbol (see +SYMBOL-CLASSIFICATION-STRING). + +E.g., completing \"mvb\" in a package that uses COMMON-LISP would +return something like: + + ((\"multiple-value-bind\" 26.588236 ((0 \"m\") (9 \"v\") (15 \"b\")) + (:FBOUNDP :MACRO)) + ...) + +If STRING is package qualified the result list will also be +qualified. If string is non-qualified the result strings are +also not qualified and are considered relative to +DEFAULT-PACKAGE-NAME. + +Which symbols are candidates for matching depends on the symbol +designator's format. The cases are as follows: + FOO - Symbols accessible in the buffer package. + PKG:FOO - Symbols external in package PKG. + PKG::FOO - Symbols accessible in package PKG." + ;; For Emacs we allow both NIL and 0 as value of TIME-LIMIT-IN-MSEC + ;; to denote an infinite time limit. Internally, we only use NIL for + ;; that purpose, to be able to distinguish between "no time limit + ;; alltogether" and "current time limit already exhausted." So we've + ;; got to canonicalize its value at first: + (let* ((no-time-limit-p (or (not time-limit-in-msec) + (zerop time-limit-in-msec))) + (time-limit (if no-time-limit-p nil time-limit-in-msec))) + (multiple-value-bind (completion-set interrupted-p) + (fuzzy-completion-set string default-package-name :limit limit + :time-limit-in-msec time-limit) + ;; We may send this as elisp [] arrays to spare a coerce here, + ;; but then the network serialization were slower by handling arrays. + ;; Instead we limit the number of completions that is transferred + ;; (the limit is set from Emacs.) + (list (coerce completion-set 'list) interrupted-p)))) + + +;;; A Fuzzy Matching -- Not to be confused with a fuzzy completion +;;; object that will be sent back to Emacs, as described above. + +(defstruct (fuzzy-matching (:conc-name fuzzy-matching.) + (:predicate fuzzy-matching-p) + (:constructor make-fuzzy-matching + (symbol package-name score package-chunks + symbol-chunks &key (symbol-p t)))) + symbol ; The symbol that has been found to match. + symbol-p ; To deffirentiate between completeing + ; package: and package:nil + package-name ; The name of the package where SYMBOL was found in. + ; (This is not necessarily the same as the home-package + ; of SYMBOL, because the SYMBOL can be internal to + ; lots of packages; also think of package nicknames.) + score ; The higher the better SYMBOL is a match. + package-chunks ; Chunks pertaining to the package identifier of SYMBOL. + symbol-chunks) ; Chunks pertaining to SYMBOL's name. + +(defun %fuzzy-extract-matching-info (fuzzy-matching user-input-string) + (multiple-value-bind (_ user-package-name __ input-internal-p) + (parse-completion-arguments user-input-string nil) + (declare (ignore _ __)) + (with-struct (fuzzy-matching. score symbol package-name package-chunks + symbol-chunks symbol-p) + fuzzy-matching + (let (symbol-name real-package-name internal-p) + (cond (symbol-p ; symbol fuzzy matching? + (setf symbol-name (symbol-name symbol)) + (setf internal-p input-internal-p) + (setf real-package-name (cond ((keywordp symbol) "") + ((not user-package-name) nil) + (t package-name)))) + (t ; package fuzzy matching? + (setf symbol-name "") + (setf real-package-name package-name) + ;; If no explicit package name was given by the user + ;; (e.g. input was "asdf"), we want to append only + ;; one colon ":" to the package names. + (setf internal-p (if user-package-name input-internal-p nil)))) + (values symbol-name + real-package-name + (if user-package-name internal-p nil) + (completion-output-symbol-converter user-input-string) + (completion-output-package-converter user-input-string)))))) + +(defun fuzzy-format-matching (fuzzy-matching user-input-string) + "Returns the completion (\"foo:bar\") that's represented by FUZZY-MATCHING." + (multiple-value-bind (symbol-name package-name internal-p + symbol-converter package-converter) + (%fuzzy-extract-matching-info fuzzy-matching user-input-string) + (setq symbol-name (and symbol-name + (funcall symbol-converter symbol-name))) + (setq package-name (and package-name + (funcall package-converter package-name))) + (let ((result (untokenize-symbol package-name internal-p symbol-name))) + ;; We return the length of the possibly added prefix as second value. + (values result (search symbol-name result))))) + +(defun fuzzy-convert-matching-for-emacs (fuzzy-matching user-input-string) + "Converts a result from the fuzzy completion core into something +that emacs is expecting. Converts symbols to strings, fixes case +issues, and adds information (as a string) describing if the symbol is +bound, fbound, a class, a macro, a generic-function, a +special-operator, or a package." + (with-struct (fuzzy-matching. symbol score package-chunks symbol-chunks + symbol-p) + fuzzy-matching + (multiple-value-bind (name added-length) + (fuzzy-format-matching fuzzy-matching user-input-string) + (list name + (format nil "~,2f" score) + (append package-chunks + (mapcar (lambda (chunk) + ;; Fix up chunk positions to account for possible + ;; added package identifier. + (let ((offset (first chunk)) + (string (second chunk))) + (list (+ added-length offset) string))) + symbol-chunks)) + (if symbol-p + (symbol-classification-string symbol) + "-------p"))))) + +(defun fuzzy-completion-set (string default-package-name + &key limit time-limit-in-msec) + "Returns two values: an array of completion objects, sorted by +their score, that is how well they are a match for STRING +according to the fuzzy completion algorithm. If LIMIT is set, +only the top LIMIT results will be returned. Additionally, a flag +is returned that indicates whether or not TIME-LIMIT-IN-MSEC was +exhausted." + (check-type limit (or null (integer 0 #.(1- most-positive-fixnum)))) + (check-type time-limit-in-msec + (or null (integer 0 #.(1- most-positive-fixnum)))) + (multiple-value-bind (matchings interrupted-p) + (fuzzy-generate-matchings string default-package-name time-limit-in-msec) + (when (and limit + (> limit 0) + (< limit (length matchings))) + (if (array-has-fill-pointer-p matchings) + (setf (fill-pointer matchings) limit) + (setf matchings (make-array limit :displaced-to matchings)))) + (map-into matchings #'(lambda (m) + (fuzzy-convert-matching-for-emacs m string)) + matchings) + (values matchings interrupted-p))) + + +(defun fuzzy-generate-matchings (string default-package-name + time-limit-in-msec) + "Does all the hard work for FUZZY-COMPLETION-SET. If +TIME-LIMIT-IN-MSEC is NIL, an infinite time limit is assumed." + (multiple-value-bind (parsed-symbol-name parsed-package-name + package internal-p) + (parse-completion-arguments string default-package-name) + (flet ((fix-up (matchings parent-package-matching) + ;; The components of each matching in MATCHINGS have been computed + ;; relatively to PARENT-PACKAGE-MATCHING. Make them absolute. + (let* ((p parent-package-matching) + (p.name (fuzzy-matching.package-name p)) + (p.score (fuzzy-matching.score p)) + (p.chunks (fuzzy-matching.package-chunks p))) + (map-into + matchings + (lambda (m) + (let ((m.score (fuzzy-matching.score m))) + (setf (fuzzy-matching.package-name m) p.name) + (setf (fuzzy-matching.package-chunks m) p.chunks) + (setf (fuzzy-matching.score m) + (if (equal parsed-symbol-name "") + ;; Make package matchings be sorted before all + ;; the relative symbol matchings while preserving + ;; over all orderness. + (/ p.score 100) + (+ p.score m.score))) + m)) + matchings))) + (find-symbols (designator package time-limit &optional filter) + (fuzzy-find-matching-symbols designator package + :time-limit-in-msec time-limit + :external-only (not internal-p) + :filter (or filter #'identity))) + (find-packages (designator time-limit) + (fuzzy-find-matching-packages designator + :time-limit-in-msec time-limit)) + (maybe-find-local-package (name) + (or (find-locally-nicknamed-package name *buffer-package*) + (find-package name)))) + (let ((time-limit time-limit-in-msec) (symbols) (packages) (results) + (dedup-table (make-hash-table :test #'equal))) + (cond ((not parsed-package-name) ; E.g. STRING = "asd" + ;; We don't know if user is searching for a package or a symbol + ;; within his current package. So we try to find either. + (setf (values packages time-limit) + (find-packages parsed-symbol-name time-limit)) + (setf (values symbols time-limit) + (find-symbols parsed-symbol-name package time-limit))) + ((string= parsed-package-name "") ; E.g. STRING = ":" or ":foo" + (setf (values symbols time-limit) + (find-symbols parsed-symbol-name package time-limit))) + (t ; E.g. STRING = "asd:" or "asd:foo" + ;; Find fuzzy matchings of the denoted package identifier part. + ;; After that, find matchings for the denoted symbol identifier + ;; relative to all the packages found. + (multiple-value-bind (symbol-packages rest-time-limit) + (find-packages parsed-package-name time-limit-in-msec) + ;; We want to traverse the found packages in the order of + ;; their score, since those with higher score presumably + ;; represent better choices. (This is important because some + ;; packages may never be looked at if time limit exhausts + ;; during traversal.) + (setf symbol-packages + (sort symbol-packages #'fuzzy-matching-greaterp)) + (loop + for package-matching across symbol-packages + for package = (maybe-find-local-package + (fuzzy-matching.package-name + package-matching)) + while (or (not time-limit) (> rest-time-limit 0)) do + (multiple-value-bind (matchings remaining-time) + ;; The duplication filter removes all those symbols + ;; which are present in more than one package + ;; match. See *FUZZY-DUPLICATE-SYMBOL-FILTER* + (find-symbols parsed-symbol-name package rest-time-limit + (%make-duplicate-symbols-filter + package-matching symbol-packages dedup-table)) + (setf matchings (fix-up matchings package-matching)) + (setf symbols (concatenate 'vector symbols matchings)) + (setf rest-time-limit remaining-time) + (let ((guessed-sort-duration + (%guess-sort-duration (length symbols)))) + (when (and rest-time-limit + (<= rest-time-limit guessed-sort-duration)) + (decf rest-time-limit guessed-sort-duration) + (loop-finish)))) + finally + (setf time-limit rest-time-limit) + (when (equal parsed-symbol-name "") ; E.g. STRING = "asd:" + (setf packages symbol-packages)))))) + ;; Sort by score; thing with equal score, sort alphabetically. + ;; (Especially useful when PARSED-SYMBOL-NAME is empty, and all + ;; possible completions are to be returned.) + (setf results (concatenate 'vector symbols packages)) + (setf results (sort results #'fuzzy-matching-greaterp)) + (values results (and time-limit (<= time-limit 0))))))) + +(defun %guess-sort-duration (length) + ;; These numbers are pretty much arbitrary, except that they're + ;; vaguely correct on my machine with SBCL. Yes, this is an ugly + ;; kludge, but it's better than before (where this didn't exist at + ;; all, which essentially meant, that this was taken to be 0.) + (if (zerop length) + 0 + (let ((comparasions (* 3.8 (* length (log length 2))))) + (* 1000 (* comparasions (expt 10 -7)))))) ; msecs + +(defun %make-duplicate-symbols-filter (current-package-matching fuzzy-package-matchings dedup-table) + ;; Returns a filter function based on *FUZZY-DUPLICATE-SYMBOL-FILTER*. + (case *fuzzy-duplicate-symbol-filter* + (:home-package + ;; Return a filter function that takes a symbol, and which returns T + ;; if and only if /no/ matching in FUZZY-PACKAGE-MATCHINGS represents + ;; the home-package of the symbol passed. + (let ((packages (mapcar #'(lambda (m) + (find-package (fuzzy-matching.package-name m))) + (remove current-package-matching + (coerce fuzzy-package-matchings 'list))))) + #'(lambda (symbol) + (not (member (symbol-package symbol) packages))))) + (:nearest-package + ;; Keep only the first occurence of the symbol. + #'(lambda (symbol) + (unless (gethash (symbol-name symbol) dedup-table) + (setf (gethash (symbol-name symbol) dedup-table) t)))) + (:all + ;; No filter + #'identity) + (t + (typecase *fuzzy-duplicate-symbol-filter* + (function + ;; Custom filter + (funcall *fuzzy-duplicate-symbol-filter* + (fuzzy-matching.package-name current-package-matching) + (map 'list #'fuzzy-matching.package-name fuzzy-package-matchings) + dedup-table)) + (t + ;; Bad filter value + (warn "bad *FUZZY-DUPLICATE-SYMBOL-FILTER* value: ~s" + *fuzzy-duplicate-symbol-filter*) + #'identity))))) + +(defun fuzzy-matching-greaterp (m1 m2) + "Returns T if fuzzy-matching M1 should be sorted before M2. +Basically just the scores of the two matchings are compared, and +the match with higher score wins. For the case that the score is +equal, the one which comes alphabetically first wins." + (declare (type fuzzy-matching m1 m2)) + (let ((score1 (fuzzy-matching.score m1)) + (score2 (fuzzy-matching.score m2))) + (cond ((> score1 score2) t) + ((< score1 score2) nil) ; total order + (t + (let ((name1 (symbol-name (fuzzy-matching.symbol m1))) + (name2 (symbol-name (fuzzy-matching.symbol m2)))) + (string< name1 name2)))))) + +(declaim (ftype (function () (integer 0)) get-real-time-msecs)) +(defun get-real-time-in-msecs () + (let ((units-per-msec (max 1 (floor internal-time-units-per-second 1000)))) + (values (floor (get-internal-real-time) units-per-msec)))) + +(defun fuzzy-find-matching-symbols + (string package &key (filter #'identity) external-only time-limit-in-msec) + "Returns two values: a vector of fuzzy matchings for matching +symbols in PACKAGE, using the fuzzy completion algorithm, and the +remaining time limit. + +Only those symbols are considered of which FILTER does return T. + +If EXTERNAL-ONLY is true, only external symbols are considered. A +TIME-LIMIT-IN-MSEC of NIL is considered no limit; if it's zero or +negative, perform a NOP." + (let ((time-limit-p (and time-limit-in-msec t)) + (time-limit (or time-limit-in-msec 0)) + (rtime-at-start (get-real-time-in-msecs)) + (package-name (package-name package)) + (count 0)) + (declare (type boolean time-limit-p)) + (declare (type integer time-limit rtime-at-start)) + (declare (type (integer 0 #.(1- most-positive-fixnum)) count)) + + (flet ((recompute-remaining-time (old-remaining-time) + (cond ((not time-limit-p) + ;; propagate NIL back as infinite time limit + (values nil nil)) + ((> count 0) ; ease up on getting internal time like crazy + (setf count (mod (1+ count) 128)) + (values nil old-remaining-time)) + (t (let* ((elapsed-time (- (get-real-time-in-msecs) + rtime-at-start)) + (remaining (- time-limit elapsed-time))) + (values (<= remaining 0) remaining))))) + (perform-fuzzy-match (string symbol-name) + (let* ((converter (completion-output-symbol-converter string)) + (converted-symbol-name (funcall converter symbol-name))) + (compute-highest-scoring-completion string + converted-symbol-name)))) + (let ((completions (make-array 256 :adjustable t :fill-pointer 0)) + (rest-time-limit time-limit)) + (do-symbols* (symbol package) + (multiple-value-bind (exhausted? remaining-time) + (recompute-remaining-time rest-time-limit) + (setf rest-time-limit remaining-time) + (cond (exhausted? (return)) + ((not (and (or (not external-only) + (symbol-external-p symbol package)) + (funcall filter symbol)))) + ((string= "" string) ; "" matches always + (vector-push-extend + (make-fuzzy-matching symbol package-name + 0.0 '() '()) + completions)) + (t + (multiple-value-bind (match-result score) + (perform-fuzzy-match string (symbol-name symbol)) + (when match-result + (vector-push-extend + (make-fuzzy-matching symbol package-name score + '() match-result) + completions))))))) + (values completions rest-time-limit))))) + +(defun fuzzy-find-matching-packages (name &key time-limit-in-msec) + "Returns a vector of fuzzy matchings for each package that is +similiar to NAME, and the remaining time limit. +Cf. FUZZY-FIND-MATCHING-SYMBOLS." + (let ((time-limit-p (and time-limit-in-msec t)) + (time-limit (or time-limit-in-msec 0)) + (rtime-at-start (get-real-time-in-msecs)) + (converter (completion-output-package-converter name)) + (completions (make-array 32 :adjustable t :fill-pointer 0))) + (declare (type boolean time-limit-p)) + (declare (type integer time-limit rtime-at-start)) + (declare (type function converter)) + (flet ((match-package (names) + (loop with max-pkg-name = "" + with max-result = nil + with max-score = 0 + for package-name in names + for converted-name = (funcall converter package-name) + do + (multiple-value-bind (result score) + (compute-highest-scoring-completion name + converted-name) + (when (and result (> score max-score)) + (setf max-pkg-name package-name) + (setf max-result result) + (setf max-score score))) + finally + (when max-result + (vector-push-extend + (make-fuzzy-matching nil max-pkg-name + max-score max-result '() + :symbol-p nil) + completions))))) + (cond ((and time-limit-p (<= time-limit 0)) + (values #() time-limit)) + (t + (loop for (nick) in (package-local-nicknames *buffer-package*) + do + (match-package (list nick))) + (loop for package in (list-all-packages) + do + ;; Find best-matching package-nickname: + (match-package (package-names package)) + finally + (return + (values completions + (and time-limit-p + (let ((elapsed-time (- (get-real-time-in-msecs) + rtime-at-start))) + (- time-limit elapsed-time))))))))))) + + +(defslimefun fuzzy-completion-selected (original-string completion) + "This function is called by Slime when a fuzzy completion is +selected by the user. It is for future expansion to make +testing, say, a machine learning algorithm for completion scoring +easier. + +ORIGINAL-STRING is the string the user completed from, and +COMPLETION is the completion object (see docstring for +SWANK:FUZZY-COMPLETIONS) corresponding to the completion that the +user selected." + (declare (ignore original-string completion)) + nil) + + +;;;;; Fuzzy completion core + +(defparameter *fuzzy-recursion-soft-limit* 30 + "This is a soft limit for recursion in +RECURSIVELY-COMPUTE-MOST-COMPLETIONS. Without this limit, +completing a string such as \"ZZZZZZ\" with a symbol named +\"ZZZZZZZZZZZZZZZZZZZZZZZ\" will result in explosive recursion to +find all the ways it can match. + +Most natural language searches and symbols do not have this +problem -- this is only here as a safeguard.") +(declaim (fixnum *fuzzy-recursion-soft-limit*)) + +(defvar *all-chunks* '()) +(declaim (type list *all-chunks*)) + +(defun compute-highest-scoring-completion (short full) + "Finds the highest scoring way to complete the abbreviation +SHORT onto the string FULL, using CHAR= as a equality function for +letters. Returns two values: The first being the completion +chunks of the highest scorer, and the second being the score." + (let* ((scored-results + (mapcar #'(lambda (result) + (cons (score-completion result short full) result)) + (compute-most-completions short full))) + (winner (first (sort scored-results #'> :key #'first)))) + (values (rest winner) (first winner)))) + +(defun compute-most-completions (short full) + "Finds most possible ways to complete FULL with the letters in SHORT. +Calls RECURSIVELY-COMPUTE-MOST-COMPLETIONS recursively. Returns +a list of (&rest CHUNKS), where each CHUNKS is a description of +how a completion matches." + (let ((*all-chunks* nil)) + (recursively-compute-most-completions short full 0 0 nil nil nil t) + *all-chunks*)) + +(defun recursively-compute-most-completions + (short full + short-index initial-full-index + chunks current-chunk current-chunk-pos + recurse-p) + "Recursively (if RECURSE-P is true) find /most/ possible ways +to fuzzily map the letters in SHORT onto FULL, using CHAR= to +determine if two letters match. + +A chunk is a list of elements that have matched consecutively. +When consecutive matches stop, it is coerced into a string, +paired with the starting position of the chunk, and pushed onto +CHUNKS. + +Whenever a letter matches, if RECURSE-P is true, +RECURSIVELY-COMPUTE-MOST-COMPLETIONS calls itself with a position +one index ahead, to find other possibly higher scoring +possibilities. If there are less than +*FUZZY-RECURSION-SOFT-LIMIT* results in *ALL-CHUNKS* currently, +this call will also recurse. + +Once a word has been completely matched, the chunks are pushed +onto the special variable *ALL-CHUNKS* and the function returns." + (declare (optimize speed) + (type fixnum short-index initial-full-index) + (type list current-chunk) + (simple-string short full)) + (flet ((short-cur () + "Returns the next letter from the abbreviation, or NIL + if all have been used." + (if (= short-index (length short)) + nil + (aref short short-index))) + (add-to-chunk (char pos) + "Adds the CHAR at POS in FULL to the current chunk, + marking the start position if it is empty." + (unless current-chunk + (setf current-chunk-pos pos)) + (push char current-chunk)) + (collect-chunk () + "Collects the current chunk to CHUNKS and prepares for + a new chunk." + (when current-chunk + (let ((current-chunk-as-string + (nreverse + (make-array (length current-chunk) + :element-type 'character + :initial-contents current-chunk)))) + (push (list current-chunk-pos current-chunk-as-string) chunks) + (setf current-chunk nil + current-chunk-pos nil))))) + ;; If there's an outstanding chunk coming in collect it. Since + ;; we're recursively called on skipping an input character, the + ;; chunk can't possibly continue on. + (when current-chunk (collect-chunk)) + (do ((pos initial-full-index (1+ pos))) + ((= pos (length full))) + (let ((cur-char (aref full pos))) + (if (and (short-cur) + (char= cur-char (short-cur))) + (progn + (when recurse-p + ;; Try other possibilities, limiting insanely deep + ;; recursion somewhat. + (recursively-compute-most-completions + short full short-index (1+ pos) + chunks current-chunk current-chunk-pos + (not (> (length *all-chunks*) + *fuzzy-recursion-soft-limit*)))) + (incf short-index) + (add-to-chunk cur-char pos)) + (collect-chunk)))) + (collect-chunk) + ;; If we've exhausted the short characters we have a match. + (if (short-cur) + nil + (let ((rev-chunks (reverse chunks))) + (push rev-chunks *all-chunks*) + rev-chunks)))) + + +;;;;; Fuzzy completion scoring + +(defvar *fuzzy-completion-symbol-prefixes* "*+-%&?<" + "Letters that are likely to be at the beginning of a symbol. +Letters found after one of these prefixes will be scored as if +they were at the beginning of ths symbol.") +(defvar *fuzzy-completion-symbol-suffixes* "*+->" + "Letters that are likely to be at the end of a symbol. +Letters found before one of these suffixes will be scored as if +they were at the end of the symbol.") +(defvar *fuzzy-completion-word-separators* "-/." + "Letters that separate different words in symbols. Letters +after one of these symbols will be scores more highly than other +letters.") + +(defun score-completion (completion short full) + "Scores the completion chunks COMPLETION as a completion from +the abbreviation SHORT to the full string FULL. COMPLETION is a +list like: + ((0 \"mul\") (9 \"v\") (15 \"b\")) +Which, if SHORT were \"mulvb\" and full were \"multiple-value-bind\", +would indicate that it completed as such (completed letters +capitalized): + MULtiple-Value-Bind + +Letters are given scores based on their position in the string. +Letters at the beginning of a string or after a prefix letter at +the beginning of a string are scored highest. Letters after a +word separator such as #\- are scored next highest. Letters at +the end of a string or before a suffix letter at the end of a +string are scored medium, and letters anywhere else are scored +low. + +If a letter is directly after another matched letter, and its +intrinsic value in that position is less than a percentage of the +previous letter's value, it will use that percentage instead. + +Finally, a small scaling factor is applied to favor shorter +matches, all other things being equal." + (labels ((at-beginning-p (pos) + (= pos 0)) + (after-prefix-p (pos) + (and (= pos 1) + (find (aref full 0) *fuzzy-completion-symbol-prefixes*))) + (word-separator-p (pos) + (find (aref full pos) *fuzzy-completion-word-separators*)) + (after-word-separator-p (pos) + (find (aref full (1- pos)) *fuzzy-completion-word-separators*)) + (at-end-p (pos) + (= pos (1- (length full)))) + (before-suffix-p (pos) + (and (= pos (- (length full) 2)) + (find (aref full (1- (length full))) + *fuzzy-completion-symbol-suffixes*))) + (score-or-percentage-of-previous (base-score pos chunk-pos) + (if (zerop chunk-pos) + base-score + (max base-score + (+ (* (score-char (1- pos) (1- chunk-pos)) 0.85) + (expt 1.2 chunk-pos))))) + (score-char (pos chunk-pos) + (score-or-percentage-of-previous + (cond ((at-beginning-p pos) 10) + ((after-prefix-p pos) 10) + ((word-separator-p pos) 1) + ((after-word-separator-p pos) 8) + ((at-end-p pos) 6) + ((before-suffix-p pos) 6) + (t 1)) + pos chunk-pos)) + (score-chunk (chunk) + (loop for chunk-pos below (length (second chunk)) + for pos from (first chunk) + summing (score-char pos chunk-pos)))) + (let* ((chunk-scores (mapcar #'score-chunk completion)) + (length-score (/ 10.0 (1+ (- (length full) (length short)))))) + (values + (+ (reduce #'+ chunk-scores) length-score) + (list (mapcar #'list chunk-scores completion) length-score))))) + +(defun highlight-completion (completion full) + "Given a chunk definition COMPLETION and the string FULL, +HIGHLIGHT-COMPLETION will create a string that demonstrates where +the completion matched in the string. Matches will be +capitalized, while the rest of the string will be lower-case." + (let ((highlit (nstring-downcase (copy-seq full)))) + (dolist (chunk completion) + (setf highlit (nstring-upcase highlit + :start (first chunk) + :end (+ (first chunk) + (length (second chunk)))))) + highlit)) + +(defun format-fuzzy-completion-set (winners) + "Given a list of completion objects such as on returned by +FUZZY-COMPLETION-SET, format the list into user-readable output +for interactive debugging purpose." + (let ((max-len + (loop for winner in winners maximizing (length (first winner))))) + (loop for (sym score result) in winners do + (format t "~&~VA score ~8,2F ~A" + max-len (highlight-completion result sym) score result)))) + +(provide :swank-fuzzy) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-goo.goo b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-goo.goo new file mode 100644 index 0000000..562401d --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-goo.goo @@ -0,0 +1,995 @@ +;;;; swank-goo.goo --- Swank server for GOO +;;; +;;; Copyright (C) 2005 Helmut Eller +;;; +;;; This file is licensed under the terms of the GNU General Public +;;; License as distributed with Emacs (press C-h C-c to view it). + +;;;; Installation +;; +;; 1. Add something like this to your .emacs: +;; +;; (setq slime-lisp-implementations +;; '((goo ("g2c") :init goo-slime-init))) +;; +;; (defun goo-slime-init (file _) +;; (format "%S\n%S\n" +;; `(set goo/system:*module-search-path* +;; (cat '(".../slime/contrib/") +;; goo/system:*module-search-path*)) +;; `(swank-goo:start-swank ,file))) +;; +;; 2. Start everything with M-- M-x slime goo +;; + +;;;; Code + +(use goo) +(use goo/boot) +(use goo/x) +(use goo/io/port) +(use goo/io/write) +(use goo/eval) +(use goo/system) +(use goo/conditions) +(use goo/fun) +(use goo/loc) +(use goo/chr) +(use eval/module) +(use eval/ast) +(use eval/g2c) + + +;;;; server setup + +(df create-server (port-number) (setup-server port-number announce-port)) + +(df start-swank (port-file) + (setup-server 0 (fun (s) (write-port-file (%local-port s) port-file)))) + +(df setup-server (port-number announce) + (let ((s (create-socket port-number))) + (fin (seq + (announce s) + (let ((c (accept s))) + ;;(post "connection: %s" c) + (fin (serve-requests c) + (%close (@fd c))))) + (post "closing socket: %s" s) + (%close s)))) + +(df announce-port (socket) + (post "Listening on port: %d\n" (%local-port socket))) + +(df write-port-file (port-number filename) + (with-port (file (open filename)) + (msg file "%d\n" port-number))) + +(dc ()) + +(dc ()) +(dp @socket ( => )) +(dp @in ( => )) +(dp @out ( => )) + +(dv emacs-connection|(t? ) #f) + +(df serve-requests (socket) + (dlet ((emacs-connection (new + @socket socket + @out (new @socket socket) + @in (new @socket socket)))) + (dlet ((out (@out emacs-connection)) + (in (@in emacs-connection))) + (while #t + (simple-restart + "SLIME top-level" + (fun () (process-next-event socket))))))) + +(d. (t= 'nil)) +(d. t #t) +(d. cons pair) + +(dv tag-counter| 0) + +(df process-next-event (port) (dispatch-event (decode-message port) port)) + +(df dispatch-event (event port) + ;; (post "%=\n" event) + (match event + ((:emacs-rex ,form ,package ,_thread-id ,id) + (eval-for-emacs form package port id)) + ((:read-string ,_) + (def tag (incf tag-counter)) + (encode-message `(:read-string ,_ ,tag) port) + (rep loop () + (match (decode-message port) + ((:emacs-return-string ,_ ,rtag ,str) + (assert (= tag rtag) "Unexpected reply tag: %d" rtag) + str) + ((,@evt) + (try-recover + (fun () (dispatch-event evt port)) + (fun () (encode-message `(:read-aborted ,_ ,tag) port))) + (loop))))) + ((:emacs-return-string ,_ ,rtag ,str) + (error "Unexpected event: %=" event)) + ((,@_) (encode-message event port)))) + +(dc ()) +(dp @module ( => )) +(dp @id ( => )) +(dp @port ( => )) +(dp @prev ( => (t? ))) + +;; should be ddv +(dv eval-context|(t? ) #f) + +(df buffer-module () (@module eval-context)) + +(df eval-for-emacs (form| package|(t+ ) port id|) + (try-recover + (fun () + (try debugger-hook + (dlet ((eval-context (new + @module (find-buffer-module package) @id id + @port port @prev eval-context))) + (def result (eval (frob-form-for-eval form) 'swank-goo)) + (force-out out) + (dispatch-event `(:return (:ok ,result) ,id) port)))) + (fun () (dispatch-event `(:return (:abort) ,id) port)))) + +(dm find-buffer-module (name| => ) + (or (elt-or (all-modules) (as-sym name) #f) + (find-buffer-module 'nil))) + +(dm find-buffer-module (name| => ) default-module) + +(dv default-module| (runtime-module 'goo/user)) + +(d. slimefuns (fab 100)) + +(ds defslimefun (,name ,args ,@body) + `(set (elt slimefuns ',name) + (df ,(cat-sym 'swank@ name) ,args ,@body))) + +(df slimefun (name) + (or (elt-or slimefuns name #f) + (error "Undefined slimefun: %=" name))) + +;; rewrite (swank:foo ...) to ((slimefun 'foo) ...) +(df frob-form-for-eval (form) + (match form + ((,op ,@args) + (match (map as-sym (split (sym-name op) #\:)) + ((swank ,name) + `((slimefun ',name) ,@args)))))) + + +;;;; debugger + +(dc ()) +(dp @level ( => )) +(dp @top-frame ( => )) +(dp @restarts ( => )) +(dp @condition ( => )) +(dp @eval-context ( => (t? ))) + +(dv sldb-context|(t? ) #f) + +(df debugger-hook (c| resume) + (let ((tf (find-top-frame 'debugger-hook 2)) + (rs (compute-restarts c)) + (l (if sldb-context (1+ (@level sldb-context)) 1))) + (cond ((> l 10) (emergency-abort c)) + (#t + (dlet ((sldb-context (new + @level l @top-frame tf + @restarts rs @condition c + @eval-context eval-context))) + (let ((bt (compute-backtrace tf 0 10))) + (force-out out) + (dispatch-event `(:debug 0 ,l + ,@(debugger-info c rs bt eval-context)) + (@port eval-context)) + (sldb-loop l (@port eval-context)))))))) + +(df emergency-abort (c) + (post "Maximum debug level reached aborting...\n") + (post "%s\n" (describe-condition c)) + (do-stack-frames (fun (f args) (msg out " %= %=\n" f args))) + (invoke-handler-interactively (find-restart ) in out)) + +(df sldb-loop (level port) + (fin (while #t + (dispatch-event `(:debug-activate 0 ,level) port) + (simple-restart + (msg-to-str "Return to SLDB level %s" level) + (fun () (process-next-event port)))) + (dispatch-event `(:debug-return 0 ,level nil) port))) + +(defslimefun backtrace (start| end|(t+ )) + (backtrace-for-emacs + (compute-backtrace (@top-frame sldb-context) + start + (if (isa? end ) end #f)))) + +(defslimefun throw-to-toplevel () + (invoke-handler-interactively (find-restart ) in out)) + +(defslimefun invoke-nth-restart-for-emacs (sldb-level| n|) + (when (= (@level sldb-context) sldb-level) + (invoke-handler-interactively (elt (@restarts sldb-context) n) in out))) + +(defslimefun debugger-info-for-emacs (start end) + (debugger-info (@condition sldb-context) + (@restarts sldb-context) + (compute-backtrace (@top-frame sldb-context) + start + (if (isa? end ) end #f)))) + +(defslimefun frame-locals-and-catch-tags (frame-idx) + (def frame (nth-frame frame-idx)) + (list + (map-keyed (fun (i name) + (lst ':name (sym-name name) ':id 0 + ':value (safe-write-to-string (frame-var-value frame i)))) + (frame-var-names frame)) + '())) + +(defslimefun inspect-frame-var (frame-idx var-idx) + (reset-inspector) + (inspect-object (frame-var-value (nth-frame frame-idx) var-idx))) + +(defslimefun inspect-current-condition () + (reset-inspector) + (inspect-object (@condition sldb-context))) + +(defslimefun frame-source-location (frame-idx) + (match (nth-frame frame-idx) + ((,f ,@_) + (or (emacs-src-loc f) + `(:error ,(msg-to-str "No src-loc available for: %s" f)))))) + +(defslimefun eval-string-in-frame (string frame-idx) + (def frame (nth-frame frame-idx)) + (let ((names (frame-var-names frame)) + (values (frame-var-values frame))) + (write-to-string + (app (eval `(fun ,names ,(read-from-string string)) + (module-name (buffer-module))) + values)))) + +(df debugger-info (condition restarts backtrace eval-context) + (lst `(,(try-or (fun () (describe-condition condition)) "<...>") + ,(cat " [class: " (class-name-str condition) "]") + ()) + (restarts-for-emacs restarts) + (backtrace-for-emacs backtrace) + (pending-continuations eval-context))) + +(df backtrace-for-emacs (backtrace) + (map (fun (f) + (match f + ((,idx (,f ,@args)) + (lst idx (cat (if (fun-name f) + (sym-name (fun-name f)) + (safe-write-to-string f)) + (safe-write-to-string args)))))) + backtrace)) + +(df restarts-for-emacs (restarts) + (map (fun (x) `(,(sym-name (class-name (%handler-condition-type x))) + ,(describe-restart x))) + restarts)) + +(df describe-restart (restart) + (describe-handler (%handler-info restart) (%handler-condition-type restart))) + +(df compute-restarts (condition) + (packing (%do-handlers-of-type (fun (c) (pack c))))) + +(df find-restart (type) + (esc ret + (%do-handlers-of-type type ret) + #f)) + +(df pending-continuations (context|(t? )) + (if context + (pair (@id context) (pending-continuations (@prev context))) + '())) + +(df find-top-frame (fname| offset|) + (esc ret + (let ((top-seen? #f)) + (do-stack-frames (fun (f args) + (cond (top-seen? + (cond ((== offset 0) + (ret (pair f args))) + (#t (decf offset)))) + ((== (fun-name f) fname) + (set top-seen? #t)))))))) + +(df compute-backtrace (top-frame start| end) + (packing + (esc break + (do-user-frames (fun (idx f args) + (when (and end (<= end idx)) + (break #f)) + (when (<= start idx) + (pack (lst idx (pair f args))))) + top-frame)))) + +(df nth-frame (n|) + (esc ret + (do-user-frames + (fun (idx f args) + (when (= idx n) + (ret (pair f args)))) + (@top-frame sldb-context)))) + +(df frame-var-value (frame var-idx) + (match frame + ((,f ,@args) + (def sig (fun-sig f)) + (def arity (sig-arity sig)) + (def nary? (sig-nary? sig)) + (cond ((< var-idx arity) (elt args var-idx)) + (nary? (sub* args arity)))))) + +(df frame-var-names (frame) + (match frame + ((,f ,@_) (fun-info-names (fun-info f))))) + +(df frame-var-values (frame) + (map (curry frame-var-value frame) (keys (frame-var-names frame)))) + +(df do-user-frames (f| top-frame) + (let ((idx -1) + (top-seen? #f)) + (do-stack-frames + (fun (ffun args) + (cond (top-seen? + (incf idx) + (f idx ffun (rev args))) + ((= (pair ffun args) top-frame) + (set top-seen? #t))))))) + + +;;;; Write some classes a little less verbose + +;; (dm recurring-write (port| x d| recur|) +;; (msg port "#{%s &%s}" (class-name-str x) +;; (num-to-str-base (address-of x) 16))) + +(dm recurring-write (port| x| d| recur|) + (msg port "#{%s %s}" (class-name-str x) (module-name x))) + +(dm recurring-write (port| x| d| recur|) + (msg port "#{%s %s}" (class-name-str x) (binding-name x))) + +(dm recurring-write (port| x| d| recur|) + (msg port "#{%s %s}" (class-name-str x) (len x))) + +(dm recurring-write (port| x| + d| recur|) + (msg port "#{%s}" (class-name-str x))) + +(dm recurring-write (port| x| + d| recur|) + (msg port "#{%s}" (class-name-str x))) + +(dm recurring-write (port| x| d| recur|) + (msg port "#{%s %s:%=}" (class-name-str x) + (src-loc-file x) (src-loc-line x))) + + +;;;; Inspector + +(dc ()) +(dp! @object ( => )) +(dp! @parts ( => ) (new )) +(dp! @stack ( => ) '()) + +(dv inspector #f) + +(defslimefun init-inspector (form|) + (reset-inspector) + (inspect-object (str-eval form (buffer-module)))) + +(defslimefun quit-inspector () (reset-inspector) 'nil) + +(defslimefun inspect-nth-part (n|) + (inspect-object (elt (@parts inspector) n))) + +(defslimefun inspector-pop () + (cond ((<= 2 (len (@stack inspector))) + (popf (@stack inspector)) + (inspect-object (popf (@stack inspector)))) + (#t 'nil))) + +(df reset-inspector () (set inspector (new ))) + +(df inspect-object (o) + (set (@object inspector) o) + (set (@parts inspector) (new )) + (pushf (@stack inspector) o) + (lst ':title (safe-write-to-string o) ; ':type (class-name-str o) + ':content (inspector-content + `("class: " (:value ,(class-of o)) "\n" + ,@(inspect o))))) + +(df inspector-content (content) + (map (fun (part) + (case-by part isa? + (() part) + (() + (match part + ((:value ,o ,@str) + `(:value ,@(if (nul? str) + (lst (safe-write-to-string o)) + str) + ,(assign-index o))))) + (#t (error "Bad inspector content: %=" part)))) + content)) + +(df assign-index (o) + (pushf (@parts inspector) o) + (1- (len (@parts inspector)))) + +(dg inspect (o)) + +;; a list of dangerous functions +(d. getter-blacklist (lst fun-code fun-env class-row)) + +(dm inspect (o) + (join (map (fun (p) + (let ((getter (prop-getter p))) + `(,(sym-name (fun-name getter)) ": " + ,(cond ((mem? getter-blacklist getter) "<...>") + ((not (prop-bound? o getter)) "") + (#t (try-or (fun () `(:value ,(getter o))) + "<...>")))))) + (class-props (class-of o))) + '("\n"))) + +(dm inspect (o|) + (join (packing (do-keyed (fun (pos val) + (pack `(,(num-to-str pos) ": " (:value ,val)))) + o)) + '("\n"))) + +(dm inspect (o|) + (join (packing (do-keyed (fun (key val) + (pack `((:value ,key) "\t: " (:value ,val)))) + o)) + '("\n"))) + +;; inspecting the env of closures is broken +;; (dm inspect (o|) +;; (cat (sup o) +;; '("\n") +;; (if (%fun-env? o) +;; (inspect (packing (for ((i (below (%fun-env-len o)))) +;; (pack (%fun-env-elt o i))))) +;; '()))) +;; +;; (df %fun-env? (f| => ) #eb{ FUNENV($f) != $#f }) +;; (df %fun-env-len (f| => ) #ei{ ((ENV)FUNENV ($f))->size }) +;; (df %fun-env-elt (f| i| => ) #eg{ FUNENVGET($f, @i) }) + + +;;;; init + +(defslimefun connection-info () + `(:pid + ,(process-id) :style nil + :lisp-implementation (:type "GOO" :name "goo" + :version ,(%lookup '*goo-version* 'eval/main)) + :machine (:instance "" :type "" :version "") + :features () + :package (:name "goo/user" :prompt "goo/user"))) + +(defslimefun quit-lisp () #ei{ exit (0),0 }) + +(defslimefun set-default-directory (dir|) #ei{ chdir(@dir) } dir) + + +;;;; eval + +(defslimefun ping () "PONG") + +(defslimefun create-repl (_) + (let ((name (sym-name (module-name (buffer-module))))) + `(,name ,name))) + +(defslimefun listener-eval (string) + (clear-input in) + `(:values ,(write-to-string (str-eval string (buffer-module))))) + +(defslimefun interactive-eval (string) + (cat "=> " (write-to-string (str-eval string (buffer-module))))) + +(df str-eval (s| m|) + (eval (read-from-string s) (module-name m))) + +(df clear-input (in|) (while (ready? in) (get in))) + +(dc ()) + +(defslimefun simple-break () + (simple-restart + "Continue from break" + (fun () (sig (new + condition-message "Interrupt from Emacs")))) + 'nil) + +(defslimefun clear-repl-results () 'nil) + + +;;;; compile + +(defslimefun compile-string-for-emacs (string buffer position directory) + (def start (current-time)) + (def r (g2c-eval (read-from-string string) + (module-target-environment (buffer-module)))) + (lst (write-to-string r) + (/ (as (- (current-time) start)) 1000000.0))) + +(defslimefun compiler-notes-for-emacs () 'nil) + +(defslimefun filename-to-modulename (filename| => (t+ )) + (try-or (fun () (sym-name (filename-to-modulename filename))) 'nil)) + +(df filename-to-modulename (filename| => ) + (def paths (map pathname-to-components + (map simplify-filename + (pick file-exists? *module-search-path*)))) + (def filename (pathname-to-components filename)) + (def moddir (rep parent ((modpath filename)) + (cond ((any? (curry = modpath) paths) + modpath) + (#t + (parent (components-parent-directory modpath)))))) + (def modfile (components-to-pathname (sub* filename (len moddir)))) + (as-sym (sub modfile 0 (- (len modfile) (len *goo-extension*))))) + + + +;;;; Load + +(defslimefun load-file (filename) + (let ((file (cond ((= (sub (rev filename) 0 4) "oog.") filename) + (#t (cat filename ".goo"))))) + (safe-write-to-string (load-file file (filename-to-modulename file))))) + + +;;;; background activities + +(defslimefun operator-arglist (op _) + (try-or (fun () + (let ((value (str-eval op (buffer-module)))) + (if (isa? value ) + (write-to-string value) + 'nil))) + 'nil)) + + +;;;; M-. + +(defslimefun find-definitions-for-emacs (name|) + (match (parse-symbol name) + ((,sym ,modname) + (def env (module-target-environment (runtime-module modname))) + (def b (find-binding sym env)) + (cond (b (find-binding-definitions b)) + (#t 'nil))))) + +(df parse-symbol (name| => ) + (if (mem? name #\:) + (match (split name #\:) + ((,module ,name) (lst (as-sym name) (as-sym module)))) + (lst (as-sym name) (module-name (buffer-module))))) + +(df find-binding-definitions (b|) + (def value (case (binding-kind b) + (('runtime) (loc-val (binding-locative b))) + (('global) (let ((box (binding-global-box b))) + (and box (global-box-value box)))) + (('macro) (binding-info b)) + (#t (error "unknown binding kind %=" (binding-kind b))))) + (map (fun (o) + (def loc (emacs-src-loc o)) + `(,(write-to-string (dspec o)) + ,(or loc `(:error "no src-loc available")))) + (defining-objects value))) + +(dm defining-objects (o => ) '()) +(dm defining-objects (o| => ) (lst o)) +(dm defining-objects (o| => ) (pair o (fun-mets o))) + +(dm emacs-src-loc (o|) + (def loc (fun-src-loc o)) + (and loc `(:location (:file ,(simplify-filename + (find-goo-file-in-path + (module-name-to-relpath (src-loc-file loc)) + *module-search-path*))) + (:line ,(src-loc-line loc)) + ()))) + +(dm dspec (f|) + (cond ((fun-name f) + `(,(if (isa? f ) 'dg 'dm) ,(fun-name f) ,@(dspec-arglist f))) + (#t f))) + +(df dspec-arglist (f|) + (map2 (fun (name class) + (cond ((= class ) name) + ((isa? class ) + `(,name ,(class-name class))) + (#t `(,name ,class)))) + (fun-info-names (fun-info f)) + (sig-specs (fun-sig f)))) + +(defslimefun buffer-first-change (filename) 'nil) + + +;;;; apropos + +(defslimefun apropos-list-for-emacs + (pattern only-external? case-sensitive? package) + (def matches (fab 100)) + (do-all-bindings + (fun (b) + (when (finds (binding-name-str b) pattern) + (set (elt matches + (cat-sym (binding-name b) + (module-name (binding-module b)))) + b)))) + (set matches (sort-by (packing-as (for ((b matches)) (pack b))) + (fun (x y) + (< (binding-name x) + (binding-name y))))) + (map (fun (b) + `(:designator + ,(cat (sym-name (module-name (binding-module b))) ":" + (binding-name-str b) + "\tkind: " (sym-name (binding-kind b))))) + (as matches))) + +(df do-all-bindings (f|) + (for ((module (%module-loader-modules (runtime-module-loader)))) + (do f (environment-bindings (module-target-environment module))))) + +(dm < (s1| s2| => ) + (let ((l1 (len s1)) (l2 (len s2))) + (rep loop ((i 0)) + (cond ((= i l1) (~= l1 l2)) + ((= i l2) #f) + ((< (elt s1 i) (elt s2 i)) #t) + ((= (elt s1 i) (elt s2 i)) (loop (1+ i))) + (#t #f))))) + +(df %binding-info (name| module|) + (binding-info + (find-binding + name (module-target-environment (runtime-module module))))) + + +;;;; completion + +(defslimefun simple-completions (pattern| package) + (def matches (lst)) + (for ((b (environment-bindings (module-target-environment (buffer-module))))) + (when (prefix? (binding-name-str b) pattern) + (pushf matches b))) + (def strings (map binding-name-str matches)) + `(,strings ,(cond ((nul? strings) pattern) + (#t (fold+ common-prefix strings))))) + +(df common-prefix (s1| s2|) + (let ((limit (min (len s1) (len s2)))) + (rep loop ((i 0)) + (cond ((or (= i limit) + (~= (elt s1 i) (elt s2 i))) + (sub s1 0 i)) + (#t (loop (1+ i))))))) + +(defslimefun list-all-package-names (_|...) + (map sym-name (keys (all-modules)))) + +(df all-modules () (%module-loader-modules (runtime-module-loader))) + + +;;;; Macroexpand + +(defslimefun swank-macroexpand-1 (str|) + (write-to-string + (%ast-macro-expand (read-from-string str) + (module-target-environment (buffer-module)) + #f))) + + +;;;; streams + +(dc ()) +(dp @socket ( => )) +(dp! @buf-len ( => ) 0) +(dp @buf ( => ) (new )) +(dp! @timestamp ( => ) 0) + +(dm recurring-write (port| x| d| recur|) + (msg port "#{%s buf-len: %s}" (class-name-str x) (@buf-len x))) + +(dm put (p| c|) + (add! (@buf p) c) + (incf (@buf-len p)) + (maybe-flush p (= c #\newline))) + +(dm puts (p| s|) + (add! (@buf p) s) + (incf (@buf-len p) (len s)) + (maybe-flush p (mem? s #\newline))) + +(df maybe-flush (p| newline?|) + (and (or (> (@buf-len p) 4000) newline?) + (> (- (current-time) (@timestamp p)) 100000) + (force-out p))) + +(dm force-out (p|) + (unless (zero? (@buf-len p)) + (dispatch-event `(:write-string ,(%buf-to-str (@buf p))) (@socket p)) + (set (@buf-len p) 0) + (zap! (@buf p))) + (set (@timestamp p) (current-time))) + +(df %buf-to-str (buf|) + (packing-as + (for ((i buf)) + (cond ((isa? i ) (for ((c i)) (pack c))) + (#t (pack i)))))) + +(dc ()) +(dp @socket ( => )) +(dp! @idx ( => ) 0) +(dp! @buf ( => ) "") + +(df receive-input (p|) + (dispatch-event `(:read-string ,0) (@socket p))) + +(dm get (p| => ) + (cond ((< (@idx p) (len (@buf p))) + (def c (elt (@buf p) (@idx p))) + (incf (@idx p)) + c) + (#t + (def input (receive-input p)) + (cond ((zero? (len input)) (eof-object)) + (#t (set (@buf p) input) + (set (@idx p) 0) + (get p)))))) + +(dm ready? (p| => ) (< (@idx p) (len (@buf p)))) + +(dm peek (p| => ) + (let ((c (get p))) + (unless (eof-object? c) + (decf (@idx p))) + c)) + + +;;;; Message encoding + +(df decode-message (port|) + (read-from-string (get-block port (read-message-length port)))) + +(df read-message-length (port) + (or (str-to-num (cat "#x" (get-block port 6))) + (error "can't parse message length"))) + +(df encode-message (message port) + (let ((string (dlet ((*max-print-length* 1000000) + (*max-print-depth* 1000000)) + (write-to-string message)))) + (puts port (encode-message-length (len string))) + (puts port string) + (force-out port))) + +(df encode-message-length (n) + (loc ((hex (byte) + (if (< byte #x10) + (cat "0" (num-to-str-base byte 16)) + (num-to-str-base byte 16))) + (byte (i) (hex (& (>> n (* i 8)) 255)))) + (cat (byte 2) (byte 1) (byte 0)))) + + +;;;; semi general utilities + +;; Return the name of O's class as string. +(df class-name-str (o => ) (sym-name (class-name (class-of o)))) + +(df binding-name-str (b| => ) (sym-name (binding-name b))) + +(df as-sym (str|) (as str)) + +;; Replace '//' in the middle of a filename with with a '/' +(df simplify-filename (str| => ) + (match (pathname-to-components str) + ((,hd ,@tl) + (components-to-pathname (cons hd (del-vals tl 'root)))))) + +;; Execute BODY and only if BODY exits abnormally execute RECOVER. +(df try-recover (body recover) + (let ((ok #f)) + (fin (let ((val (body))) + (set ok #t) + val) + (unless ok + (recover))))) + +;; like CL's IGNORE-ERRORS but return VALUE in case of an error. +(df try-or (body| value) + (esc ret + (try (fun (condition resume) (ret value)) + (body)))) + +(df simple-restart (type msg body) + (esc restart + (try ((type type) (description msg)) + (fun (c r) (restart #f)) + (body)))) + +(df safe-write-to-string (o) + (esc ret + (try (fun (c r) + (ret (cat "#"))) + (write-to-string o)))) + +;; Read a string of length COUNT. +(df get-block (port| count| => ) + (packing-as + (for ((i (below count))) + (let ((c (get port))) + (cond ((eof-object? c) + (error "Premature EOF (read %d of %d)" i count)) + (#t (pack c))))))) + + +;;;; import some internal bindings + +(df %lookup (name| module|) + (loc-val + (binding-locative + (find-binding + name (module-target-environment (runtime-module module)))))) + +(d. %handler-info (%lookup 'handler-info 'goo/conditions)) +(d. %handler-condition-type (%lookup 'handler-condition-type 'goo/conditions)) +(d. %do-handlers-of-type (%lookup 'do-handlers-of-type 'goo/conditions)) +(d. %module-loader-modules (%lookup 'module-loader-modules 'eval/module)) +(d. %ast-macro-expand (%lookup 'ast-macro-expand 'eval/ast)) + + +;;;; low level socket stuff +;;; this shouldn't be here + +#{ +#include +#include +#include +#include +#include +#include +#include + +/* convert a goo number to a C long */ +static long g2i (P o) { return untag (o); } + +static int +set_reuse_address (int socket, int value) { + return setsockopt (socket, SOL_SOCKET, SO_REUSEADDR, &value, sizeof value); +} + +static int +bind_socket (int socket, int port) { + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons (port); + addr.sin_addr.s_addr = htonl (INADDR_ANY); + return bind (socket, (struct sockaddr *)&addr, sizeof addr); +} + +static int +local_port (int socket) { + struct sockaddr_in addr; + socklen_t len = sizeof addr; + int code = getsockname (socket, (struct sockaddr *)&addr, &len); + return (code == -1) ? -1 : ntohs (addr.sin_port); +} + +static int +c_accept (int socket) { + struct sockaddr_in addr; + socklen_t len = sizeof addr; + return accept (socket, (struct sockaddr *)&addr, &len); +} + +static P tup3 (P e0, P e1, P e2) { + P tup = YPPtfab ((P)3, YPfalse); + YPtelt_setter (e0, tup, (P)0); + YPtelt_setter (e1, tup, (P)1); + YPtelt_setter (e2, tup, (P)2); + return tup; +} + +static P +current_time (void) { + struct timeval timeval; + int code = gettimeofday (&timeval, NULL); + if (code == 0) { + return tup3 (YPib ((P)(timeval.tv_sec >> 24)), + YPib ((P)(timeval.tv_sec & 0xffffff)), + YPib ((P)(timeval.tv_usec))); + } else return YPib ((P)errno); +} +} + +;; Return the current time in microsecs +(df current-time (=> ) + (def t #eg{ current_time () }) + (cond ((isa? t ) (error "%s" (strerror t))) + (#t (+ (* (+ (<< (1st t) 24) + (2nd t)) + 1000000) + (3rd t))))) + +(dm strerror (e| => ) #es{ strerror (g2i ($e)) }) +(dm strerror (e|(t= #f) => ) #es{ strerror (errno) }) + +(df checkr (value|) + (cond ((~== value -1) value) + (#t (error "%s" (strerror #f))))) + +(df create-socket (port| => ) + (let ((socket (checkr #ei{ socket (PF_INET, SOCK_STREAM, 0) }))) + (checkr #ei{ set_reuse_address (g2i ($socket), 1) }) + (checkr #ei{ bind_socket (g2i ($socket), g2i ($port)) }) + (checkr #ei{ listen (g2i ($socket), 1)}) + socket)) + +(df %local-port (fd|) (checkr #ei{ local_port (g2i ($fd)) })) +(df %close (fd|) (checkr #ei{ close (g2i ($fd)) })) + +(dc ( )) +(dp @fd ( => )) +(dp @in ( => )) +(dp @out ( => )) + +(dm recurring-write (port| x| d| recur|) + (msg port "#{%s fd: %s}" (class-name-str x) (@fd x))) + +(dm get (port| => ) (get (@in port))) + +(dm puts (port| s|) (puts (@out port) s)) +(dm force-out (port|) (force-out (@out port))) + +(dm fdopen (fd| type|(t= ) => ) + (new @fd fd + @in (new port-handle (%fdopen fd "r")) + @out (new port-handle (%fdopen fd "w")))) + +(df %fdopen (fd| mode| => ) + (def addr #ei{ fdopen (g2i ($fd), @mode) }) + (when (zero? addr) + (error "fdopen failed: %s" (strerror #f))) + (%lb (%iu addr))) + +(df accept (socket| => ) + (fdopen (checkr #ei{ c_accept (g2i ($socket)) }) )) + +(export + start-swank + create-server) + +;;; swank-goo.goo ends here \ No newline at end of file diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-hyperdoc.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-hyperdoc.lisp new file mode 100644 index 0000000..1e34a1d --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-hyperdoc.lisp @@ -0,0 +1,18 @@ +(in-package :swank) + +(defslimefun hyperdoc (string) + (let ((hyperdoc-package (find-package :hyperdoc))) + (when hyperdoc-package + (multiple-value-bind (symbol foundp symbol-name package) + (parse-symbol string *buffer-package*) + (declare (ignore symbol)) + (when foundp + (funcall (find-symbol (string :lookup) hyperdoc-package) + (package-name (if (member package (cons *buffer-package* + (package-use-list + *buffer-package*))) + *buffer-package* + package)) + symbol-name)))))) + +(provide :swank-hyperdoc) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-ikarus.ss b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-ikarus.ss new file mode 100644 index 0000000..e048446 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-ikarus.ss @@ -0,0 +1,86 @@ +;; swank-larceny.scm --- Swank server for Ikarus +;; +;; License: Public Domain +;; Author: Helmut Eller +;; +;; In a shell execute: +;; ikarus swank-ikarus.ss +;; and then `M-x slime-connect' in Emacs. +;; + +(library (swank os) + (export getpid make-server-socket accept local-port close-socket) + (import (rnrs) + (only (ikarus foreign) make-c-callout dlsym dlopen + pointer-set-c-long! pointer-ref-c-unsigned-short + malloc free pointer-size) + (rename (only (ikarus ipc) tcp-server-socket accept-connection + close-tcp-server-socket) + (tcp-server-socket make-server-socket) + (close-tcp-server-socket close-socket)) + (only (ikarus) + struct-type-descriptor + struct-type-field-names + struct-field-accessor) + ) + + (define libc (dlopen)) + (define (cfun name return-type arg-types) + ((make-c-callout return-type arg-types) (dlsym libc name))) + + (define getpid (cfun "getpid" 'signed-int '())) + + (define (accept socket codec) + (let-values (((in out) (accept-connection socket))) + (values (transcoded-port in (make-transcoder codec)) + (transcoded-port out (make-transcoder codec))))) + + (define (socket-fd socket) + (let ((rtd (struct-type-descriptor socket))) + (do ((i 0 (+ i 1)) + (names (struct-type-field-names rtd) (cdr names))) + ((eq? (car names) 'fd) ((struct-field-accessor rtd i) socket))))) + + (define sockaddr_in/size 16) + (define sockaddr_in/sin_family 0) + (define sockaddr_in/sin_port 2) + (define sockaddr_in/sin_addr 4) + + (define (local-port socket) + (let* ((fd (socket-fd socket)) + (addr (malloc sockaddr_in/size)) + (size (malloc (pointer-size)))) + (pointer-set-c-long! size 0 sockaddr_in/size) + (let ((code (getsockname fd addr size)) + (port (ntohs (pointer-ref-c-unsigned-short + addr sockaddr_in/sin_port)))) + (free addr) + (free size) + (cond ((= code -1) (error "getsockname failed")) + (#t port))))) + + (define getsockname + (cfun "getsockname" 'signed-int '(signed-int pointer pointer))) + + (define ntohs (cfun "ntohs" 'unsigned-short '(unsigned-short))) + + ) + + +(library (swank sys) + (export implementation-name eval-in-interaction-environment) + (import (rnrs) + (rnrs eval) + (only (ikarus) interaction-environment)) + + (define (implementation-name) "ikarus") + + (define (eval-in-interaction-environment form) + (eval form (interaction-environment))) + + ) + +(import (only (ikarus) load)) +(load "swank-r6rs.scm") +(import (swank)) +(start-server #f) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-indentation.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-indentation.lisp new file mode 100644 index 0000000..67e638d --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-indentation.lisp @@ -0,0 +1,140 @@ +(in-package :swank) + +(defvar *application-hints-tables* '() + "A list of hash tables mapping symbols to indentation hints (lists +of symbols and numbers as per cl-indent.el). Applications can add hash +tables to the list to change the auto indentation slime sends to +emacs.") + +(defun has-application-indentation-hint-p (symbol) + (let ((default (load-time-value (gensym)))) + (dolist (table *application-hints-tables*) + (let ((indentation (gethash symbol table default))) + (unless (eq default indentation) + (return-from has-application-indentation-hint-p + (values indentation t)))))) + (values nil nil)) + +(defun application-indentation-hint (symbol) + (let ((indentation (has-application-indentation-hint-p symbol))) + (labels ((walk (indentation-spec) + (etypecase indentation-spec + (null nil) + (number indentation-spec) + (symbol (string-downcase indentation-spec)) + (cons (cons (walk (car indentation-spec)) + (walk (cdr indentation-spec))))))) + (walk indentation)))) + +;;; override swank version of this function +(defun symbol-indentation (symbol) + "Return a form describing the indentation of SYMBOL. + +The form is to be used as the `common-lisp-indent-function' property +in Emacs." + (cond + ((has-application-indentation-hint-p symbol) + (application-indentation-hint symbol)) + ((and (macro-function symbol) + (not (known-to-emacs-p symbol))) + (let ((arglist (arglist symbol))) + (etypecase arglist + ((member :not-available) + nil) + (list + (macro-indentation arglist))))) + (t nil))) + +;;; More complex version. +(defun macro-indentation (arglist) + (labels ((frob (list &optional base) + (if (every (lambda (x) + (member x '(nil "&rest") :test #'equal)) + list) + ;; If there was nothing interesting, don't return anything. + nil + ;; Otherwise substitute leading NIL's with 4 or 1. + (let ((ok t)) + (substitute-if (if base + 4 + 1) + (lambda (x) + (if (and ok (not x)) + t + (setf ok nil))) + list)))) + (walk (list level &optional firstp) + (when (consp list) + (let ((head (car list))) + (if (consp head) + (let ((indent (frob (walk head (+ level 1) t)))) + (cons (list* "&whole" (if (zerop level) + 4 + 1) + indent) (walk (cdr list) level))) + (case head + ;; &BODY is &BODY, this is clear. + (&body + '("&body")) + ;; &KEY is tricksy. If it's at the base level, we want + ;; to indent them normally: + ;; + ;; (foo bar quux + ;; :quux t + ;; :zot nil) + ;; + ;; If it's at a destructuring level, we want indent of 1: + ;; + ;; (with-foo (var arg + ;; :foo t + ;; :quux nil) + ;; ...) + (&key + (if (zerop level) + '("&rest" nil) + '("&rest" 1))) + ;; &REST is tricksy. If it's at the front of + ;; destructuring, we want to indent by 1, otherwise + ;; normally: + ;; + ;; (foo (bar quux + ;; zot) + ;; ...) + ;; + ;; but + ;; + ;; (foo bar quux + ;; zot) + (&rest + (if (and (plusp level) firstp) + '("&rest" 1) + '("&rest" nil))) + ;; &WHOLE and &ENVIRONMENT are skipped as if they weren't there + ;; at all. + ((&whole &environment) + (walk (cddr list) level firstp)) + ;; &OPTIONAL is indented normally -- and the &OPTIONAL marker + ;; itself is not counted. + (&optional + (walk (cdr list) level)) + ;; Indent normally, walk the tail -- but + ;; unknown lambda-list keywords terminate the walk. + (otherwise + (unless (member head lambda-list-keywords) + (cons nil (walk (cdr list) level)))))))))) + (frob (walk arglist 0 t) t))) + +#+nil +(progn + (assert (equal '(4 4 ("&whole" 4 "&rest" 1) "&body") + (macro-indentation '(bar quux (&rest slots) &body body)))) + (assert (equal nil + (macro-indentation '(a b c &rest more)))) + (assert (equal '(4 4 4 "&body") + (macro-indentation '(a b c &body more)))) + (assert (equal '(("&whole" 4 1 1 "&rest" 1) "&body") + (macro-indentation '((name zot &key foo bar) &body body)))) + (assert (equal nil + (macro-indentation '(x y &key z))))) + +(provide :swank-indentation) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-jolt.k b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-jolt.k new file mode 100644 index 0000000..93e53ab --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-jolt.k @@ -0,0 +1,998 @@ +;;; swank-jolt.k --- Swank server for Jolt -*- goo -*- +;; +;; Copyright (C) 2008 Helmut Eller +;; +;; This file is licensed under the terms of the GNU General Public +;; License as distributed with Emacs (press C-h C-c for details). + +;;; Commentary: +;; +;; Jolt/Coke is a Lisp-like language wich operates at the semantic level of +;; C, i.e. most objects are machine words and memory pointers. The +;; standard boot files define an interface to Id Smalltalk. So we can +;; also pretend to do OOP, but we must be careful to pass properly +;; tagged pointers to Smalltalk. +;; +;; This file only implements a minimum of SLIME's functionality. We +;; install a handler with atexit(3) to invoke the debugger. This way +;; we can stop Jolt from terminating the process on every error. +;; Unfortunately, the backtrace doesn't contain much information and +;; we also have no error message (other than the exit code). Jolt +;; usually prints some message to stdout before calling exit, so you +;; have to look in the *inferior-lisp* buffer for hints. We do +;; nothing (yet) to recover from SIGSEGV. + +;;; Installation +;; +;; 1. Download and build cola. See . +;; I used the svn version: +;; svn co http://piumarta.com/svn2/idst/trunk idst +;; 2. Add something like this to your .emacs: +;; +;; (add-to-list 'slime-lisp-implementations +;; '(jolt (".../idst/function/jolt-burg/main" +;; "boot.k" ".../swank-jolt.k" "-") ; note the "-" +;; :init jolt-slime-init +;; :init-function slime-redirect-inferior-output) +;; (defun jolt-slime-init (file _) (format "%S\n" `(start-swank ,file))) +;; (defun jolt () (interactive) (slime 'jolt)) +;; +;; 3. Use `M-x jolt' to start it. +;; + +;;; Code + +;; In this file I use 2-3 letters for often used names, like DF or +;; VEC, even if those names are abbreviations. I think that after a +;; little getting used to, this style is just as readable as the more +;; traditional DEFUN and VECTOR. Shorter names make it easier to +;; write terse code, in particular 1-line definitions. + +;; `df' is like `defun' in a traditional lisp +(syntax df + (lambda (form compiler) + (printf "df %s ...\n" [[[form second] asString] _stringValue]) + `(define ,[form second] (lambda ,@[form copyFrom: '2])))) + +;; (! args ...) is the same as [args ...] but easier to edit. +(syntax ! + (lambda (form compiler) + (cond ((== [form size] '3) + (if [[form third] isSymbol] + `(send ',[form third] ,[form second]) + [compiler errorSyntax: [form third]])) + ((and [[form size] > '3] + (== [[form size] \\ '2] '0)) + (let ((args [OrderedCollection new]) + (keys [OrderedCollection new]) + (i '2) (len [form size])) + (while (< i len) + (let ((key [form at: i])) + (if (or [key isKeyword] + (and (== i '2) [key isSymbol])) ; for [X + Y] + [keys addLast: [key asString]] + [compiler errorSyntax: key])) + [args addLast: [form at: [i + '1]]] + (set i [i + '2])) + `(send ',[[keys concatenated] asSymbol] ,[form second] ,@args))) + (1 [compiler errorArgumentCount: form])))) + +(define Integer (import "Integer")) +(define Symbol (import "Symbol")) ;; aka. _selector +(define StaticBlockClosure (import "StaticBlockClosure")) +(define BlockClosure (import "BlockClosure")) +(define SequenceableCollection (import "SequenceableCollection")) +(define _vtable (import "_vtable")) +(define ByteArray (import "ByteArray")) +(define CodeGenerator (import "CodeGenerator")) +(define TheGlobalEnvironment (import "TheGlobalEnvironment")) + +(df error (msg) (! Object error: msg)) +(df print-to-string (obj) + (let ((len '200) + (stream (! WriteStream on: (! String new: len)))) + (! stream print: obj) + (! stream contents))) +(df assertion-failed (exp) + (error (! '"Assertion failed: " , (print-to-string exp)))) + +(syntax assert + (lambda (form) + `(if (not ,(! form second)) + (assertion-failed ',(! form second))))) + +(df isa? (obj type) (! obj isKindOf: type)) +(df equal (o1 o2) (! o1 = o2)) + +(define nil 0) +(define false 0) +(define true (! Object notNil)) +(df bool? (obj) (or (== obj false) (== obj true))) +(df int? (obj) (isa? obj Integer)) + +;; In this file the convention X>Y is used for operations that convert +;; X-to-Y. And _ means "machine word". So _>int is the operator that +;; converts a machine word to an Integer. + +(df _>int (word) (! Integer value_: word)) +(df int>_ (i) (! i _integerValue)) + +;; Fixnum operators. Manual tagging/untagging would probably be more +;; efficent than invoking methods. + +(df fix? (obj) (& obj 1)) +(df _>fix (n) (! SmallInteger value_: n)) +(df fix>_ (i) (! i _integerValue)) +(df fx+ (fx1 fx2) (! fx1 + fx2)) +(df fx* (fx1 fx2) (! fx1 * fx2)) +(df fx1+ (fx) (! fx + '1)) +(df fx1- (fx) (! fx - '1)) + +(df str? (obj) (isa? obj String)) +(df >str (o) (! o asString)) +(df str>_ (s) (! s _stringValue)) +(df _>str (s) (! String value_: s)) +(df sym? (obj) (isa? obj Symbol)) +(df seq? (obj) (isa? obj SequenceableCollection)) +(df array? (obj) (isa? obj Array)) +(df len (obj) (! obj size)) +(df len_ (obj) (! (! obj size) _integerValue)) +(df ref (obj idx) (! obj at: idx)) +(df set-ref (obj idx elt) (! obj at: idx put: elt)) +(df first (obj) (! obj first)) +(df second (obj) (! obj second)) + +(df puts (string stream) (! stream nextPutAll: string)) + +(define _GC_base (dlsym "GC_base")) + +;; Is ADDR a pointer to a heap allocated object? The Boehm GC nows +;; such things. This is useful for debugging, because we can quite +;; safely (i.e. without provoking SIGSEGV) access such addresses. +(df valid-pointer? (addr) + (let ((ptr (& addr (~ 1)))) + (and (_GC_base ptr) + (_GC_base (long@ ptr -1))))) + +;; Print OBJ as a Lisp printer would do. +(df prin1 (obj stream) + (cond ((fix? obj) (! stream print: obj)) + ((== obj nil) (puts '"nil" stream)) + ((== obj false) (puts '"#f" stream)) + ((== obj true) (puts '"#t" stream)) + ((not (valid-pointer? obj)) + (begin (puts '"#int obj) stream) + (puts '">" stream))) + ((int? obj) (! stream print: obj)) + ((sym? obj) (puts (>str obj) stream)) + ((isa? obj StaticBlockClosure) + (begin (puts '"#" stream))) + ((and (str? obj) (len obj)) + (! obj printEscapedOn: stream delimited: (ref '"\"" '0))) + ((and (array? obj) (len obj)) + (begin (puts '"(" stream) + (let ((max (- (len_ obj) 1))) + (for (i 0 1 max) + (prin1 (ref obj (_>fix i)) stream) + (if (!= i max) + (puts '" " stream)))) + (puts '")" stream))) + ((and (isa? obj OrderedCollection) (len obj)) + (begin (puts '"#[" stream) + (let ((max (- (len_ obj) 1))) + (for (i 0 1 max) + (prin1 (ref obj (_>fix i)) stream) + (if (!= i max) + (puts '" " stream)))) + (puts '"]" stream))) + (true + (begin (puts '"#<" stream) + (puts (! obj debugName) stream) + (puts '">" stream)))) + obj) + +(df print (obj) + (prin1 obj StdOut) + (puts '"\n" StdOut)) + +(df prin1-to-string (obj) + (let ((len '100) + (stream (! WriteStream on: (! String new: len)))) + (prin1 obj stream) + (! stream contents))) + +;;(df %vable-tally (_vtable) (long@ _vtable)) +(df cr () (printf "\n")) +(df print-object-selectors (obj) + (let ((vtable (! obj _vtable)) + (tally (long@ vtable 0)) + (bindings (long@ vtable 1))) + (for (i 1 1 tally) + (print (long@ (long@ bindings i))) + (cr)))) + +(df print-object-slots (obj) + (let ((size (! obj _sizeof)) + (end (+ obj size))) + (while (< obj end) + (print (long@ obj)) + (cr) + (incr obj 4)))) + +(df intern (string) (! Symbol intern: string)) + +;; Jolt doesn't seem to have an equivalent for gensym, but it's damn +;; hard to write macros without it. So here we adopt the conventions +;; that symbols which look like ".[0-9]+" are reserved for gensym and +;; shouldn't be used for "user visible variables". +(define gensym-counter 0) +(df gensym () + (set gensym-counter (+ gensym-counter 1)) + (intern (! '"." , (>str (_>fix gensym-counter))))) + +;; Surprisingly, SequenceableCollection doesn't have a indexOf method. +;; So we even need to implement such mundane things. +(df index-of (seq elt) + (let ((max (len seq)) + (i '0)) + (while (! i < max) + (if (equal (ref seq i) elt) + (return i) + (set i (! i + '1)))) + nil)) + +(df find-dot (array) (index-of array '.)) + +;; What followes is the implementation of the pattern matching macro MIF. +;; The syntax is (mif (PATTERN EXP) THEN ELSE). +;; The THEN-branch is executed if PATTERN matches the value produced by EXP. +;; ELSE gets only executed if the match failes. +;; A pattern can be +;; 1) a symbol, which matches all values, but also binds the variable to the +;; value +;; 2) (quote LITERAL), matches if the value is `equal' to LITERAL. +;; 3) (PS ...) matches sequences, if the elements match PS. +;; 4) (P1 ... Pn . Ptail) matches if P1 ... Pn match the respective elements +;; at indices 1..n and if Ptail matches the rest +;; of the sequence +;; Examples: +;; (mif (x 10) x 'else) => 10 +;; (mif ('a 'a) 'then 'else) => then +;; (mif ('a 'b) 'then 'else) => else +;; (mif ((a b) '(1 2)) b 'else) => 2 +;; (mif ((a . b) '(1 2)) b 'else) => '(2) +;; (mif ((. x) '(1 2)) x 'else) => '(1 2) + +(define mif% 0) ;; defer +(df mif%array (compiler pattern i value then fail) + ;;(print `(mif%array ,pattern ,i ,value)) + (cond ((== i (len_ pattern)) then) + ((== (ref pattern (_>fix i)) '.) + (begin + (if (!= (- (len_ pattern) 2) i) + (begin + (print pattern) + (! compiler error: (! '"dot in strange position: " + , (>str (_>fix i)))))) + (mif% compiler + (ref pattern (_>fix (+ i 1))) + `(! ,value copyFrom: ',(_>fix i)) + then fail))) + (true + (mif% compiler + (ref pattern (_>fix i)) + `(ref ,value ',(_>fix i)) + (mif%array compiler pattern (+ i 1) value then fail) + fail)))) + +(df mif% (compiler pattern value then fail) + ;;(print `(mif% ,pattern ,value ,then)) + (cond ((== pattern '_) then) + ((== pattern '.) (! compiler errorSyntax: pattern)) + ((sym? pattern) + `(let ((,pattern ,value)) ,then)) + ((seq? pattern) + (cond ((== (len_ pattern) 0) + `(if (== (len_ ,value) 0) ,then (goto ,fail))) + ((== (first pattern) 'quote) + (begin + (if (not (== (len_ pattern) 2)) + (! compiler errorSyntax: pattern)) + `(if (equal ,value ,pattern) ,then (goto ,fail)))) + (true + (let ((tmp (gensym)) (tmp2 (gensym)) + (pos (find-dot pattern))) + `(let ((,tmp2 ,value) + (,tmp ,tmp2)) + (if (and (seq? ,tmp) + ,(if (find-dot pattern) + `(>= (len ,tmp) + ',(_>fix (- (len_ pattern) 2))) + `(== (len ,tmp) ',(len pattern)))) + ,(mif%array compiler pattern 0 tmp then fail) + (goto ,fail))))))) + (true (! compiler errorSyntax: pattern)))) + +(syntax mif + (lambda (node compiler) + ;;(print `(mif ,node)) + (if (not (or (== (len_ node) 4) + (== (len_ node) 3))) + (! compiler errorArgumentCount: node)) + (if (not (and (array? (ref node '1)) + (== (len_ (ref node '1)) 2))) + (! compiler errorSyntax: (ref node '1))) + (let ((pattern (first (ref node '1))) + (value (second (ref node '1))) + (then (ref node '2)) + (else (if (== (len_ node) 4) + (ref node '3) + `(error "mif failed"))) + (destination (gensym)) + (fail (! compiler newLabel)) + (success (! compiler newLabel))) + `(let ((,destination 0)) + ,(mif% compiler pattern value + `(begin (set ,destination ,then) + (goto ,success)) + fail) + (label ,fail) + (set ,destination ,else) + (label ,success) + ,destination)))) + +;; (define *catch-stack* nil) +;; +(df bar (o) (mif ('a o) 'yes 'no)) +(assert (== (bar 'a) 'yes)) +(assert (== (bar 'b) 'no)) +(df foo (o) (mif (('a) o) 'yes 'no)) +(assert (== (foo '(a)) 'yes)) +(assert (== (foo '(b)) 'no)) +(df baz (o) (mif (('a 'b) o) 'yes 'no)) +(assert (== (baz '(a b)) 'yes)) +(assert (== (baz '(a c)) 'no)) +(assert (== (baz '(b c)) 'no)) +(assert (== (baz 'a) 'no)) +(df mifvar (o) (mif (y o) y 'no)) +(assert (== (mifvar 'foo) 'foo)) +(df mifvec (o) (mif ((y) o) y 'no)) +(assert (== (mifvec '(a)) 'a)) +(assert (== (mifvec 'x) 'no)) +(df mifvec2 (o) (mif (('a y) o) y 'no)) +(assert (== (mifvec2 '(a b)) 'b)) +(assert (== (mifvec2 '(b c)) 'no)) +(assert (== (mif ((x) '(a)) x 'no) 'a)) +(assert (== (mif ((x . y) '(a b)) x 'no) 'a)) +(assert (== (mif ((x y . z) '(a b)) y 'no) 'b)) +(assert (equal (mif ((x . y) '(a b)) y 'no) '(b))) +(assert (equal (mif ((. x) '(a b)) x 'no) '(a b))) +(assert (equal (mif (((. x)) '((a b))) x 'no) '(a b))) +(assert (equal (mif (((. x) . y) '((a b) c)) y 'no) '(c))) +(assert (== (mif (() '()) 'yes 'no) 'yes)) +(assert (== (mif (() '(a)) 'yes 'no) 'no)) + +;; Now that we have a somewhat convenient pattern matcher we can write +;; a more convenient macro defining macro: +(syntax defmacro + (lambda (node compiler) + (mif (('defmacro name (. args) . body) node) + (begin + (printf "defmacro %s ...\n" (str>_ (>str name))) + `(syntax ,name + (lambda (node compiler) + (mif ((',name ,@args) node) + (begin ,@body) + (! compiler errorSyntax: node))))) + (! compiler errorSyntax: node)))) + +;; and an even more convenient pattern matcher: +(defmacro mcase (value . clauses) + (let ((tmp (gensym))) + `(let ((,tmp ,value)) + ,(mif (() clauses) + `(begin (print ,tmp) + (error "mcase failed")) + (mif (((pattern . body) . more) clauses) + `(mif (,pattern ,tmp) + (begin ,@(mif (() body) '(0) body)) + (mcase ,tmp ,@more)) + (! compiler errorSyntax: clauses)))))) + +;; and some traditional macros +(defmacro when (test . body) `(if ,test (begin ,@body))) +(defmacro unless (test . body) `(if ,test 0 (begin ,@body))) +(defmacro or (. args) ; the built in OR returns 1 on success. + (mcase args + (() 0) + ((e) e) + ((e1 . more) + (let ((tmp (gensym))) + `(let ((,tmp ,e1)) + (if ,tmp ,tmp (or ,@more))))))) + +(defmacro dotimes_ ((var n) . body) + (let ((tmp (gensym))) + `(let ((,tmp ,n) + (,var 0)) + (while (< ,var ,tmp) + ,@body + (set ,var (+ ,var 1)))))) + +(defmacro dotimes ((var n) . body) + (let ((tmp (gensym))) + `(let ((,tmp ,n) + (,var '0)) + (while (< ,var ,tmp) + ,@body + (set ,var (fx1+ ,var)))))) + +;; DOVEC is like the traditional DOLIST but works on "vectors" +;; i.e. sequences which can be indexed efficently. +(defmacro dovec ((var seq) . body) + (let ((i (gensym)) + (max (gensym)) + (tmp (gensym))) + `(let ((,i 0) + (,tmp ,seq) + (,max (len_ ,tmp))) + (while (< ,i ,max) + (let ((,var (! ,tmp at: (_>fix ,i)))) + ,@body + (set ,i (+ ,i 1))))))) + +;; "Packing" is what Lispers usually call "collecting". +;; The Lisp idiom (let ((result '())) .. (push x result) .. (nreverse result)) +;; translates to (packing (result) .. (pack x result)) +(defmacro packing ((var) . body) + `(let ((,var (! OrderedCollection new))) + ,@body + (! ,var asArray))) + +(df pack (elt packer) (! packer addLast: elt)) + +(assert (equal (packing (p) (dotimes_ (i 2) (pack (_>fix i) p))) + '(0 1))) + +(assert (equal (packing (p) (dovec (e '(2 3)) (pack e p))) + '(2 3))) + +(assert (equal (packing (p) + (let ((a '(2 3))) + (dotimes (i (len a)) + (pack (ref a i) p)))) + '(2 3))) + +;; MAPCAR (more or less) +(df map (fun col) + (packing (r) + (dovec (e col) + (pack (fun e) r)))) + +;; VEC allocates and initializes a new array. +;; The macro translates (vec x y z) to `(,x ,y ,z). +(defmacro vec (. args) + `(quasiquote + (,@(map (lambda (arg) `(,'unquote ,arg)) + args)))) + +(assert (equal (vec '0 '1) '(0 1))) +(assert (equal (vec) '())) +(assert (== (len (vec 0 1 2 3 4)) '5)) + +;; Concatenate. +(defmacro cat (. args) `(! (vec '"" ,@args) concatenated)) + +(assert (equal (cat '"a" '"b" '"c") '"abc")) + +;; Take a vector of bytes and copy the bytes to a continuous +;; block of memory +(df assemble_ (col) (! (! ByteArray withAll: col) _bytes)) + +;; Jolt doesn't seem to have catch/throw or something equivalent. +;; Here I use a pair of assembly routines as substitue. +;; (catch% FUN) calls FUN with the current stack pointer. +;; (throw% VALUE K) unwinds the stack to K and then returns VALUE. +;; catch% is a bit like call/cc. +;; +;; [Would setjmp/longjmp work from Jolt? or does setjmp require +;; C-compiler magic?] +;; [I figure Smalltalk has a way to do non-local-exits but, I don't know +;; how to use that in Jolt.] +;; +(define catch% + (assemble_ + '(0x55 ; push %ebp + 0x89 0xe5 ; mov %esp,%ebp + 0x54 ; push %esp + 0x8b 0x45 0x08 ; mov 0x8(%ebp),%eax + 0xff 0xd0 ; call *%eax + 0xc9 ; leave + 0xc3 ; ret + ))) + +(define throw% + (assemble_ + `(,@'() + 0x8b 0x44 0x24 0x04 ; mov 0x4(%esp),%eax + 0x8b 0x6c 0x24 0x08 ; mov 0x8(%esp),%ebp + 0xc9 ; leave + 0xc3 ; ret + ))) + +(df bar (i k) + (if (== i 0) + (throw% 100 k) + (begin + (printf "bar %d\n" i) + (bar (- i 1) k)))) +(df foo (k) + (printf "foo.1\n") + (printf "foo.2 %d\n" (bar 10 k))) + +;; Our way to produce closures: we compile a new little function which +;; hardcodes the addresses of the code resp. the data-vector. The +;; nice thing is that such closures can be used called C function +;; pointers. It's probably slow to invoke the compiler for such +;; things, so use with care. +(df make-closure (addr state) + (int>_ + (! `(lambda (a b c d) + (,(_>int addr) ,(_>int state) a b c d)) + eval))) + +;; Return a closure which calls FUN with ARGS and the arguments +;; that the closure was called with. +;; Example: ((curry printf "%d\n") 10) +(defmacro curry (fun . args) + `(make-closure + (lambda (state a b c d) + ((ref state '0) + ,@(packing (sv) + (dotimes (i (len args)) + (pack `(ref state ',(fx1+ i)) sv))) + a b c d)) + (vec ,fun ,@args))) + +(df parse-closure-arglist (vars) + (let ((pos (or (index-of vars '|) + (return nil))) + (cvars (! vars copyFrom: '0 to: (fx1- pos))) + (lvars (! vars copyFrom: (fx1+ pos)))) + (vec cvars lvars))) + +;; Create a closure, to-be-closed-over variables must enumerated +;; explicitly. +;; Example: ((let ((x 1)) (closure (x | y) (+ x y))) 3) => 4. +;; The variables before the "|" are captured by the closure. +(defmacro closure ((. vars) . body) + (mif ((cvars lvars) (parse-closure-arglist vars)) + `(curry (lambda (,@cvars ,@lvars) ,@body) + ,@cvars) + (! compiler errorSyntax: vars))) + +;; The analog for Smalltalkish "blocks". +(defmacro block ((. vars) . body) + (mif ((cvars lvars) (parse-closure-arglist vars)) + `(! StaticBlockClosure + function_: (curry (lambda (,@cvars _closure _self ,@lvars) ,@body) + ,@cvars) + arity_: ,(len lvars)) + (! compiler errorSyntax: vars))) + +(define %mkstemp (dlsym "mkstemp")) +(df make-temp-file () + (let ((name (! '"/tmp/jolt-tmp.XXXXXX" copy)) + (fd (%mkstemp (! name _stringValue)))) + (if (== fd -1) + (error "mkstemp failed")) + `(,fd ,name))) +(define %unlink (dlsym "unlink")) +(df unlink (filename) (%unlink (! filename _stringValue))) + +(define write (dlsym "write")) +(df write-bytes (addr count fd) + (let ((written (write fd addr count))) + (if (!= written count) + (begin + (printf "write failed %p %d %d => %d" addr count fd written) + (error '"write failed"))))) + +(define system (dlsym "system")) +(define main (dlsym "main")) + +;; Starting at address ADDR, disassemble COUNT bytes. +;; This is implemented by writing the memory region to a file +;; and call ndisasm on it. +(df disas (addr count) + (let ((fd+name (make-temp-file))) + (write-bytes addr count (first fd+name)) + (let ((cmd (str>_ (cat '"ndisasm -u -o " + (>str (_>fix addr)) + '" " (second fd+name))))) + (printf "Running: %s\n" cmd) + (system cmd)) + (unlink (second fd+name)))) + +(df rep () + (let ((result (! (! CokeScanner read: StdIn) eval))) + (puts '"=> " StdOut) + (print result) + (puts '"\n" StdOut))) + +;; Perhaps we could use setcontext/getcontext to return from signal +;; handlers (or not). +(define +ucontext-size+ 350) +(define _getcontext (dlsym "getcontext")) +(define _setcontext (dlsym "setcontext")) +(df getcontext () + (let ((context (malloc 350))) + (_getcontext context) + context)) + +(define on_exit (dlsym "on_exit")) ; "atexit" doesn't work. why? + +(define *top-level-restart* 0) +(define *top-level-context* 0) +(define *debugger-hook* 0) + +;; Jolt's error handling strategy is charmingly simple: call exit. +;; We invoke the SLIME debugger from an exit handler. +;; (The handler is registered with atexit, that's a libc function.) + +(df exit-handler (reason arg) + (printf "exit-handler 0x%x\n" reason) + ;;(backtrace) + (on_exit exit-handler nil) + (when *debugger-hook* + (*debugger-hook* `(exit ,reason))) + (cond (*top-level-context* + (_setcontext *top-level-context*)) + (*top-level-restart* + (throw% reason *top-level-restart*)))) + +(df repl () + (set *top-level-context* (getcontext)) + (while (not (! (! StdIn readStream) atEnd)) + (printf "top-level\n") + (catch% + (lambda (k) + (set *top-level-restart* k) + (printf "repl\n") + (while 1 + (rep))))) + (printf "EOF\n")) + +;; (repl) + + +;;; Socket code. (How boring. Duh, should have used netcat instead.) + +(define strerror (dlsym "strerror")) + +(df check-os-code (value) + (if (== value -1) + (error (_>str (strerror (fix>_ (! OS errno))))) + value)) + +;; For now just hard-code constants which usually reside in header +;; files (just like a Forth guy would do). +(define PF_INET 2) +(define SOCK_STREAM 1) +(define SOL_SOCKET 1) +(define SO_REUSEADDR 2) +(define socket (dlsym "socket")) +(define setsockopt (dlsym "setsockopt")) + +(df set-reuse-address (sock value) + (let ((word-size 4) + (val (! Object _balloc: (_>fix word-size)))) + (set-int@ val value) + (check-os-code + (setsockopt sock SOL_SOCKET SO_REUSEADDR val word-size)))) + +(define sockaddr_in/size 16) +(define sockaddr_in/sin_family 0) +(define sockaddr_in/sin_port 2) +(define sockaddr_in/sin_addr 4) +(define INADDR_ANY 0) +(define AF_INET 2) +(define htons (dlsym "htons")) +(define bind (dlsym "bind")) + +(df bind-socket (sock port) + (let ((addr (! OS _balloc: (_>fix sockaddr_in/size)))) + (set-short@ (+ addr sockaddr_in/sin_family) AF_INET) + (set-short@ (+ addr sockaddr_in/sin_port) (htons port)) + (set-int@ (+ addr sockaddr_in/sin_addr) INADDR_ANY) + (check-os-code + (bind sock addr sockaddr_in/size)))) + +(define listen (dlsym "listen")) + +(df create-socket (port) + (let ((sock (check-os-code (socket PF_INET SOCK_STREAM 0)))) + (set-reuse-address sock 1) + (bind-socket sock port) + (check-os-code (listen sock 1)) + sock)) + +(define accept% (dlsym "accept")) +(df accept (sock) + (let ((addr (! OS _balloc: (_>fix sockaddr_in/size))) + (len (! OS _balloc: 4))) + (set-int@ len sockaddr_in/size) + (check-os-code (accept% sock addr len)))) + +(define getsockname (dlsym "getsockname")) +(define ntohs (dlsym "ntohs")) +(df local-port (sock) + (let ((addr (! OS _balloc: (_>fix sockaddr_in/size))) + (len (! OS _balloc: 4))) + (set-int@ len sockaddr_in/size) + (check-os-code + (getsockname sock addr len)) + (ntohs (short@ (+ addr sockaddr_in/sin_port))))) + +(define close (dlsym "close")) +(define _read (dlsym "read")) + +;; Now, after 2/3 of the file we can begin with the actual Swank +;; server. + +(df read-string (fd count) + (let ((buffer (! String new: count)) + (buffer_ (str>_ buffer)) + (count_ (int>_ count)) + (start 0)) + (while (> (- count_ start) 0) + (let ((rcount (check-os-code (_read fd + (+ buffer_ start) + (- count_ start))))) + (set start (+ start rcount)))) + buffer)) + +;; Read and parse a message from the wire. +(df read-packet (fd) + (let ((header (read-string fd '6)) + (length (! Integer fromString: header base: '16)) + (payload (read-string fd length))) + (! CokeScanner read: payload))) + +;; Print a messag to the wire. +(df send-to-emacs (event fd) + (let ((stream (! WriteStream on: (! String new: '100)))) + (! stream position: '6) + (prin1 event stream) + (let ((len (! stream position))) + (! stream position: '0) + (! (fx+ len '-6) printOn: stream base: '16 width: '6) + (write-bytes (str>_ (! stream collection)) (int>_ len) fd)))) + +(df add-quotes (form) + (mcase form + ((fun . args) + `(,fun ,@(packing (s) + (dovec (e args) + (pack `(quote ,e) s))))))) + +(define sldb 0) ;defer + +(df eval-for-emacs (form id fd abort) + (let ((old-hook *debugger-hook*)) + (mcase (catch% + (closure (form fd | k) + (set *debugger-hook* (curry sldb fd k)) + `(ok ,(int>_ (! (add-quotes form) eval))))) + (('ok value) + (set *debugger-hook* old-hook) + (send-to-emacs `(:return (:ok ,value) ,id) fd) + 'ok) + (arg + (set *debugger-hook* old-hook) + (send-to-emacs `(:return (:abort) ,id) fd) + (throw% arg abort))))) + +(df process-events (fd) + (on_exit exit-handler nil) + (let ((done nil)) + (while (not done) + (mcase (read-packet fd) + ((':emacs-rex form package thread id) + (mcase (catch% (closure (form id fd | abort) + (eval-for-emacs form id fd abort))) + ('ok) + ;;('abort nil) + ('top-level) + (other + ;;(return other) ; compiler breaks with return + (set done 1)))))))) + +(df next-frame (fp) + (let ((next (get-caller-fp fp))) + (if (and (!= next fp) + (<= next %top-level-fp)) + next + nil))) + +(df nth-frame (n top) + (let ((fp top) + (i 0)) + (while fp + (if (== i n) (return fp)) + (set fp (next-frame fp)) + (set i (+ i 1))) + nil)) + +(define Dl_info/size 16) +(define Dl_info/dli_fname 0) +(define Dl_info/dli_sname 8) + +(df get-dl-sym-name (addr) + (let ((info (! OS _balloc: (_>fix Dl_info/size)))) + (when (== (dladdr addr info) 0) + (return nil)) + (let ((sname (long@ (+ info Dl_info/dli_sname)) ) + (fname (long@ (+ info Dl_info/dli_fname)))) + (cond ((and sname fname) + (cat (_>str sname) '" in " (_>str fname))) + (sname (_>str fname)) + (fname (cat '" " (_>str fname))) + (true nil))))) + +;;(get-dl-sym-name printf) + +(df guess-function-name (ip) + (let ((fname (get-function-name ip))) + (if fname + (_>str fname) + (get-dl-sym-name ip)))) + +(df backtrace>el (top_ from_ to_) + (let ((fp (nth-frame from_ top_)) + (i from_)) + (packing (bt) + (while (and fp (< i to_)) + (let ((ip (get-frame-ip fp))) + (pack (vec (_>int i) + (cat (or (guess-function-name ip) '"(no-name)") + '" " ;;(>str (_>int ip)) + )) + bt)) + (set i (+ i 1)) + (set fp (next-frame fp)))))) + +(df debugger-info (fp msg) + (vec `(,(prin1-to-string msg) " [type ...]" ()) + '(("quit" "Return to top level")) + (backtrace>el fp 0 20) + '())) + +(define *top-frame* 0) +(define *sldb-quit* 0) + +(df debugger-loop (fd args abort) + (let ((fp (get-current-fp))) + (set *top-frame* fp) + (send-to-emacs `(:debug 0 1 ,@(debugger-info fp args)) fd) + (while 1 + (mcase (read-packet fd) + ((':emacs-rex form package thread id) + (mcase (catch% (closure (form id fd | k) + (set *sldb-quit* k) + (eval-for-emacs form id fd k) + 'ok)) + ('ok nil) + (other + (send-to-emacs `(:return (:abort) ,id) fd) + (throw% other abort)))))))) + +(df sldb (fd abort args) + (let ((old-top-frame *top-frame*) + (old-sldb-quit *sldb-quit*)) + (mcase (catch% (curry debugger-loop fd args)) + (value + (set *top-frame* old-top-frame) + (set *sldb-quit* old-sldb-quit) + (send-to-emacs `(:debug-return 0 1 nil) fd) + (throw% value abort))))) + +(df swank:backtrace (start end) + (backtrace>el *top-frame* (int>_ start) (int>_ end))) + +(df sldb-quit () + (assert *sldb-quit*) + (throw% 'top-level *sldb-quit*)) + +(df swank:invoke-nth-restart-for-emacs (...) (sldb-quit)) +(df swank:throw-to-toplevel (...) (sldb-quit)) + +(df setup-server (port announce) + (let ((sock (create-socket port))) + (announce sock) + (let ((client (accept sock))) + (process-events client) + (close client)) + (printf "Closing socket: %d %d\n" sock (local-port sock)) + (close sock))) + +(df announce-port (sock) + (printf "Listening on port: %d\n" (local-port sock))) + +(df create-server (port) (setup-server port announce-port)) + +(df write-port-file (filename sock) + (let ((f (! File create: filename))) + (! f write: (print-to-string (_>int (local-port sock)))) + (! f close))) + +(df start-swank (port-file) + (setup-server 0 (curry write-port-file (_>str port-file)))) + +(define getpid (dlsym "getpid")) +(df swank:connection-info () + `(,@'() + :pid ,(_>int (getpid)) + :style nil + :lisp-implementation (,@'() + :type "Coke" + :name "jolt" + :version ,(! CodeGenerator versionString)) + :machine (:instance "" :type ,(! OS architecture) :version "") + :features () + :package (:name "jolt" :prompt "jolt"))) + +(df swank:listener-eval (string) + (let ((result (! (! CokeScanner read: string) eval))) + `(:values ,(prin1-to-string (if (or (fix? result) + (and (valid-pointer? result) + (int? result))) + (int>_ result) + result)) + ,(prin1-to-string result)))) + +(df swank:interactive-eval (string) + (let ((result (! (! CokeScanner read: string) eval))) + (cat '"=> " (prin1-to-string (if (or (fix? result) + (and (valid-pointer? result) + (int? result))) + (int>_ result) + result)) + '", " (prin1-to-string result)))) + +(df swank:operator-arglist () nil) +(df swank:buffer-first-change () nil) +(df swank:create-repl (_) '("jolt" "jolt")) + +(df min (x y) (if (<= x y) x y)) + +(df common-prefix2 (e1 e2) + (let ((i '0) + (max (min (len e1) (len e2)))) + (while (and (< i max) + (== (ref e1 i) (ref e2 i))) + (set i (fx1+ i))) + (! e1 copyFrom: '0 to: (fx1- i)))) + +(df common-prefix (seq) + (mcase seq + (() nil) + (_ + (let ((prefix (ref seq '0))) + (dovec (e seq) + (set prefix (common-prefix2 prefix e))) + prefix)))) + +(df swank:simple-completions (prefix _package) + (let ((matches (packing (s) + (dovec (e (! TheGlobalEnvironment keys)) + (let ((name (>str e))) + (when (! name beginsWith: prefix) + (pack name s))))))) + (vec matches (or (common-prefix matches) prefix)))) + + +;; swank-jolt.k ends here diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-kawa.scm b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-kawa.scm new file mode 100644 index 0000000..3dd9c07 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-kawa.scm @@ -0,0 +1,2504 @@ +;;;; swank-kawa.scm --- Swank server for Kawa +;;; +;;; Copyright (C) 2007 Helmut Eller +;;; +;;; This file is licensed under the terms of the GNU General Public +;;; License as distributed with Emacs (press C-h C-c for details). + +;;;; Installation +;; +;; 1. You need Kawa (version 2.x) and a JVM with debugger support. +;; +;; 2. Compile this file and create swank-kawa.jar with: +;; java -cp kawa.jar:$JAVA_HOME/lib/tools.jar \ +;; -Xss2M kawa.repl --r7rs -d classes -C swank-kawa.scm && +;; jar cf swank-kawa.jar -C classes . +;; +;; 3. Add something like this to your .emacs: +#| +;; Kawa, Swank, and the debugger classes (tools.jar) must be in the +;; classpath. You also need to start the debug agent. +(setq slime-lisp-implementations + '((kawa + ("java" + ;; needed jar files + "-cp" "kawa-2.0.1.jar:swank-kawa.jar:/opt/jdk1.8.0/lib/tools.jar" + ;; channel for debugger + "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n" + ;; depending on JVM, compiler may need more stack + "-Xss2M" + ;; kawa without GUI + "kawa.repl" "-s") + :init kawa-slime-init))) + +(defun kawa-slime-init (file _) + (setq slime-protocol-version 'ignore) + (format "%S\n" + `(begin (import (swank-kawa)) + (start-swank ,file) + ;; Optionally add source paths of your code so + ;; that M-. works better: + ;;(set! swank-java-source-path + ;; (append + ;; '(,(expand-file-name "~/lisp/slime/contrib/") + ;; "/scratch/kawa") + ;; swank-java-source-path)) + ))) + +;; Optionally define a command to start it. +(defun kawa () + (interactive) + (slime 'kawa)) + +|# +;; 4. Start everything with M-- M-x slime kawa +;; +;; + + +;;; Code: + +(define-library (swank macros) + (export df fun seq set fin esc + ! !! !s @ @s + when unless while dotimes dolist for packing with pushf == assert + mif mcase mlet mlet* typecase ignore-errors + ferror + ) + (import (scheme base) + (only (kawa base) + syntax + quasisyntax + syntax-case + define-syntax-case + identifier? + + invoke + invoke-static + field + static-field + instance? + try-finally + try-catch + primitive-throw + + format + reverse! + as + )) + (begin " +(" + +(define (ferror fstring #!rest args) + (let ((err ( + (as (apply format fstring args))))) + (primitive-throw err))) + +(define (rewrite-lambda-list args) + (syntax-case args () + (() #`()) + ((rest x ...) (eq? #'rest #!rest) args) + ((optional x ...) (eq? #'optional #!optional) args) + ((var args ...) (identifier? #'var) + #`(var #,@(rewrite-lambda-list #'(args ...)))) + (((var type) args ...) (identifier? #'var) + #`((var :: type) #,@(rewrite-lambda-list #'(args ...)))))) + +(define-syntax df + (lambda (stx) + (syntax-case stx (=>) + ((df name (args ... => return-type) body ...) + #`(define (name #,@(rewrite-lambda-list #'(args ...))) :: return-type + (seq body ...))) + ((df name (args ...) body ...) + #`(define (name #,@(rewrite-lambda-list #'(args ...))) + (seq body ...)))))) + +(define-syntax fun + (lambda (stx) + (syntax-case stx (=>) + ((fun (args ... => return-type) body ...) + #`(lambda #,(rewrite-lambda-list #'(args ...)) :: return-type + (seq body ...))) + ((fun (args ...) body ...) + #`(lambda #,(rewrite-lambda-list #'(args ...)) + (seq body ...)))))) + +(define-syntax fin + (syntax-rules () + ((fin body handler ...) + (try-finally body (seq handler ...))))) + +(define-syntax seq + (syntax-rules () + ((seq) + (begin #!void)) + ((seq body ...) + (begin body ...)))) + +(define-syntax esc + (syntax-rules () + ((esc abort body ...) + (let* ((key ()) + (abort (lambda (val) (throw key val)))) + (catch key + (lambda () body ...) + (lambda (key val) val)))))) + +(define-syntax ! + (syntax-rules () + ((! name obj args ...) + (invoke obj 'name args ...)))) + +(define-syntax !! + (syntax-rules () + ((!! name1 name2 obj args ...) + (! name1 (! name2 obj args ...))))) + +(define-syntax !s + (syntax-rules () + ((! class name args ...) + (invoke-static class 'name args ...)))) + +(define-syntax @ + (syntax-rules () + ((@ name obj) + (field obj 'name)))) + +(define-syntax @s + (syntax-rules (quote) + ((@s class name) + (static-field class (quote name))))) + +(define-syntax while + (syntax-rules () + ((while exp body ...) + (do () ((not exp)) body ...)))) + +(define-syntax dotimes + (syntax-rules () + ((dotimes (i n result) body ...) + (let ((max :: n)) + (do ((i :: 0 (as (+ i 1)))) + ((= i max) result) + body ...))) + ((dotimes (i n) body ...) + (dotimes (i n #f) body ...)))) + +(define-syntax dolist + (syntax-rules () + ((dolist (e list) body ... ) + (for ((e list)) body ...)))) + +(define-syntax for + (syntax-rules () + ((for ((var iterable)) body ...) + (let ((iter (! iterator iterable))) + (while (! has-next iter) + ((lambda (var) body ...) + (! next iter))))))) + +(define-syntax packing + (syntax-rules () + ((packing (var) body ...) + (let ((var :: '())) + (let ((var (lambda (v) (set! var (cons v var))))) + body ...) + (reverse! var))))) + +;;(define-syntax loop +;; (syntax-rules (for = then collect until) +;; ((loop for var = init then step until test collect exp) +;; (packing (pack) +;; (do ((var init step)) +;; (test) +;; (pack exp)))) +;; ((loop while test collect exp) +;; (packing (pack) (while test (pack exp)))))) + +(define-syntax with + (syntax-rules () + ((with (vars ... (f args ...)) body ...) + (f args ... (lambda (vars ...) body ...))))) + +(define-syntax pushf + (syntax-rules () + ((pushf value var) + (set! var (cons value var))))) + +(define-syntax == + (syntax-rules () + ((== x y) + (eq? x y)))) + +(define-syntax set + (syntax-rules () + ((set x y) + (let ((tmp y)) + (set! x tmp) + tmp)) + ((set x y more ...) + (begin (set! x y) (set more ...))))) + +(define-syntax assert + (syntax-rules () + ((assert test) + (seq + (when (not test) + (error "Assertion failed" 'test)) + 'ok)) + ((assert test fstring args ...) + (seq + (when (not test) + (error "Assertion failed" 'test (format #f fstring args ...))) + 'ok)))) + +(define-syntax mif + (syntax-rules (quote unquote _) + ((mif ('x value) then else) + (if (equal? 'x value) then else)) + ((mif (,x value) then else) + (if (eq? x value) then else)) + ((mif (() value) then else) + (if (eq? value '()) then else)) + #| This variant produces no lambdas but breaks the compiler + ((mif ((p . ps) value) then else) + (let ((tmp value) + (fail? :: 0) + (result #!null)) + (if (instance? tmp ) + (let ((tmp :: tmp)) + (mif (p (! get-car tmp)) + (mif (ps (! get-cdr tmp)) + (set! result then) + (set! fail? -1)) + (set! fail? -1))) + (set! fail? -1)) + (if (= fail? 0) result else))) + |# + ((mif ((p . ps) value) then else) + (let ((fail (lambda () else)) + (tmp value)) + (if (instance? tmp ) + (let ((tmp :: tmp)) + (mif (p (! get-car tmp)) + (mif (ps (! get-cdr tmp)) + then + (fail)) + (fail))) + (fail)))) + ((mif (_ value) then else) + then) + ((mif (var value) then else) + (let ((var value)) then)) + ((mif (pattern value) then) + (mif (pattern value) then (values))))) + +(define-syntax mcase + (syntax-rules () + ((mcase exp (pattern body ...) more ...) + (let ((tmp exp)) + (mif (pattern tmp) + (begin body ...) + (mcase tmp more ...)))) + ((mcase exp) (ferror "mcase failed ~s\n~a" 'exp exp)))) + +(define-syntax mlet + (syntax-rules () + ((mlet (pattern value) body ...) + (let ((tmp value)) + (mif (pattern tmp) + (begin body ...) + (error "mlet failed" tmp)))))) + +(define-syntax mlet* + (syntax-rules () + ((mlet* () body ...) (begin body ...)) + ((mlet* ((pattern value) ms ...) body ...) + (mlet (pattern value) (mlet* (ms ...) body ...))))) + +(define-syntax typecase% + (syntax-rules (eql or satisfies) + ((typecase% var (#t body ...) more ...) + (seq body ...)) + ((typecase% var ((eql value) body ...) more ...) + (cond ((eqv? var 'value) body ...) + (else (typecase% var more ...)))) + ((typecase% var ((satisfies predicate) body ...) more ...) + (cond ((predicate var) body ...) + (else (typecase% var more ...)))) + ((typecase% var ((or type) body ...) more ...) + (typecase% var (type body ...) more ...)) + ((typecase% var ((or type ...) body ...) more ...) + (let ((f (lambda (var) body ...))) + (typecase% var + (type (f var)) ... + (#t (typecase% var more ...))))) + ((typecase% var (type body ...) more ...) + (cond ((instance? var type) + (let ((var :: type (as type var))) + body ...)) + (else (typecase% var more ...)))) + ((typecase% var) + (error "typecase% failed" var + (! getClass (as var)))))) + +(define-syntax typecase + (lambda (stx) + (syntax-case stx () + ((_ exp more ...) (identifier? (syntax exp)) + #`(typecase% exp more ...)) + ((_ exp more ...) + #`(let ((tmp exp)) + (typecase% tmp more ...)))))) + +(define-syntax ignore-errors + (syntax-rules () + ((ignore-errors body ...) + (try-catch (seq body ...) + (v #f) + (v #f))))) + +)) + +(define-library (swank-kawa) + (export start-swank + create-swank-server + swank-java-source-path + break) + (import (scheme base) + (scheme file) + (scheme repl) + (scheme read) + (scheme write) + (scheme eval) + (scheme process-context) + (swank macros) + (only (kawa base) + + define-alias + define-variable + + define-simple-class + this + + invoke-special + instance? + as + + primitive-throw + try-finally + try-catch + synchronized + + call-with-input-string + call-with-output-string + force-output + format + + make-process + command-parse + + runnable + + scheme-implementation-version + reverse! + ) + (rnrs hashtables) + (only (gnu kawa slib syntaxutils) expand) + (only (kawa regex) regex-match)) + (begin " +(" + + +;;(define-syntax dc +;; (syntax-rules () +;; ((dc name () %% (props ...) prop more ...) +;; (dc name () %% (props ... (prop )) more ...)) +;; ;;((dc name () %% (props ...) (prop type) more ...) +;; ;; (dc name () %% (props ... (prop type)) more ...)) +;; ((dc name () %% ((prop type) ...)) +;; (define-simple-class name () +;; ((*init* (prop :: type) ...) +;; (set (field (this) 'prop) prop) ...) +;; (prop :type type) ...)) +;; ((dc name () props ...) +;; (dc name () %% () props ...)))) + + +;;;; Aliases + +(define-alias java.net.ServerSocket) +(define-alias java.net.Socket) +(define-alias java.io.InputStreamReader) +(define-alias java.io.OutputStreamWriter) +(define-alias gnu.kawa.io.InPort) +(define-alias gnu.kawa.io.OutPort) +(define-alias java.io.File) +(define-alias java.lang.String) +(define-alias java.lang.StringBuilder) +(define-alias java.lang.Throwable) +(define-alias gnu.text.SourceError) +(define-alias gnu.expr.ModuleInfo) +(define-alias java.lang.Iterable) +(define-alias java.lang.Thread) +(define-alias java.util.concurrent.LinkedBlockingQueue) +(define-alias java.util.concurrent.Exchanger) +(define-alias java.util.concurrent.TimeUnit) +(define-alias com.sun.jdi.VirtualMachine) +(define-alias com.sun.jdi.Mirror) +(define-alias com.sun.jdi.Value) +(define-alias com.sun.jdi.ThreadReference) +(define-alias com.sun.jdi.ObjectReference) +(define-alias com.sun.jdi.ArrayReference) +(define-alias com.sun.jdi.StringReference) +(define-alias com.sun.jdi.Method) +(define-alias com.sun.jdi.ClassType) +(define-alias com.sun.jdi.ReferenceType) +(define-alias com.sun.jdi.StackFrame) +(define-alias com.sun.jdi.Field) +(define-alias com.sun.jdi.LocalVariable) +(define-alias com.sun.jdi.Location) +(define-alias com.sun.jdi.AbsentInformationException) +(define-alias com.sun.jdi.event.Event) +(define-alias com.sun.jdi.event.ExceptionEvent) +(define-alias com.sun.jdi.event.StepEvent) +(define-alias com.sun.jdi.event.BreakpointEvent) +(define-alias gnu.mapping.Environment) + +(define-simple-class () + (owner :: #:init (!s java.lang.Thread currentThread)) + (peer :: ) + (queue :: #:init ()) + (lock #:init ())) + + +;;;; Entry Points + +(df create-swank-server (port-number) + (setup-server port-number announce-port)) + +(df start-swank (port-file) + (let ((announce (fun ((socket )) + (with (f (call-with-output-file port-file)) + (format f "~d\n" (! get-local-port socket)))))) + (spawn (fun () + (setup-server 0 announce))))) + +(df setup-server ((port-number ) announce) + (! set-name (current-thread) "swank") + (let ((s ( port-number))) + (announce s) + (let ((c (! accept s))) + (! close s) + (log "connection: ~s\n" c) + (fin (dispatch-events c) + (log "closing socket: ~a\n" s) + (! close c))))) + +(df announce-port ((socket )) + (log "Listening on port: ~d\n" (! get-local-port socket))) + + +;;;; Event dispatcher + +(define-variable *the-vm* #f) +(define-variable *last-exception* #f) +(define-variable *last-stacktrace* #f) +(df %vm (=> ) *the-vm*) + +;; FIXME: this needs factorization. But I guess the whole idea of +;; using bidirectional channels just sucks. Mailboxes owned by a +;; single thread to which everybody can send are much easier to use. + +(df dispatch-events ((s )) + (mlet* ((charset "iso-8859-1") + (ins ( (! getInputStream s) charset)) + (outs ( (! getOutputStream s) charset)) + ((in . _) (spawn/chan/catch (fun (c) (reader ins c)))) + ((out . _) (spawn/chan/catch (fun (c) (writer outs c)))) + ((dbg . _) (spawn/chan/catch vm-monitor)) + (user-env (interaction-environment)) + (x (seq + (! set-flag user-env #t #|:THREAD_SAFE|# 8) + (! set-flag user-env #f #|:DIRECT_INHERITED_ON_SET|# 16) + #f)) + ((listener . _) + (spawn/chan (fun (c) (listener c user-env)))) + (inspector #f) + (threads '()) + (repl-thread #f) + (extra '()) + (vm (let ((vm #f)) (fun () (or vm (rpc dbg `(get-vm))))))) + (while #t + (mlet ((c . event) (recv* (append (list in out dbg listener) + (if inspector (list inspector) '()) + (map car threads) + extra))) + ;;(log "event: ~s\n" event) + (mcase (list c event) + ((_ (':emacs-rex ('|swank:debugger-info-for-emacs| from to) + pkg thread id)) + (send dbg `(debug-info ,thread ,from ,to ,id))) + ((_ (':emacs-rex ('|swank:throw-to-toplevel|) pkg thread id)) + (send dbg `(throw-to-toplevel ,thread ,id))) + ((_ (':emacs-rex ('|swank:sldb-continue|) pkg thread id)) + (send dbg `(thread-continue ,thread ,id))) + ((_ (':emacs-rex ('|swank:frame-source-location| frame) + pkg thread id)) + (send dbg `(frame-src-loc ,thread ,frame ,id))) + ((_ (':emacs-rex ('|swank:frame-locals-and-catch-tags| frame) + pkg thread id)) + (send dbg `(frame-details ,thread ,frame ,id))) + ((_ (':emacs-rex ('|swank:sldb-disassemble| frame) + pkg thread id)) + (send dbg `(disassemble-frame ,thread ,frame ,id))) + ((_ (':emacs-rex ('|swank:backtrace| from to) pkg thread id)) + (send dbg `(thread-frames ,thread ,from ,to ,id))) + ((_ (':emacs-rex ('|swank:list-threads|) pkg thread id)) + (send dbg `(list-threads ,id))) + ((_ (':emacs-rex ('|swank:debug-nth-thread| n) _ _ _)) + (send dbg `(debug-nth-thread ,n))) + ((_ (':emacs-rex ('|swank:quit-thread-browser|) _ _ id)) + (send dbg `(quit-thread-browser ,id))) + ((_ (':emacs-rex ('|swank:init-inspector| str . _) pkg _ id)) + (set inspector (make-inspector user-env (vm))) + (send inspector `(init ,str ,id))) + ((_ (':emacs-rex ('|swank:inspect-frame-var| frame var) + pkg thread id)) + (mlet ((im . ex) (chan)) + (set inspector (make-inspector user-env (vm))) + (send dbg `(get-local ,ex ,thread ,frame ,var)) + (send inspector `(init-mirror ,im ,id)))) + ((_ (':emacs-rex ('|swank:inspect-current-condition|) pkg thread id)) + (mlet ((im . ex) (chan)) + (set inspector (make-inspector user-env (vm))) + (send dbg `(get-exception ,ex ,thread)) + (send inspector `(init-mirror ,im ,id)))) + ((_ (':emacs-rex ('|swank:inspect-nth-part| n) pkg _ id)) + (send inspector `(inspect-part ,n ,id))) + ((_ (':emacs-rex ('|swank:inspector-pop|) pkg _ id)) + (send inspector `(pop ,id))) + ((_ (':emacs-rex ('|swank:quit-inspector|) pkg _ id)) + (send inspector `(quit ,id))) + ((_ (':emacs-interrupt id)) + (let* ((vm (vm)) + (t (find-thread id (map cdr threads) repl-thread vm))) + (send dbg `(interrupt-thread ,t)))) + ((_ (':emacs-rex form _ _ id)) + (send listener `(,form ,id))) + ((_ ('get-vm c)) + (send dbg `(get-vm ,c))) + ((_ ('get-channel c)) + (mlet ((im . ex) (chan)) + (pushf im extra) + (send c ex))) + ((_ ('forward x)) + (send out x)) + ((_ ('set-listener x)) + (set repl-thread x)) + ((_ ('publish-vm vm)) + (set *the-vm* vm)) + ))))) + +(df find-thread (id threads listener (vm )) + (cond ((== id ':repl-thread) listener) + ((== id 't) listener + ;;(if (null? threads) + ;; listener + ;; (vm-mirror vm (car threads))) + ) + (#t + (let ((f (find-if threads + (fun (t :: ) + (= id (! uniqueID + (as (vm-mirror vm t))))) + #f))) + (cond (f (vm-mirror vm f)) + (#t listener)))))) + + +;;;; Reader thread + +(df reader ((in ) (c )) + (! set-name (current-thread) "swank-net-reader") + (let ((rt (!s gnu.kawa.lispexpr.ReadTable createInitial))) ; ':' not special + (while #t + (send c (decode-message in rt))))) + +(df decode-message ((in ) (rt ) => ) + (let* ((header (read-chunk in 6)) + (len (!s java.lang.Integer parseInt header 16))) + (call-with-input-string (read-chunk in len) + (fun ((port )) + (%read port rt))))) + +(df read-chunk ((in ) (len ) => ) + (let ((chars ( #:length len))) + (let loop ((offset :: 0)) + (cond ((= offset len) ( chars)) + (#t (let ((count (! read in chars offset (- len offset)))) + (assert (not (= count -1)) "partial packet") + (loop (+ offset count)))))))) + +;;; FIXME: not thread safe +(df %read ((port ) (table )) + (let ((old (!s gnu.kawa.lispexpr.ReadTable getCurrent))) + (try-finally + (seq (!s gnu.kawa.lispexpr.ReadTable setCurrent table) + (read port)) + (!s gnu.kawa.lispexpr.ReadTable setCurrent old)))) + + +;;;; Writer thread + +(df writer ((out ) (c )) + (! set-name (current-thread) "swank-net-writer") + (while #t + (encode-message out (recv c)))) + +(df encode-message ((out ) (message )) + (let ((builder ( (as 512)))) + (print-for-emacs message builder) + (! write out (! toString (format "~6,'0x" (! length builder)))) + (! write out builder) + (! flush out))) + +(df print-for-emacs (obj (out )) + (let ((pr (fun (o) (! append out (! toString (format "~s" o))))) + (++ (fun ((s )) (! append out (! toString s))))) + (cond ((null? obj) (++ "nil")) + ((string? obj) (pr obj)) + ((number? obj) (pr obj)) + ;;((keyword? obj) (++ ":") (! append out (to-str obj))) + ((symbol? obj) (pr obj)) + ((pair? obj) + (++ "(") + (let loop ((obj obj)) + (print-for-emacs (car obj) out) + (let ((cdr (cdr obj))) + (cond ((null? cdr) (++ ")")) + ((pair? cdr) (++ " ") (loop cdr)) + (#t (++ " . ") (print-for-emacs cdr out) (++ ")")))))) + (#t (error "Unprintable object" obj))))) + +;;;; SLIME-EVAL + +(df eval-for-emacs ((form ) env (id ) (c )) + ;;(! set-uncaught-exception-handler (current-thread) + ;; ( (fun (t e) (reply-abort c id)))) + (reply c (%eval form env) id)) + +(define-variable *slime-funs*) +(set *slime-funs* (tab)) + +(df %eval (form env) + (apply (lookup-slimefun (car form) *slime-funs*) env (cdr form))) + +(df lookup-slimefun ((name ) tab) + ;; name looks like '|swank:connection-info| + (or (get tab name #f) + (ferror "~a not implemented" name))) + +(df %defslimefun ((name ) (fun )) + (let ((string (symbol->string name))) + (cond ((regex-match #/:/ string) + (put *slime-funs* name fun)) + (#t + (let ((qname (string->symbol (string-append "swank:" string)))) + (put *slime-funs* qname fun)))))) + +(define-syntax defslimefun + (syntax-rules () + ((defslimefun name (args ...) body ...) + (seq + (df name (args ...) body ...) + (%defslimefun 'name name))))) + +(defslimefun connection-info ((env )) + (let ((prop (fun (name) (!s java.lang.System getProperty name)))) + `(:pid + 0 + :style :spawn + :lisp-implementation (:type "Kawa" :name "kawa" + :version ,(scheme-implementation-version)) + :machine (:instance ,(prop "java.vm.name") :type ,(prop "os.name") + :version ,(prop "java.runtime.version")) + :features () + :package (:name "??" :prompt ,(! getName env)) + :encoding (:coding-systems ("iso-8859-1")) + ))) + + +;;;; Listener + +(df listener ((c ) (env )) + (! set-name (current-thread) "swank-listener") + (log "listener: ~s ~s ~s ~s\n" + (current-thread) (! hashCode (current-thread)) c env) + (let ((out (make-swank-outport (rpc c `(get-channel))))) + (set (current-output-port) out) + (let ((vm (as (rpc c `(get-vm))))) + (send c `(set-listener ,(vm-mirror vm (current-thread)))) + (request-uncaught-exception-events vm) + ;;stack snaphost are too expensive + ;;(request-caught-exception-events vm) + ) + (rpc c `(get-vm)) + (listener-loop c env out))) + +(define-simple-class () + ((*init*) + (invoke-special (this) '*init* )) + ((abort) :: void + (primitive-throw (this)))) + +(df listener-loop ((c ) (env ) port) + (while (not (nul? c)) + ;;(log "listener-loop: ~s ~s\n" (current-thread) c) + (mlet ((form id) (recv c)) + (let ((restart (fun () + (close-port port) + (reply-abort c id) + (send (car (spawn/chan + (fun (cc) + (listener (recv cc) env)))) + c) + (set c #!null)))) + (! set-uncaught-exception-handler (current-thread) + ( (fun (t e) (restart)))) + (try-catch + (let* ((val (%eval form env))) + (force-output) + (reply c val id)) + (ex (invoke-debugger ex) (restart)) + (ex (invoke-debugger ex) (restart)) + (ex + (let ((flag (!s java.lang.Thread interrupted))) + (log "listener-abort: ~s ~a\n" ex flag)) + (restart)) + ))))) + +(df invoke-debugger (condition) + ;;(log "should now invoke debugger: ~a" condition) + (try-catch + (break condition) + (ex (seq)))) + +(defslimefun |swank-repl:create-repl| (env #!rest _) + (list "user" "user")) + +(defslimefun interactive-eval (env str) + (values-for-echo-area (eval (read-from-string str) env))) + +(defslimefun interactive-eval-region (env (s )) + (with (port (call-with-input-string s)) + (values-for-echo-area + (let next ((result (values))) + (let ((form (read port))) + (cond ((== form #!eof) result) + (#t (next (eval form env))))))))) + +(defslimefun |swank-repl:listener-eval| (env string) + (let* ((form (read-from-string string)) + (list (values-to-list (eval form env)))) + `(:values ,@(map pprint-to-string list)))) + +(defslimefun pprint-eval (env string) + (let* ((form (read-from-string string)) + (l (values-to-list (eval form env)))) + (apply cat (map pprint-to-string l)))) + +(defslimefun eval-and-grab-output (env string) + (let ((form (read (open-input-string string)))) + (let-values ((values (eval form env))) + (list "" + (format #f "~{~S~^~%~}" values))))) + +(df call-with-abort (f) + (try-catch (f) (ex (exception-message ex)))) + +(df exception-message ((ex )) + (typecase ex + ( (! to-string ex)) + ( (format "~a: ~a" + (class-name-sans-package ex) + (! getMessage ex))))) + +(df values-for-echo-area (values) + (let ((values (values-to-list values))) + (cond ((null? values) "; No value") + (#t (format "~{~a~^, ~}" (map pprint-to-string values)))))) + +;;;; Compilation + +(defslimefun compile-file-for-emacs (env (filename ) load? + #!optional options) + (let ((jar (cat (path-sans-extension (filepath filename)) ".jar"))) + (wrap-compilation + (fun ((m )) + (!s kawa.lang.CompileFile read filename m)) + jar (if (lisp-bool load?) env #f) #f))) + +(df wrap-compilation (f jar env delete?) + (let ((start-time (current-time)) + (messages ())) + (try-catch + (let ((c (as (f messages)))) + (set (@ explicit c) #t) + (! compile-to-archive c (! get-module c) jar)) + (ex + (log "error during compilation: ~a\n~a" ex (! getStackTrace ex)) + (! error messages (as #\f) + (to-str (exception-message ex)) #!null) + #f)) + (log "compilation done.\n") + (let ((success? (zero? (! get-error-count messages)))) + (when (and env success?) + (log "loading ...\n") + (eval `(load ,jar) env) + (log "loading ... done.\n")) + (when delete? + (ignore-errors (delete-file jar) #f)) + (let ((end-time (current-time))) + (list ':compilation-result + (compiler-notes-for-emacs messages) + (if success? 't 'nil) + (/ (- end-time start-time) 1000.0)))))) + +(defslimefun compile-string-for-emacs (env string buffer offset dir) + (wrap-compilation + (fun ((m )) + (let ((c (as + (call-with-input-string + string + (fun ((p )) + (! set-path p + (format "~s" + `(buffer ,buffer offset ,offset str ,string))) + (!s kawa.lang.CompileFile read p m)))))) + (let ((o (@ currentOptions c))) + (! set o "warn-invoke-unknown-method" #t) + (! set o "warn-undefined-variable" #t)) + (let ((m (! getModule c))) + (! set-name m (format ":~a/~a" buffer (current-time)))) + c)) + "/tmp/kawa-tmp.zip" env #t)) + +(df compiler-notes-for-emacs ((messages )) + (packing (pack) + (do ((e (! get-errors messages) (@ next e))) + ((nul? e)) + (pack (source-error>elisp e))))) + +(df source-error>elisp ((e ) => ) + (list ':message (to-string (@ message e)) + ':severity (case (integer->char (@ severity e)) + ((#\e #\f) ':error) + ((#\w) ':warning) + (else ':note)) + ':location (error-loc>elisp e))) + +(df error-loc>elisp ((e )) + (cond ((nul? (@ filename e)) `(:error "No source location")) + ((! starts-with (@ filename e) "(buffer ") + (mlet (('buffer b 'offset ('quote ((:position o) _)) 'str s) + (read-from-string (@ filename e))) + (let ((off (line>offset (1- (@ line e)) s)) + (col (1- (@ column e)))) + `(:location (:buffer ,b) (:position ,(+ o off col)) nil)))) + (#t + `(:location (:file ,(to-string (@ filename e))) + (:line ,(@ line e) ,(1- (@ column e))) + nil)))) + +(df line>offset ((line ) (s ) => ) + (let ((offset :: 0)) + (dotimes (i line) + (set offset (! index-of s (as #\newline) offset)) + (assert (>= offset 0)) + (set offset (as (+ offset 1)))) + (log "line=~a offset=~a\n" line offset) + offset)) + +(defslimefun load-file (env filename) + (format "Loaded: ~a => ~s" filename (eval `(load ,filename) env))) + +;;;; Completion + +(defslimefun simple-completions (env (pattern ) _) + (let* ((env (as env)) + (matches (packing (pack) + (let ((iter (! enumerate-all-locations env))) + (while (! has-next iter) + (let ((l (! next-location iter))) + (typecase l + ( + (let ((name (!! get-name get-key-symbol l))) + (when (! starts-with name pattern) + (pack name))))))))))) + `(,matches ,(cond ((null? matches) pattern) + (#t (fold+ common-prefix matches)))))) + +(df common-prefix ((s1 ) (s2 ) => ) + (let ((limit (min (! length s1) (! length s2)))) + (let loop ((i 0)) + (cond ((or (= i limit) + (not (== (! char-at s1 i) + (! char-at s2 i)))) + (! substring s1 0 i)) + (#t (loop (1+ i))))))) + +(df fold+ (f list) + (let loop ((s (car list)) + (l (cdr list))) + (cond ((null? l) s) + (#t (loop (f s (car l)) (cdr l)))))) + +;;; Quit + +(defslimefun quit-lisp (env) + (exit)) + +;;(defslimefun set-default-directory (env newdir)) + + +;;;; Dummy defs + +(defslimefun buffer-first-change (#!rest y) '()) +(defslimefun swank-require (#!rest y) '()) +(defslimefun frame-package-name (#!rest y) '()) + +;;;; arglist + +(defslimefun operator-arglist (env name #!rest _) + (mcase (try-catch `(ok ,(eval (read-from-string name) env)) + (ex 'nil)) + (('ok obj) + (mcase (arglist obj) + ('#f 'nil) + ((args rtype) + (format "(~a~{~^ ~a~})~a" name + (map (fun (e) + (if (equal (cadr e) "java.lang.Object") (car e) e)) + args) + (if (equal rtype "java.lang.Object") + "" + (format " => ~a" rtype)))))) + (_ 'nil))) + +(df arglist (obj) + (typecase obj + ( + (let* ((mref (module-method>meth-ref obj))) + (list (mapi (! arguments mref) + (fun ((v )) + (list (! name v) (! typeName v)))) + (! returnTypeName mref)))) + ( #f))) + +;;;; M-. + +(defslimefun find-definitions-for-emacs (env name) + (mcase (try-catch `(ok ,(eval (read-from-string name) env)) + (ex `(error ,(exception-message ex)))) + (('ok obj) (mapi (all-definitions obj) + (fun (d) + `(,(format "~a" d) ,(src-loc>elisp (src-loc d)))))) + (('error msg) `((,name (:error ,msg)))))) + +(define-simple-class () + (file #:init #f) + (line #:init #f) + ((*init* file name) + (set (@ file (this)) file) + (set (@ line (this)) line)) + ((lineNumber) :: (or line (absent))) + ((lineNumber (s :: )) :: int (! lineNumber (this))) + ((method) :: (absent)) + ((sourcePath) :: (or file (absent))) + ((sourcePath (s :: )) :: (! sourcePath (this))) + ((sourceName) :: (absent)) + ((sourceName (s :: )) :: (! sourceName (this))) + ((declaringType) :: (absent)) + ((codeIndex) :: -1) + ((virtualMachine) :: *the-vm*) + ((compareTo o) :: + (typecase o + ( (- (! codeIndex (this)) (! codeIndex o)))))) + +(df absent () (primitive-throw ())) + +(df all-definitions (o) + (typecase o + ( (list o)) + ( (list o)) + ( (append (mappend all-definitions (gf-methods o)) + (let ((s (! get-setter o))) + (if s (all-definitions s) '())))) + ( (list o)) + ( (all-definitions (! get-class o))) + ( (list o)) + ( (all-definitions (! getReflectClass o))) + ( '()) + )) + +(df gf-methods ((f )) + (let* ((o :: (vm-mirror *the-vm* f)) + (f (! field-by-name (! reference-type o) "methods")) + (ms (vm-demirror *the-vm* (! get-value o f)))) + (filter (array-to-list ms) (fun (x) (not (nul? x)))))) + +(df src-loc (o => ) + (typecase o + ( (src-loc (@ method o))) + ( (module-method>src-loc o)) + ( ( #f #f)) + ( (class>src-loc o)) + ( ( #f #f)) + ( (bytemethod>src-loc o)))) + +(df module-method>src-loc ((f )) + (! location (module-method>meth-ref f))) + +(df module-method>meth-ref ((f ) => ) + (let* ((module (! reference-type + (as (vm-mirror *the-vm* (@ module f))))) + (1st-method-by-name (fun (name) + (let ((i (! methods-by-name module name))) + (cond ((! is-empty i) #f) + (#t (1st i))))))) + (as (or (1st-method-by-name (! get-name f)) + (let ((mangled (mangled-name f))) + (or (1st-method-by-name mangled) + (1st-method-by-name (cat mangled "$V")) + (1st-method-by-name (cat mangled "$X")))))))) + +(df mangled-name ((f )) + (let* ((name0 (! get-name f)) + (name (cond ((nul? name0) (format "lambda~d" (@ selector f))) + (#t (!s gnu.expr.Compilation mangleName name0))))) + name)) + +(df class>src-loc ((c ) => ) + (let* ((type (class>ref-type c)) + (locs (! all-line-locations type))) + (cond ((not (! isEmpty locs)) (1st locs)) + (#t ( (1st (! source-paths type "Java")) + #f))))) + +(df class>ref-type ((class ) => ) + (! reflectedType (as + (vm-mirror *the-vm* class)))) + +(df class>class-type ((class ) => ) + (as (class>ref-type class))) + +(df bytemethod>src-loc ((m ) => ) + (let* ((cls (class>class-type (! get-reflect-class + (! get-declaring-class m)))) + (name (! get-name m)) + (sig (! get-signature m)) + (meth (! concrete-method-by-name cls name sig))) + (! location meth))) + +(df src-loc>elisp ((l )) + (df src-loc>list ((l )) + (list (ignore-errors (! source-name l "Java")) + (ignore-errors (! source-path l "Java")) + (ignore-errors (! line-number l "Java")))) + (mcase (src-loc>list l) + ((name path line) + (cond ((not path) + `(:error ,(call-with-abort (fun () (! source-path l))))) + ((! starts-with (as path) "(buffer ") + (mlet (('buffer b 'offset o 'str s) (read-from-string path)) + `(:location (:buffer ,b) + (:position ,(+ o (line>offset line s))) + nil))) + (#t + `(:location ,(or (find-file-in-path name (source-path)) + (find-file-in-path path (source-path)) + (ferror "Can't find source-path: ~s ~s ~a" + path name (source-path))) + (:line ,(or line -1)) ())))))) + +(df src-loc>str ((l )) + (cond ((nul? l) "") + (#t (format "~a ~a ~a" + (or (ignore-errors (! source-path l)) + (ignore-errors (! source-name l)) + (ignore-errors (!! name declaring-type l))) + (ignore-errors (!! name method l)) + (ignore-errors (! lineNumber l)))))) + +;;;;;; class-path hacking + +;; (find-file-in-path "kawa/lib/kawa/hashtable.scm" (source-path)) + +(df find-file-in-path ((filename ) (path )) + (let ((f ( filename))) + (cond ((! isAbsolute f) `(:file ,filename)) + (#t (let ((result #f)) + (find-if path (fun (dir) + (let ((x (find-file-in-dir f dir))) + (set result x))) + #f) + result))))) + +(df find-file-in-dir ((file ) (dir )) + (let ((filename :: (! getPath file))) + (or (let ((child ( ( dir) filename))) + (and (! exists child) + `(:file ,(! getPath child)))) + (try-catch + (and (not (nul? (! getEntry ( dir) filename))) + `(:zip ,dir ,filename)) + (ex #f))))) + +(define swank-java-source-path + (let* ((jre-home :: (!s getProperty "java.home")) + (parent :: (! get-parent ( jre-home)))) + (list (! get-path ( parent "src.zip"))))) + +(df source-path () + (mlet ((base) (search-path-prop "user.dir")) + (append + (list base) + (map (fun ((s )) + (let ((f ( s)) + (base :: (as base))) + (cond ((! isAbsolute f) s) + (#t (! getPath ( base s)))))) + (class-path)) + swank-java-source-path))) + +(df class-path () + (append (search-path-prop "java.class.path") + (search-path-prop "sun.boot.class.path"))) + +(df search-path-prop ((name )) + (array-to-list (! split (!s java.lang.System getProperty name) + (@s pathSeparator)))) + +;;;; Disassemble + +(defslimefun disassemble-form (env form) + (mcase (read-from-string form) + (('quote name) + (let ((f (eval name env))) + (typecase f + ( + (disassemble-to-string (module-method>meth-ref f)))))))) + +(df disassemble-to-string ((mr ) => ) + (with-sink #f (fun (out) (disassemble-meth-ref mr out)))) + +(df disassemble-meth-ref ((mr ) (out )) + (let* ((t (! declaring-type mr))) + (disas-header mr out) + (disas-code (! constant-pool t) + (! constant-pool-count t) + (! bytecodes mr) + out))) + +(df disas-header ((mr ) (out )) + (let* ((++ (fun ((str )) (! write out str))) + (? (fun (flag str) (if flag (++ str))))) + (? (! is-static mr) "static ") + (? (! is-final mr) "final ") + (? (! is-private mr) "private ") + (? (! is-protected mr) "protected ") + (? (! is-public mr) "public ") + (++ (! name mr)) (++ (! signature mr)) (++ "\n"))) + +(df disas-code ((cpool ) (cpoolcount ) (bytecode ) + (out )) + (let* ((ct ( "foo")) + (met (! addMethod ct "bar" 0)) + (ca ( met)) + (constants (let* ((bs ()) + (s ( bs))) + (! write-short s cpoolcount) + (! write s cpool) + (! flush s) + (! toByteArray bs)))) + (vm-set-slot *the-vm* ct "constants" + ( + ( + ( + constants)))) + (! setCode ca bytecode) + (let ((w ( ct out 0))) + (! print ca w) + (! flush w)))) + +(df with-sink (sink (f )) + (cond ((instance? sink ) (f sink)) + ((== sink #t) (f (as (current-output-port)))) + ((== sink #f) + (let* ((buffer ()) + (out ( buffer))) + (f out) + (! flush out) + (! toString buffer))) + (#t (ferror "Invalid sink designator: ~s" sink)))) + +(df test-disas ((c ) (m )) + (let* ((vm (as *the-vm*)) + (c (as (1st (! classes-by-name vm c)))) + (m (as (1st (! methods-by-name c m))))) + (with-sink #f (fun (out) (disassemble-meth-ref m out))))) + +;; (test-disas "java.lang.Class" "toString") + + +;;;; Macroexpansion + +(defslimefun swank-expand-1 (env s) (%swank-macroexpand s env)) +(defslimefun swank-expand (env s) (%swank-macroexpand s env)) +(defslimefun swank-expand-all (env s) (%swank-macroexpand s env)) + +(df %swank-macroexpand (string env) + (pprint-to-string (%macroexpand (read-from-string string) env))) + +(df %macroexpand (sexp env) (expand sexp #:env env)) + + +;;;; Inspector + +(define-simple-class () + (object #:init #!null) + (parts :: #:init () ) + (stack :: #:init '()) + (content :: #:init '())) + +(df make-inspector (env (vm ) => ) + (car (spawn/chan (fun (c) (inspector c env vm))))) + +(df inspector ((c ) env (vm )) + (! set-name (current-thread) "inspector") + (let ((state :: ()) + (open #t)) + (while open + (mcase (recv c) + (('init str id) + (set state ()) + (let ((obj (try-catch (eval (read-from-string str) env) + (ex ex)))) + (reply c (inspect-object obj state vm) id))) + (('init-mirror cc id) + (set state ()) + (let* ((mirror (recv cc)) + (obj (vm-demirror vm mirror))) + (reply c (inspect-object obj state vm) id))) + (('inspect-part n id) + (let ((part (! get (@ parts state) n))) + (reply c (inspect-object part state vm) id))) + (('pop id) + (reply c (inspector-pop state vm) id)) + (('quit id) + (reply c 'nil id) + (set open #f)))))) + +(df inspect-object (obj (state ) (vm )) + (set (@ object state) obj) + (set (@ parts state) ()) + (pushf obj (@ stack state)) + (set (@ content state) (inspector-content + `("class: " (:value ,(! getClass obj)) "\n" + ,@(inspect obj vm)) + state)) + (cond ((nul? obj) (list ':title "#!null" ':id 0 ':content `())) + (#t + (list ':title (pprint-to-string obj) + ':id (assign-index obj state) + ':content (let ((c (@ content state))) + (content-range c 0 (len c))))))) + +(df inspect (obj vm) + (let ((obj (as (vm-mirror vm obj)))) + (typecase obj + ( (inspect-array-ref vm obj)) + ( (inspect-obj-ref vm obj))))) + +(df inspect-array-ref ((vm ) (obj )) + (packing (pack) + (let ((i 0)) + (for (((v :: ) (! getValues obj))) + (pack (format "~d: " i)) + (pack `(:value ,(vm-demirror vm v))) + (pack "\n") + (set i (1+ i)))))) + +(df inspect-obj-ref ((vm ) (obj )) + (let* ((type (! referenceType obj)) + (fields (! allFields type)) + (values (! getValues obj fields)) + (ifields '()) (sfields '()) (imeths '()) (smeths '()) + (frob (lambda (lists) (apply append (reverse lists))))) + (for (((f :: ) fields)) + (let* ((val (as (! get values f))) + (l `(,(! name f) ": " (:value ,(vm-demirror vm val)) "\n"))) + (if (! is-static f) + (pushf l sfields) + (pushf l ifields)))) + (for (((m :: ) (! allMethods type))) + (let ((l `(,(! name m) ,(! signature m) "\n"))) + (if (! is-static m) + (pushf l smeths) + (pushf l imeths)))) + `(,@(frob ifields) + "--- static fields ---\n" ,@(frob sfields) + "--- methods ---\n" ,@(frob imeths) + "--- static methods ---\n" ,@(frob smeths)))) + +(df inspector-content (content (state )) + (map (fun (part) + (mcase part + ((':value val) + `(:value ,(pprint-to-string val) ,(assign-index val state))) + (x (to-string x)))) + content)) + +(df assign-index (obj (state ) => ) + (! add (@ parts state) obj) + (1- (! size (@ parts state)))) + +(df content-range (l start end) + (let* ((len (length l)) (end (min len end))) + (list (subseq l start end) len start end))) + +(df inspector-pop ((state ) vm) + (cond ((<= 2 (len (@ stack state))) + (let ((obj (cadr (@ stack state)))) + (set (@ stack state) (cddr (@ stack state))) + (inspect-object obj state vm))) + (#t 'nil))) + +;;;; IO redirection + +(define-simple-class () + (q :: #:init ( (as 100))) + ((*init*) (invoke-special (this) '*init*)) + ((write (buffer :: ) (from :: ) (to :: )) :: + (synchronized (this) + (assert (not (== q #!null))) + (! put q `(write ,( buffer from to))))) + ((close) :: + (synchronized (this) + (! put q 'close) + (set! q #!null))) + ((flush) :: + (synchronized (this) + (assert (not (== q #!null))) + (let ((ex ())) + (! put q `(flush ,ex)) + (! exchange ex #!null))))) + +(df swank-writer ((in ) (q )) + (! set-name (current-thread) "swank-redirect-thread") + (let* ((out (as (recv in))) + (builder ()) + (flush (fun () + (unless (zero? (! length builder)) + (send out `(forward (:write-string ,( builder)))) + (! setLength builder 0)))) + (closed #f)) + (while (not closed) + (mcase (! poll q (as long 200) (@s MILLISECONDS)) + ('#!null (flush)) + (('write s) + (! append builder (as s)) + (when (> (! length builder) 4000) + (flush))) + (('flush ex) + (flush) + (! exchange (as ex) #!null)) + ('close + (set closed #t) + (flush)))))) + +(df make-swank-outport ((out )) + (let ((w ())) + (mlet ((in . _) (spawn/chan (fun (c) (swank-writer c (@ q w))))) + (send in out)) + ( w #t #t))) + + +;;;; Monitor + +;;(define-simple-class () +;; (threadmap type: (tab))) + +(df vm-monitor ((c )) + (! set-name (current-thread) "swank-vm-monitor") + (let ((vm (vm-attach))) + (log-vm-props vm) + (request-breakpoint vm) + (mlet* (((ev . _) (spawn/chan/catch + (fun (c) + (let ((q (! eventQueue vm))) + (while #t + (send c `(vm-event ,(to-list (! remove q))))))))) + (to-string (vm-to-string vm)) + (state (tab))) + (send c `(publish-vm ,vm)) + (while #t + (mcase (recv* (list c ev)) + ((_ . ('get-vm cc)) + (send cc vm)) + ((,c . ('debug-info thread from to id)) + (reply c (debug-info thread from to state) id)) + ((,c . ('throw-to-toplevel thread id)) + (set state (throw-to-toplevel thread id c state))) + ((,c . ('thread-continue thread id)) + (set state (thread-continue thread id c state))) + ((,c . ('frame-src-loc thread frame id)) + (reply c (frame-src-loc thread frame state) id)) + ((,c . ('frame-details thread frame id)) + (reply c (list (frame-locals thread frame state) '()) id)) + ((,c . ('disassemble-frame thread frame id)) + (reply c (disassemble-frame thread frame state) id)) + ((,c . ('thread-frames thread from to id)) + (reply c (thread-frames thread from to state) id)) + ((,c . ('list-threads id)) + (reply c (list-threads vm state) id)) + ((,c . ('interrupt-thread ref)) + (set state (interrupt-thread ref state c))) + ((,c . ('debug-nth-thread n)) + (let ((t (nth (get state 'all-threads #f) n))) + ;;(log "thread ~d : ~a\n" n t) + (set state (interrupt-thread t state c)))) + ((,c . ('quit-thread-browser id)) + (reply c 't id) + (set state (del state 'all-threads))) + ((,ev . ('vm-event es)) + ;;(log "vm-events: len=~a\n" (len es)) + (for (((e :: ) (as es))) + (set state (process-vm-event e c state)))) + ((_ . ('get-exception from tid)) + (mlet ((_ _ es) (get state tid #f)) + (send from (let ((e (car es))) + (typecase e + ( (! exception e)) + ( e)))))) + ((_ . ('get-local rc tid frame var)) + (send rc (frame-local-var tid frame var state))) + ))))) + +(df reply ((c ) value id) + (send c `(forward (:return (:ok ,value) ,id)))) + +(df reply-abort ((c ) id) + (send c `(forward (:return (:abort nil) ,id)))) + +(df process-vm-event ((e ) (c ) state) + ;;(log "vm-event: ~s\n" e) + (typecase e + ( + ;;(log "exception: ~s\n" (! exception e)) + ;;(log "exception-message: ~s\n" + ;; (exception-message (vm-demirror *the-vm* (! exception e)))) + ;;(log "exception-location: ~s\n" (src-loc>str (! location e))) + ;;(log "exception-catch-location: ~s\n" (src-loc>str (! catch-location e))) + (cond ((! notifyUncaught (as + (! request e))) + (process-exception e c state)) + (#t + (let* ((t (! thread e)) + (r (! request e)) + (ex (! exception e))) + (unless (eq? *last-exception* ex) + (set *last-exception* ex) + (set *last-stacktrace* (copy-stack t))) + (! resume t)) + state))) + ( + (let* ((r (! request e)) + (k (! get-property r 'continuation))) + (! disable r) + (log "k: ~s\n" k) + (k e)) + state) + ( + (log "breakpoint event: ~a\n" e) + (debug-thread (! thread e) e state c)) + )) + +(df process-exception ((e ) (c ) state) + (let* ((tref (! thread e)) + (tid (! uniqueID tref)) + (s (get state tid #f))) + (mcase s + ('#f + ;; XXX redundant in debug-thread + (let* ((level 1) + (state (put state tid (list tref level (list e))))) + (send c `(forward (:debug ,tid ,level + ,@(debug-info tid 0 15 state)))) + (send c `(forward (:debug-activate ,tid ,level))) + state)) + ((_ level exs) + (send c `(forward (:debug-activate ,(! uniqueID tref) ,level))) + (put state tid (list tref (1+ level) (cons e exs))))))) + +(define-simple-class () + (loc :: ) + (args) + (names) + (values :: ) + (self) + ((*init* (loc :: ) args names (values :: ) self) + (set (@ loc (this)) loc) + (set (@ args (this)) args) + (set (@ names (this)) names) + (set (@ values (this)) values) + (set (@ self (this)) self)) + ((toString) :: + (format "#" (src-loc>str loc)))) + +(df copy-stack ((t )) + (packing (pack) + (iter (! frames t) + (fun ((f )) + (let ((vars (ignore-errors (! visibleVariables f)))) + (pack ( + (or (ignore-errors (! location f)) #!null) + (ignore-errors (! getArgumentValues f)) + (or vars #!null) + (or (and vars (ignore-errors (! get-values f vars))) + #!null) + (ignore-errors (! thisObject f))))))))) + +(define-simple-class () + (thread :: ) + ((*init* (thread :: )) (set (@ thread (this)) thread)) + ((request) :: #!null) + ((virtualMachine) :: (! virtualMachine thread))) + +(df break (#!optional condition) + ((breakpoint condition))) + +;; We set a breakpoint on this function. It returns a function which +;; specifies what the debuggee should do next (the actual return value +;; is set via JDI). Lets hope that the compiler doesn't optimize this +;; away. +(df breakpoint (condition => ) + (fun () #!null)) + +;; Enable breakpoints event on the breakpoint function. +(df request-breakpoint ((vm )) + (let* ((swank-classes (! classesByName vm "swank-kawa")) + (swank-classes-legacy (! classesByName vm "swank$Mnkawa")) + (class :: (1st (if (= (length swank-classes) 0) + swank-classes-legacy + swank-classes))) + (meth :: (1st (! methodsByName class "breakpoint"))) + (erm (! eventRequestManager vm)) + (req (! createBreakpointRequest erm (! location meth)))) + (! setSuspendPolicy req (@ SUSPEND_EVENT_THREAD req)) + (! put-property req 'swank #t) + (! put-property req 'argname "condition") + (! enable req))) + +(df log-vm-props ((vm )) + (letrec-syntax ((p (syntax-rules () + ((p name) (log "~s: ~s\n" 'name (! name vm))))) + (p* (syntax-rules () + ((p* n ...) (seq (p n) ...))))) + (p* canBeModified + canRedefineClasses + canAddMethod + canUnrestrictedlyRedefineClasses + canGetBytecodes + canGetConstantPool + canGetSyntheticAttribute + canGetSourceDebugExtension + canPopFrames + canForceEarlyReturn + canGetMethodReturnValues + canGetInstanceInfo + ))) + +;;;;; Debugger + +(df debug-thread ((tref ) (ev ) state (c )) + (unless (! is-suspended tref) + (! suspend tref)) + (let* ((id (! uniqueID tref)) + (level 1) + (state (put state id (list tref level (list ev))))) + (send c `(forward (:debug ,id ,level ,@(debug-info id 0 10 state)))) + (send c `(forward (:debug-activate ,id ,level))) + state)) + +(df interrupt-thread ((tref ) state (c )) + (debug-thread tref ( tref) state c)) + +(df debug-info ((tid ) (from ) to state) + (mlet ((thread-ref level evs) (get state tid #f)) + (let* ((tref (as thread-ref)) + (vm (! virtualMachine tref)) + (ev (as (car evs))) + (ex (typecase ev + ( (breakpoint-condition ev)) + ( (! exception ev)) + ( ( "Interrupt")))) + (desc (typecase ex + ( + ;;(log "ex: ~a ~a\n" ex (vm-demirror vm ex)) + (! toString (vm-demirror vm ex))) + ( (! toString ex)))) + (type (format " [type ~a]" + (typecase ex + ( (! name (! referenceType ex))) + ( (!! getName getClass ex))))) + (bt (thread-frames tid from to state))) + `((,desc ,type nil) (("quit" "terminate current thread")) ,bt ())))) + +(df breakpoint-condition ((e ) => ) + (let ((frame (! frame (! thread e) 0))) + (1st (! get-argument-values frame)))) + +(df thread-frames ((tid ) (from ) to state) + (mlet ((thread level evs) (get state tid #f)) + (let* ((thread (as thread)) + (fcount (! frameCount thread)) + (stacktrace (event-stacktrace (car evs))) + (missing (cond ((zero? (len stacktrace)) 0) + (#t (- (len stacktrace) fcount)))) + (fstart (max (- from missing) 0)) + (flen (max (- to from missing) 0)) + (frames (! frames thread fstart (min flen (- fcount fstart))))) + (packing (pack) + (let ((i from)) + (dotimes (_ (max (- missing from) 0)) + (pack (list i (format "~a" (stacktrace i)))) + (set i (1+ i))) + (iter frames (fun ((f )) + (let ((s (frame-to-string f))) + (pack (list i s)) + (set i (1+ i)))))))))) + +(df event-stacktrace ((ev )) + (let ((nothing (fun () ())) + (vm (! virtualMachine ev))) + (typecase ev + ( + (let ((condition (vm-demirror vm (breakpoint-condition ev)))) + (cond ((instance? condition ) + (throwable-stacktrace vm condition)) + (#t (nothing))))) + ( + (throwable-stacktrace vm (vm-demirror vm (! exception ev)))) + ( (nothing))))) + +(df throwable-stacktrace ((vm ) (ex )) + (cond ((== ex (ignore-errors (vm-demirror vm *last-exception*))) + *last-stacktrace*) + (#t + (! getStackTrace ex)))) + +(df frame-to-string ((f )) + (let ((loc (! location f)) + (vm (! virtualMachine f))) + (format "~a (~a)" (!! name method loc) + (call-with-abort + (fun () (format "~{~a~^ ~}" + (mapi (! getArgumentValues f) + (fun (arg) + (pprint-to-string + (vm-demirror vm arg)))))))))) + +(df frame-src-loc ((tid ) (n ) state) + (try-catch + (mlet* (((frame vm) (nth-frame tid n state)) + (vm (as vm))) + (src-loc>elisp + (typecase frame + ( (! location frame)) + ( (@ loc frame)) + ( + (let* ((classname (! getClassName frame)) + (classes (! classesByName vm classname)) + (t (as (1st classes)))) + (1st (! locationsOfLine t (! getLineNumber frame)))))))) + (ex + (let ((msg (! getMessage ex))) + `(:error ,(if (== msg #!null) + (! toString ex) + msg)))))) + +(df nth-frame ((tid ) (n ) state) + (mlet ((tref level evs) (get state tid #f)) + (let* ((thread (as tref)) + (fcount (! frameCount thread)) + (stacktrace (event-stacktrace (car evs))) + (missing (cond ((zero? (len stacktrace)) 0) + (#t (- (len stacktrace) fcount)))) + (vm (! virtualMachine thread)) + (frame (cond ((< n missing) + (stacktrace n)) + (#t (! frame thread (- n missing)))))) + (list frame vm)))) + +;;;;; Locals + +(df frame-locals ((tid ) (n ) state) + (mlet ((thread _ _) (get state tid #f)) + (let* ((thread (as thread)) + (vm (! virtualMachine thread)) + (p (fun (x) (pprint-to-string + (call-with-abort (fun () (vm-demirror vm x))))))) + (map (fun (x) + (mlet ((name value) x) + (list ':name name ':value (p value) ':id 0))) + (%frame-locals tid n state))))) + +(df frame-local-var ((tid ) (frame ) (var ) state => ) + (cadr (nth (%frame-locals tid frame state) var))) + +(df %frame-locals ((tid ) (n ) state) + (mlet ((frame _) (nth-frame tid n state)) + (typecase frame + ( + (let* ((visible (try-catch (! visibleVariables frame) + (ex + '()))) + (map (! getValues frame visible)) + (p (fun (x) x))) + (packing (pack) + (let ((self (ignore-errors (! thisObject frame)))) + (when self + (pack (list "this" (p self))))) + (iter (! entrySet map) + (fun ((e )) + (let ((var (as (! getKey e))) + (val (as (! getValue e)))) + (pack (list (! name var) (p val))))))))) + ( + (packing (pack) + (when (@ self frame) + (pack (list "this" (@ self frame)))) + (iter (! entrySet (@ values frame)) + (fun ((e )) + (let ((var (as (! getKey e))) + (val (as (! getValue e)))) + (pack (list (! name var) val))))))) + ( '())))) + +(df disassemble-frame ((tid ) (frame ) state) + (mlet ((frame _) (nth-frame tid frame state)) + (typecase frame + ( "") + ( + (let* ((l (! location frame)) + (m (! method l)) + (c (! declaringType l))) + (disassemble-to-string m)))))) + +;;;;; Restarts + +;; FIXME: factorize +(df throw-to-toplevel ((tid ) (id ) (c ) state) + (mlet ((tref level exc) (get state tid #f)) + (let* ((t (as tref)) + (ev (car exc))) + (typecase ev + ( ; actually uncaughtException + (! resume t) + (reply-abort c id) + ;;(send-debug-return c tid state) + (do ((level level (1- level)) + (exc exc (cdr exc))) + ((null? exc)) + (send c `(forward (:debug-return ,tid ,level nil)))) + (del state tid)) + ( + ;; XXX race condition? + (log "resume from from break (suspendCount: ~d)\n" (! suspendCount t)) + (let ((vm (! virtualMachine t)) + (k (fun () (primitive-throw ())))) + (reply-abort c id) + (! force-early-return t (vm-mirror vm k)) + (! resume t) + (do ((level level (1- level)) + (exc exc (cdr exc))) + ((null? exc)) + (send c `(forward (:debug-return ,tid ,level nil)))) + (del state tid))) + ( + (log "resume from from interrupt\n") + (let ((vm (! virtualMachine t))) + (! stop t (vm-mirror vm ())) + (! resume t) + (reply-abort c id) + (do ((level level (1- level)) + (exc exc (cdr exc))) + ((null? exc)) + (send c `(forward (:debug-return ,tid ,level nil)))) + (del state tid)) + ))))) + +(df thread-continue ((tid ) (id ) (c ) state) + (mlet ((tref level exc) (get state tid #f)) + (log "thread-continue: ~a ~a ~a \n" tref level exc) + (let* ((t (as tref))) + (! resume t)) + (reply-abort c id) + (do ((level level (1- level)) + (exc exc (cdr exc))) + ((null? exc)) + (send c `(forward (:debug-return ,tid ,level nil)))) + (del state tid))) + +(df thread-step ((t ) k) + (let* ((vm (! virtual-machine t)) + (erm (! eventRequestManager vm)) + ( ) + (req (! createStepRequest erm t + (@s STEP_MIN) + (@s STEP_OVER)))) + (! setSuspendPolicy req (@ SUSPEND_EVENT_THREAD req)) + (! addCountFilter req 1) + (! put-property req 'continuation k) + (! enable req))) + +(df eval-in-thread ((t ) sexp + #!optional (env :: (!s current))) + (let* ((vm (! virtualMachine t)) + (sc :: + (1st (! classes-by-name vm "kawa.standard.Scheme"))) + (ev :: + (1st (! methods-by-name sc "eval" + (cat "(Ljava/lang/Object;Lgnu/mapping/Environment;)" + "Ljava/lang/Object;"))))) + (! invokeMethod sc t ev (list sexp env) + (@s INVOKE_SINGLE_THREADED)))) + +;;;;; Threads + +(df list-threads (vm :: state) + (let* ((threads (! allThreads vm))) + (put state 'all-threads threads) + (packing (pack) + (pack '(\:id \:name \:status \:priority)) + (iter threads (fun ((t )) + (pack (list (! uniqueID t) + (! name t) + (let ((s (thread-status t))) + (if (! is-suspended t) + (cat "SUSPENDED/" s) + s)) + 0))))))) + +(df thread-status (t :: ) + (let ((s (! status t))) + (cond ((= s (@s THREAD_STATUS_UNKNOWN)) "UNKNOWN") + ((= s (@s THREAD_STATUS_ZOMBIE)) "ZOMBIE") + ((= s (@s THREAD_STATUS_RUNNING)) "RUNNING") + ((= s (@s THREAD_STATUS_SLEEPING)) "SLEEPING") + ((= s (@s THREAD_STATUS_MONITOR)) "MONITOR") + ((= s (@s THREAD_STATUS_WAIT)) "WAIT") + ((= s (@s THREAD_STATUS_NOT_STARTED)) "NOT_STARTED") + (#t "")))) + +;;;;; Bootstrap + +(df vm-attach (=> ) + (attach (getpid) 20)) + +(df attach (pid timeout) + (log "attaching: ~a ~a\n" pid timeout) + (let* (( ) + ( ) + (vmm (!s com.sun.jdi.Bootstrap virtualMachineManager)) + (pa (as + (or + (find-if (! attaching-connectors vmm) + (fun (x :: ) + (! equals (! name x) "com.sun.jdi.ProcessAttach")) + #f) + (error "ProcessAttach connector not found")))) + (args (! default-arguments pa))) + (! set-value (as (! get args (to-str "pid"))) pid) + (when timeout + (! set-value (as (! get args (to-str "timeout"))) timeout)) + (log "attaching2: ~a ~a\n" pa args) + (! attach pa args))) + +(df getpid () + (let ((p (make-process (command-parse "echo $PPID") #!null))) + (! waitFor p) + (! read-line ( ( (! get-input-stream p)))))) + +(df request-uncaught-exception-events ((vm )) + (let* ((erm (! eventRequestManager vm)) + (req (! createExceptionRequest erm #!null #f #t))) + (! setSuspendPolicy req (@ SUSPEND_EVENT_THREAD req)) + (! addThreadFilter req (vm-mirror vm (current-thread))) + (! enable req))) + + +(df request-caught-exception-events ((vm )) + (let* ((erm (! eventRequestManager vm)) + (req (! createExceptionRequest erm #!null #t #f))) + (! setSuspendPolicy req (@ SUSPEND_EVENT_THREAD req)) + (! addThreadFilter req (vm-mirror vm (current-thread))) + (! addClassExclusionFilter req "java.lang.ClassLoader") + (! addClassExclusionFilter req "java.net.URLClassLoader") + (! addClassExclusionFilter req "java.net.URLClassLoader$1") + (! enable req))) + +(df set-stacktrace-recording ((vm ) (flag )) + (for (((e :: ) + (!! exceptionRequests eventRequestManager vm))) + (when (! notify-caught e) + (! setEnabled e flag)))) + +;; (set-stacktrace-recording *the-vm* #f) + +(df vm-to-string ((vm )) + (let* ((obj (as (1st (! classesByName vm "java.lang.Object")))) + (met (as (1st (! methodsByName obj "toString"))))) + (fun ((o ) (t )) + (! value + (as + (! invokeMethod o t met '() + (@s INVOKE_SINGLE_THREADED))))))) + +(define-simple-class () + (var #:allocation 'static)) + +(define-variable *global-get-mirror* #!null) +(define-variable *global-set-mirror* #!null) +(define-variable *global-get-raw* #!null) +(define-variable *global-set-raw* #!null) + +(df init-global-field ((vm )) + (when (nul? *global-get-mirror*) + (set (@s var) #!null) ; prepare class + (let* ((swank-global-variable-classes + (! classes-by-name vm "swank-global-variable")) + (swank-global-variable-classes-legacy + (! classes-by-name vm "swank$Mnglobal$Mnvariable")) + (c (as + (1st (if (= (length swank-global-variable-classes) 0) + swank-global-variable-classes-legacy + swank-global-variable-classes)))) + (f (! fieldByName c "var"))) + (set *global-get-mirror* (fun () (! getValue c f))) + (set *global-set-mirror* (fun ((v )) (! setValue c f v)))) + (set *global-get-raw* (fun () '() (@s var))) + (set *global-set-raw* (fun (x) + (set (@s var) x))))) + +(df vm-mirror ((vm ) obj) + (synchronized vm + (init-global-field vm) + (*global-set-raw* obj) + (*global-get-mirror*))) + +(df vm-demirror ((vm ) (v )) + (synchronized vm + (if (== v #!null) + #!null + (typecase v + ( (init-global-field vm) + (*global-set-mirror* v) + (*global-get-raw*)) + ( (! value v)) + ( (! value v)) + ( (! value v)) + ( (! value v)) + ( (! value v)) + ( (! value v)) + ( (! value v)) + ( (! value v)))))) + +(df vm-set-slot ((vm ) (o ) (name ) value) + (let* ((o (as (vm-mirror vm o))) + (t (! reference-type o)) + (f (! field-by-name t name))) + (! set-value o f (vm-mirror vm value)))) + +(define-simple-class + () + (f :: ) + ((*init* (f :: )) (set (@ f (this)) f)) + ((uncaughtException (t :: ) (e :: )) + :: + (! println (@s java.lang.System err) (to-str "uhexc:::")) + (! apply2 f t e) + #!void)) + +;;;; Channels + +(df spawn (f) + (let ((thread ( (%%runnable f)))) + (! start thread) + thread)) + + +;; gnu.mapping.RunnableClosure uses the try{...}catch(Throwable){...} +;; idiom which defeats all attempts to use a break-on-error-style +;; debugger. Previously I had my own version of RunnableClosure +;; without that deficiency but something in upstream changed and it no +;; longer worked. Now we use the normal RunnableClosure and at the +;; cost of taking stack snapshots on every throw. +(df %%runnable (f => ) + ;;( f) + ;;( f) + ;;(runnable f) + (%runnable f) + ) + +(df %runnable (f => ) + (runnable + (fun () + (try-catch (f) + (ex + (log "exception in thread ~s: ~s" (current-thread) + ex) + (! printStackTrace ex)))))) + +(df chan () + (let ((lock ()) + (im ()) + (ex ())) + (set (@ lock im) lock) + (set (@ lock ex) lock) + (set (@ peer im) ex) + (set (@ peer ex) im) + (cons im ex))) + +(df immutable? (obj) + (or (== obj #!null) + (symbol? obj) + (number? obj) + (char? obj) + (instance? obj ) + (null? obj))) + +(df send ((c ) value => ) + (df pass (obj) + (cond ((immutable? obj) obj) + ((string? obj) (! to-string obj)) + ((pair? obj) + (let loop ((r (list (pass (car obj)))) + (o (cdr obj))) + (cond ((null? o) (reverse! r)) + ((pair? o) (loop (cons (pass (car o)) r) (cdr o))) + (#t (append (reverse! r) (pass o)))))) + ((instance? obj ) + (let ((o :: obj)) + (assert (== (@ owner o) (current-thread))) + (synchronized (@ lock c) + (set (@ owner o) (@ owner (@ peer c)))) + o)) + ((or (instance? obj ) + (instance? obj )) + ;; those can be shared, for pragmatic reasons + obj + ) + (#t (error "can't send" obj (class-name-sans-package obj))))) + ;;(log "send: ~s ~s -> ~s\n" value (@ owner c) (@ owner (@ peer c))) + (assert (== (@ owner c) (current-thread))) + ;;(log "lock: ~s send\n" (@ owner (@ peer c))) + (synchronized (@ owner (@ peer c)) + (! put (@ queue (@ peer c)) (pass value)) + (! notify (@ owner (@ peer c)))) + ;;(log "unlock: ~s send\n" (@ owner (@ peer c))) + ) + +(df recv ((c )) + (cdr (recv/timeout (list c) 0))) + +(df recv* ((cs )) + (recv/timeout cs 0)) + +(df recv/timeout ((cs ) (timeout )) + (let ((self (current-thread)) + (end (if (zero? timeout) + 0 + (+ (current-time) timeout)))) + ;;(log "lock: ~s recv\n" self) + (synchronized self + (let loop () + ;;(log "receive-loop: ~s\n" self) + (let ((ready (find-if cs + (fun ((c )) + (not (! is-empty (@ queue c)))) + #f))) + (cond (ready + ;;(log "unlock: ~s recv\n" self) + (cons ready (! take (@ queue (as ready))))) + ((zero? timeout) + ;;(log "wait: ~s recv\n" self) + (! wait self) (loop)) + (#t + (let ((now (current-time))) + (cond ((<= end now) + 'timeout) + (#t + ;;(log "wait: ~s recv\n" self) + (! wait self (- end now)) + (loop))))))))))) + +(df rpc ((c ) msg) + (mlet* (((im . ex) (chan)) + ((op . args) msg)) + (send c `(,op ,ex . ,args)) + (recv im))) + +(df spawn/chan (f) + (mlet ((im . ex) (chan)) + (let ((thread ( (%%runnable (fun () (f ex)))))) + (set (@ owner ex) thread) + (! start thread) + (cons im thread)))) + +(df spawn/chan/catch (f) + (spawn/chan + (fun (c) + (try-catch + (f c) + (ex + (send c `(error ,(! toString ex) + ,(class-name-sans-package ex) + ,(map (fun (e) (! to-string e)) + (array-to-list (! get-stack-trace ex)))))))))) + +;;;; Logging + +(define swank-log-port (current-error-port)) +(df log (fstr #!rest args) + (synchronized swank-log-port + (apply format swank-log-port fstr args) + (force-output swank-log-port)) + #!void) + +;;;; Random helpers + +(df 1+ (x) (+ x 1)) +(df 1- (x) (- x 1)) + +(df len (x => ) + (typecase x + ( (length x)) + ( (! length x)) + ( (string-length x)) + ( (vector-length x)) + ( (! size x)) + ( (@ length x)))) + +;;(df put (tab key value) (hash-table-set! tab key value) tab) +;;(df get (tab key default) (hash-table-ref/default tab key default)) +;;(df del (tab key) (hash-table-delete! tab key) tab) +;;(df tab () (make-hash-table)) + +(df put (tab key value) (hashtable-set! tab key value) tab) +(df get (tab key default) (hashtable-ref tab key default)) +(df del (tab key) (hashtable-delete! tab key) tab) +(df tab () (make-eqv-hashtable)) + +(df equal (x y => ) (equal? x y)) + +(df current-thread (=> ) (!s java.lang.Thread currentThread)) +(df current-time (=> ) (!s java.lang.System currentTimeMillis)) + +(df nul? (x) (== x #!null)) + +(df read-from-string (str) + (call-with-input-string str read)) + +;;(df print-to-string (obj) (call-with-output-string (fun (p) (write obj p)))) + +(df pprint-to-string (obj) + (let* ((w ()) + (p ( w #t #f))) + (try-catch (print-object obj p) + (ex + (format p "#" + ex (class-name-sans-package ex)))) + (! flush p) + (to-string (! getBuffer w)))) + +(df print-object (obj stream) + (typecase obj + #; + ((or (eql #!null) (eql #!eof) + ) + (write obj stream)) + (#t + #;(print-unreadable-object obj stream) + (write obj stream) + ))) + +(df print-unreadable-object ((o ) stream) + (let* ((string (! to-string o)) + (class (! get-class o)) + (name (! get-name class)) + (simplename (! get-simple-name class))) + (cond ((! starts-with string "#<") + (format stream "~a" string)) + ((or (! starts-with string name) + (! starts-with string simplename)) + (format stream "#<~a>" string)) + (#t + (format stream "#<~a ~a>" name string))))) + +(define cat string-append) + +(df values-to-list (values) + (typecase values + ( (array-to-list (! getValues values))) + ( (list values)))) + +;; (to-list (as-list (values 1 2 2))) + +(df array-to-list ((array ) => ) + (packing (pack) + (dotimes (i (@ length array)) + (pack (array i))))) + +(df lisp-bool (obj) + (cond ((== obj 'nil) #f) + ((== obj 't) #t) + (#t (error "Can't map lisp boolean" obj)))) + +(df path-sans-extension ((p path) => ) + (let ((ex (! get-extension p)) + (str (! to-string p))) + (to-string (cond ((not ex) str) + (#t (! substring str 0 (- (len str) (len ex) 1))))))) + +(df class-name-sans-package ((obj )) + (cond ((nul? obj) "<#!null>") + (#t + (try-catch + (let* ((c (! get-class obj)) + (n (! get-simple-name c))) + (cond ((equal n "") (! get-name c)) + (#t n))) + (e + (format "#<~a: ~a>" e (! get-message e))))))) + +(df list-env (#!optional (env :: (!s current))) + (let ((enum (! enumerateAllLocations env))) + (packing (pack) + (while (! hasMoreElements enum) + (pack (! nextLocation enum)))))) + +(df list-file (filename) + (with (port (call-with-input-file filename)) + (let* ((lang (!s gnu.expr.Language getDefaultLanguage)) + (messages ()) + (comp (! parse lang (as port) messages 0))) + (! get-module comp)))) + +(df list-decls (file) + (let* ((module (as (list-file file)))) + (do ((decl :: + (! firstDecl module) (! nextDecl decl))) + ((nul? decl)) + (format #t "~a ~a:~d:~d\n" decl + (! getFileName decl) + (! getLineNumber decl) + (! getColumnNumber decl) + )))) + +(df %time (f) + (define-alias ) + (define-alias ) + (let* ((gcs (!s getGarbageCollectorMXBeans)) + (mem (!s getMemoryMXBean)) + (jit (!s getCompilationMXBean)) + (oldjit (! getTotalCompilationTime jit)) + (oldgc (packing (pack) + (iter gcs (fun ((gc )) + (pack (cons gc + (list (! getCollectionCount gc) + (! getCollectionTime gc)))))))) + (heap (!! getUsed getHeapMemoryUsage mem)) + (nonheap (!! getUsed getNonHeapMemoryUsage mem)) + (start (!s java.lang.System nanoTime)) + (values (f)) + (end (!s java.lang.System nanoTime)) + (newheap (!! getUsed getHeapMemoryUsage mem)) + (newnonheap (!! getUsed getNonHeapMemoryUsage mem))) + (format #t "~&") + (let ((njit (! getTotalCompilationTime jit))) + (format #t "; JIT compilation: ~:d ms (~:d)\n" (- njit oldjit) njit)) + (iter gcs (fun ((gc )) + (mlet ((_ count time) (assoc gc oldgc)) + (format #t "; GC ~a: ~:d ms (~d)\n" + (! getName gc) + (- (! getCollectionTime gc) time) + (- (! getCollectionCount gc) count))))) + (format #t "; Heap: ~@:d (~:d)\n" (- newheap heap) newheap) + (format #t "; Non-Heap: ~@:d (~:d)\n" (- newnonheap nonheap) newnonheap) + (format #t "; Elapsed time: ~:d us\n" (/ (- end start) 1000)) + values)) + +(define-syntax time + (syntax-rules () + ((time form) + (%time (lambda () form))))) + +(df gc () + (let* ((mem (!s java.lang.management.ManagementFactory getMemoryMXBean)) + (oheap (!! getUsed getHeapMemoryUsage mem)) + (onheap (!! getUsed getNonHeapMemoryUsage mem)) + (_ (! gc mem)) + (heap (!! getUsed getHeapMemoryUsage mem)) + (nheap (!! getUsed getNonHeapMemoryUsage mem))) + (format #t "; heap: ~@:d (~:d) non-heap: ~@:d (~:d)\n" + (- heap oheap) heap (- onheap nheap) nheap))) + +(df room () + (let* ((pools (!s java.lang.management.ManagementFactory + getMemoryPoolMXBeans)) + (mem (!s java.lang.management.ManagementFactory getMemoryMXBean)) + (heap (!! getUsed getHeapMemoryUsage mem)) + (nheap (!! getUsed getNonHeapMemoryUsage mem))) + (iter pools (fun ((p )) + (format #t "~&; ~a~1,16t: ~10:d\n" + (! getName p) + (!! getUsed getUsage p)))) + (format #t "; Heap~1,16t: ~10:d\n" heap) + (format #t "; Non-Heap~1,16t: ~10:d\n" nheap))) + +;; (df javap (class #!key method signature) +;; (let* (( ) +;; (bytes +;; (typecase class +;; ( (read-bytes ( (to-str class)))) +;; ( class) +;; ( (read-class-file class)))) +;; (cdata ( ( bytes))) +;; (p ( +;; ( bytes) +;; (current-output-port) +;; ()))) +;; (cond (method +;; (dolist ((m ) +;; (array-to-list (! getMethods cdata))) +;; (when (and (equal (to-str method) (! getName m)) +;; (or (not signature) +;; (equal signature (! getInternalSig m)))) +;; (! printMethodSignature p m (! getAccess m)) +;; (! printExceptions p m) +;; (newline) +;; (! printVerboseHeader p m) +;; (! printcodeSequence p m)))) +;; (#t (p:print))) +;; (values))) + +(df read-bytes ((is ) => ) + (let ((os ())) + (let loop () + (let ((c (! read is))) + (cond ((= c -1)) + (#t (! write os c) (loop))))) + (! to-byte-array os))) + +(df read-class-file ((name ) => ) + (let ((f (cat (! replace (to-str name) (as #\.) (as #\/)) + ".class"))) + (mcase (find-file-in-path f (class-path)) + ('#f (ferror "Can't find classfile for ~s" name)) + ((:zip zipfile entry) + (let* ((z ( (as zipfile))) + (e (! getEntry z (as entry)))) + (read-bytes (! getInputStream z e)))) + ((:file s) (read-bytes ( (as s))))))) + +(df all-instances ((vm ) (classname )) + (mappend (fun ((c )) (to-list (! instances c (as long 9999)))) + (%all-subclasses vm classname))) + +(df %all-subclasses ((vm ) (classname )) + (mappend (fun ((c )) (cons c (to-list (! subclasses c)))) + (to-list (! classes-by-name vm classname)))) + +(df with-output-to-string (thunk => ) + (call-with-output-string + (fun (s) (parameterize ((current-output-port s)) (thunk))))) + +(df find-if ((i ) test default) + (let ((iter (! iterator i)) + (found #f)) + (while (and (not found) (! has-next iter)) + (let ((e (! next iter))) + (when (test e) + (set found #t) + (set default e)))) + default)) + +(df filter ((i ) test => ) + (packing (pack) + (for ((e i)) + (when (test e) + (pack e))))) + +(df iter ((i ) f) + (for ((e i)) (f e))) + +(df mapi ((i ) f => ) + (packing (pack) (for ((e i)) (pack (f e))))) + +(df nth ((i ) (n )) + (let ((iter (! iterator i))) + (dotimes (i n) + (! next iter)) + (! next iter))) + +(df 1st ((i )) (!! next iterator i)) + +(df to-list ((i ) => ) + (packing (pack) (for ((e i)) (pack e)))) + +(df as-list ((o ) => ) + (!s java.util.Arrays asList o)) + +(df mappend (f list) + (apply append (map f list))) + +(df subseq (s from to) + (typecase s + ( (apply list (! sub-list s from to))) + ( (apply vector (! sub-list s from to))) + ( (! substring s from to)) + ( (let* ((len (as (- to from))) + (t ( #:length len))) + (!s java.lang.System arraycopy s from t 0 len) + t)))) + +(df to-string (obj => ) + (typecase obj + ( ( obj)) + ((satisfies string?) obj) + ((satisfies symbol?) (symbol->string obj)) + ( ( obj)) + ( ( obj)) + (#t (error "Not a string designator" obj + (class-name-sans-package obj))))) + +(df to-str (obj => ) + (cond ((instance? obj ) obj) + ((string? obj) (! toString obj)) + ((symbol? obj) (! getName (as obj))) + (#t (error "Not a string designator" obj + (class-name-sans-package obj))))) + +)) + +;; Local Variables: +;; mode: goo +;; compile-command: "\ +;; rm -rf classes && \ +;; JAVA_OPTS=-Xss2M kawa --r7rs -d classes -C swank-kawa.scm && \ +;; jar cf swank-kawa.jar -C classes ." +;; End: diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-larceny.scm b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-larceny.scm new file mode 100644 index 0000000..e4d730d --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-larceny.scm @@ -0,0 +1,176 @@ +;; swank-larceny.scm --- Swank server for Larceny +;; +;; License: Public Domain +;; Author: Helmut Eller +;; +;; In a shell execute: +;; larceny -r6rs -program swank-larceny.scm +;; and then `M-x slime-connect' in Emacs. + +(library (swank os) + (export getpid make-server-socket accept local-port close-socket) + (import (rnrs) + (primitives foreign-procedure + ffi/handle->address + ffi/string->asciiz + sizeof:pointer + sizeof:int + %set-pointer + %get-int)) + + (define getpid (foreign-procedure "getpid" '() 'int)) + (define fork (foreign-procedure "fork" '() 'int)) + (define close (foreign-procedure "close" '(int) 'int)) + (define dup2 (foreign-procedure "dup2" '(int int) 'int)) + + (define bytevector-content-offset$ sizeof:pointer) + + (define execvp% (foreign-procedure "execvp" '(string boxed) 'int)) + (define (execvp file . args) + (let* ((nargs (length args)) + (argv (make-bytevector (* (+ nargs 1) + sizeof:pointer)))) + (do ((offset 0 (+ offset sizeof:pointer)) + (as args (cdr as))) + ((null? as)) + (%set-pointer argv + offset + (+ (ffi/handle->address (ffi/string->asciiz (car as))) + bytevector-content-offset$))) + (%set-pointer argv (* nargs sizeof:pointer) 0) + (execvp% file argv))) + + (define pipe% (foreign-procedure "pipe" '(boxed) 'int)) + (define (pipe) + (let ((array (make-bytevector (* sizeof:int 2)))) + (let ((r (pipe% array))) + (values r (%get-int array 0) (%get-int array sizeof:int))))) + + (define (fork/exec file . args) + (let ((pid (fork))) + (cond ((= pid 0) + (apply execvp file args)) + (#t pid)))) + + (define (start-process file . args) + (let-values (((r1 down-out down-in) (pipe)) + ((r2 up-out up-in) (pipe)) + ((r3 err-out err-in) (pipe))) + (assert (= 0 r1)) + (assert (= 0 r2)) + (assert (= 0 r3)) + (let ((pid (fork))) + (case pid + ((-1) + (error "Failed to fork a subprocess.")) + ((0) + (close up-out) + (close err-out) + (close down-in) + (dup2 down-out 0) + (dup2 up-in 1) + (dup2 err-in 2) + (apply execvp file args) + (exit 1)) + (else + (close down-out) + (close up-in) + (close err-in) + (list pid + (make-fd-io-stream up-out down-in) + (make-fd-io-stream err-out err-out))))))) + + (define (make-fd-io-stream in out) + (let ((write (lambda (bv start count) (fd-write out bv start count))) + (read (lambda (bv start count) (fd-read in bv start count))) + (closeit (lambda () (close in) (close out)))) + (make-custom-binary-input/output-port + "fd-stream" read write #f #f closeit))) + + (define write% (foreign-procedure "write" '(int ulong int) 'int)) + (define (fd-write fd bytevector start count) + (write% fd + (+ (ffi/handle->address bytevector) + bytevector-content-offset$ + start) + count)) + + (define read% (foreign-procedure "read" '(int ulong int) 'int)) + (define (fd-read fd bytevector start count) + ;;(printf "fd-read: ~a ~s ~a ~a\n" fd bytevector start count) + (read% fd + (+ (ffi/handle->address bytevector) + bytevector-content-offset$ + start) + count)) + + (define (make-server-socket port) + (let* ((args `("/bin/bash" "bash" + "-c" + ,(string-append + "netcat -s 127.0.0.1 -q 0 -l -v " + (if port + (string-append "-p " (number->string port)) + "")))) + (nc (apply start-process args)) + (err (transcoded-port (list-ref nc 2) + (make-transcoder (latin-1-codec)))) + (line (get-line err)) + (pos (last-index-of line '#\]))) + (cond (pos + (let* ((tail (substring line (+ pos 1) (string-length line))) + (port (get-datum (open-string-input-port tail)))) + (list (car nc) (cadr nc) err port))) + (#t (error "netcat failed: " line))))) + + (define (accept socket codec) + (let* ((line (get-line (caddr socket))) + (pos (last-index-of line #\]))) + (cond (pos + (close-port (caddr socket)) + (let ((stream (cadr socket))) + (let ((io (transcoded-port stream (make-transcoder codec)))) + (values io io)))) + (else (error "accept failed: " line))))) + + (define (local-port socket) + (list-ref socket 3)) + + (define (last-index-of str chr) + (let loop ((i (string-length str))) + (cond ((<= i 0) #f) + (#t (let ((i (- i 1))) + (cond ((char=? (string-ref str i) chr) + i) + (#t + (loop i)))))))) + + (define (close-socket socket) + ;;(close-port (cadr socket)) + #f + ) + + ) + +(library (swank sys) + (export implementation-name eval-in-interaction-environment) + (import (rnrs) + (primitives system-features + aeryn-evaluator)) + + (define (implementation-name) "larceny") + + ;; see $LARCENY/r6rsmode.sch: + ;; Larceny's ERR5RS and R6RS modes. + ;; Code names: + ;; Aeryn ERR5RS + ;; D'Argo R6RS-compatible + ;; Spanky R6RS-conforming (not yet implemented) + (define (eval-in-interaction-environment form) + (aeryn-evaluator form)) + + ) + +(import (rnrs) (rnrs eval) (larceny load)) +(load "swank-r6rs.scm") +(eval '(start-server #f) (environment '(swank))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-listener-hooks.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-listener-hooks.lisp new file mode 100644 index 0000000..f289c90 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-listener-hooks.lisp @@ -0,0 +1,91 @@ +;;; swank-listener-hooks.lisp --- listener with special hooks +;; +;; Author: Alan Ruttenberg + +;; Provides *slime-repl-eval-hooks* special variable which +;; can be used for easy interception of SLIME REPL form evaluation +;; for purposes such as integration with application event loop. + +(in-package :swank) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (swank-require :swank-repl)) + +(defvar *slime-repl-advance-history* nil + "In the dynamic scope of a single form typed at the repl, is set to nil to + prevent the repl from advancing the history - * ** *** etc.") + +(defvar *slime-repl-suppress-output* nil + "In the dynamic scope of a single form typed at the repl, is set to nil to + prevent the repl from printing the result of the evalation.") + +(defvar *slime-repl-eval-hook-pass* (gensym "PASS") + "Token to indicate that a repl hook declines to evaluate the form") + +(defvar *slime-repl-eval-hooks* nil + "A list of functions. When the repl is about to eval a form, first try running each of + these hooks. The first hook which returns a value which is not *slime-repl-eval-hook-pass* + is considered a replacement for calling eval. If there are no hooks, or all + pass, then eval is used.") + +(export '*slime-repl-eval-hooks*) + +(defslimefun repl-eval-hook-pass () + "call when repl hook declines to evaluate the form" + (throw *slime-repl-eval-hook-pass* *slime-repl-eval-hook-pass*)) + +(defslimefun repl-suppress-output () + "In the dynamic scope of a single form typed at the repl, call to + prevent the repl from printing the result of the evalation." + (setq *slime-repl-suppress-output* t)) + +(defslimefun repl-suppress-advance-history () + "In the dynamic scope of a single form typed at the repl, call to + prevent the repl from advancing the history - * ** *** etc." + (setq *slime-repl-advance-history* nil)) + +(defun %eval-region (string) + (with-input-from-string (stream string) + (let (- values) + (loop + (let ((form (read stream nil stream))) + (when (eq form stream) + (fresh-line) + (finish-output) + (return (values values -))) + (setq - form) + (if *slime-repl-eval-hooks* + (setq values (run-repl-eval-hooks form)) + (setq values (multiple-value-list (eval form)))) + (finish-output)))))) + +(defun run-repl-eval-hooks (form) + (loop for hook in *slime-repl-eval-hooks* + for res = (catch *slime-repl-eval-hook-pass* + (multiple-value-list (funcall hook form))) + until (not (eq res *slime-repl-eval-hook-pass*)) + finally (return + (if (eq res *slime-repl-eval-hook-pass*) + (multiple-value-list (eval form)) + res)))) + +(defun %listener-eval (string) + (clear-user-input) + (with-buffer-syntax () + (swank-repl::track-package + (lambda () + (let ((*slime-repl-suppress-output* :unset) + (*slime-repl-advance-history* :unset)) + (multiple-value-bind (values last-form) (%eval-region string) + (unless (or (and (eq values nil) (eq last-form nil)) + (eq *slime-repl-advance-history* nil)) + (setq *** ** ** * * (car values) + /// // // / / values)) + (setq +++ ++ ++ + + last-form) + (unless (eq *slime-repl-suppress-output* t) + (funcall swank-repl::*send-repl-results-function* values))))))) + nil) + +(setq swank-repl::*listener-eval-function* '%listener-eval) + +(provide :swank-listener-hooks) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-macrostep.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-macrostep.lisp new file mode 100644 index 0000000..7595e36 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-macrostep.lisp @@ -0,0 +1,227 @@ +;;; swank-macrostep.lisp -- fancy macro-expansion via macrostep.el +;; +;; Authors: Luis Oliveira +;; Jon Oddie +;; +;; License: Public Domain + +(defpackage swank-macrostep + (:use cl swank) + (:import-from swank + #:*macroexpand-printer-bindings* + #:with-buffer-syntax + #:with-bindings + #:to-string + #:macroexpand-all + #:compiler-macroexpand-1 + #:defslimefun + #:collect-macro-forms) + (:export #:macrostep-expand-1 + #:macro-form-p)) + +(in-package #:swank-macrostep) + +(defslimefun macrostep-expand-1 (string compiler-macros? context) + (with-buffer-syntax () + (let ((form (read-from-string string))) + (multiple-value-bind (expansion error-message) + (expand-form-once form compiler-macros? context) + (if error-message + `(:error ,error-message) + (multiple-value-bind (macros compiler-macros) + (collect-macro-forms-in-context expansion context) + (let* ((all-macros (append macros compiler-macros)) + (pretty-expansion (pprint-to-string expansion)) + (positions (collect-form-positions expansion + pretty-expansion + all-macros)) + (subform-info + (loop + for form in all-macros + for (start end) in positions + when (and start end) + collect (let ((op-name (to-string (first form))) + (op-type + (if (member form macros) + :macro + :compiler-macro))) + (list op-name + op-type + start))))) + `(:ok ,pretty-expansion ,subform-info)))))))) + +(defun expand-form-once (form compiler-macros? context) + (multiple-value-bind (expansion expanded?) + (macroexpand-1-in-context form context) + (if expanded? + (values expansion nil) + (if (not compiler-macros?) + (values nil "Not a macro form") + (multiple-value-bind (expansion expanded?) + (compiler-macroexpand-1 form) + (if expanded? + (values expansion nil) + (values nil "Not a macro or compiler-macro form"))))))) + +(defslimefun macro-form-p (string compiler-macros? context) + (with-buffer-syntax () + (let ((form + (handler-case + (read-from-string string) + (error (condition) + (unless (debug-on-swank-error) + (return-from macro-form-p + `(:error ,(format nil "Read error: ~A" condition)))))))) + `(:ok ,(macro-form-type form compiler-macros? context))))) + +(defun macro-form-type (form compiler-macros? context) + (cond + ((or (not (consp form)) + (not (symbolp (car form)))) + nil) + ((multiple-value-bind (expansion expanded?) + (macroexpand-1-in-context form context) + (declare (ignore expansion)) + expanded?) + :macro) + ((and compiler-macros? + (multiple-value-bind (expansion expanded?) + (compiler-macroexpand-1 form) + (declare (ignore expansion)) + expanded?)) + :compiler-macro) + (t + nil))) + + +;;;; Hacks to support macro-expansion within local context + +(defparameter *macrostep-tag* (gensym)) + +(defparameter *macrostep-placeholder* '*macrostep-placeholder*) + +(define-condition expansion-in-context-failed (simple-error) + ()) + +(defmacro throw-expansion (form &environment env) + (throw *macrostep-tag* (macroexpand-1 form env))) + +(defmacro throw-collected-macro-forms (form &environment env) + (throw *macrostep-tag* (collect-macro-forms form env))) + +(defun macroexpand-1-in-context (form context) + (handler-case + (macroexpand-and-catch + `(throw-expansion ,form) context) + (error () + (macroexpand-1 form)))) + +(defun collect-macro-forms-in-context (form context) + (handler-case + (macroexpand-and-catch + `(throw-collected-macro-forms ,form) context) + (error () + (collect-macro-forms form)))) + +(defun macroexpand-and-catch (form context) + (catch *macrostep-tag* + (macroexpand-all (enclose-form-in-context form context)) + (error 'expansion-in-context-failed))) + +(defun enclose-form-in-context (form context) + (with-buffer-syntax () + (destructuring-bind (prefix suffix) context + (let* ((placeholder-form + (read-from-string + (concatenate + 'string + prefix (prin1-to-string *macrostep-placeholder*) suffix))) + (substituted-form (subst form *macrostep-placeholder* + placeholder-form))) + (if (not (equal placeholder-form substituted-form)) + substituted-form + (error 'expansion-in-context-failed)))))) + + +;;;; Tracking Pretty Printer + +(defun marker-char-p (char) + (<= #xe000 (char-code char) #xe8ff)) + +(defun make-marker-char (id) + ;; using the private-use characters U+E000..U+F8FF as markers, so + ;; that's our upper limit for how many we can use. + (assert (<= 0 id #x8ff)) + (code-char (+ #xe000 id))) + +(defun marker-char-id (char) + (assert (marker-char-p char)) + (- (char-code char) #xe000)) + +(defparameter +whitespace+ (mapcar #'code-char '(9 13 10 32))) + +(defun whitespacep (char) + (member char +whitespace+)) + +(defun pprint-to-string (object &optional pprint-dispatch) + (let ((*print-pprint-dispatch* (or pprint-dispatch *print-pprint-dispatch*))) + (with-bindings *macroexpand-printer-bindings* + (to-string object)))) + +#-clisp +(defun collect-form-positions (expansion printed-expansion forms) + (loop for (start end) + in (collect-marker-positions + (pprint-to-string expansion (make-tracking-pprint-dispatch forms)) + (length forms)) + collect (when (and start end) + (list (find-non-whitespace-position printed-expansion start) + (find-non-whitespace-position printed-expansion end))))) + +;; The pprint-dispatch table constructed by +;; MAKE-TRACKING-PPRINT-DISPATCH causes an infinite loop and stack +;; overflow under CLISP version 2.49. Make the COLLECT-FORM-POSITIONS +;; entry point a no-op in thi case, so that basic macro-expansion will +;; still work (without detection of inner macro forms) +#+clisp +(defun collect-form-positions (expansion printed-expansion forms) + nil) + +(defun make-tracking-pprint-dispatch (forms) + (let ((original-table *print-pprint-dispatch*) + (table (copy-pprint-dispatch))) + (flet ((maybe-write-marker (position stream) + (when position + (write-char (make-marker-char position) stream)))) + (set-pprint-dispatch 'cons + (lambda (stream cons) + (let ((pos (position cons forms))) + (maybe-write-marker pos stream) + ;; delegate printing to the original table. + (funcall (pprint-dispatch cons original-table) + stream + cons) + (maybe-write-marker pos stream))) + most-positive-fixnum + table)) + table)) + +(defun collect-marker-positions (string position-count) + (let ((positions (make-array position-count :initial-element nil))) + (loop with p = 0 + for char across string + unless (whitespacep char) + do (if (marker-char-p char) + (push p (aref positions (marker-char-id char))) + (incf p))) + (map 'list #'reverse positions))) + +(defun find-non-whitespace-position (string position) + (loop with non-whitespace-position = -1 + for i from 0 and char across string + unless (whitespacep char) + do (incf non-whitespace-position) + until (eql non-whitespace-position position) + finally (return i))) + +(provide :swank-macrostep) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-media.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-media.lisp new file mode 100644 index 0000000..3d5ef7c --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-media.lisp @@ -0,0 +1,25 @@ +;;; swank-media.lisp --- insert other media (images) +;; +;; Authors: Christophe Rhodes +;; +;; Licence: GPLv2 or later +;; + +(in-package :swank) + +;; this file is empty of functionality. The slime-media contrib +;; allows swank to return messages other than :write-string as repl +;; results; this is used in the R implementation of swank to display R +;; objects with graphical representations (such as trellis objects) as +;; image presentations in the swank repl. In R, this is done by +;; having a hook function for the preparation of the repl results, in +;; addition to the already-existing hook for sending the repl results +;; (*send-repl-results-function*, used by swank-presentations.lisp). +;; The swank-media.R contrib implementation defines a generic function +;; for use as this hook, along with methods for commonly-encountered +;; graphical R objects. (This strategy is harder in CL, where methods +;; can only be defined if their specializers already exist; in R's S3 +;; object system, methods are ordinary functions with a special naming +;; convention) + +(provide :swank-media) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-mit-scheme.scm b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-mit-scheme.scm new file mode 100644 index 0000000..e7729ff --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-mit-scheme.scm @@ -0,0 +1,870 @@ +;;; swank-mit-scheme.scm --- SLIME server for MIT Scheme +;; +;; Copyright (C) 2008 Helmut Eller +;; +;; This file is licensed under the terms of the GNU General Public +;; License as distributed with Emacs (press C-h C-c for details). + +;;;; Installation: +#| + +1. You need MIT Scheme 9.2 + +2. The Emacs side needs some fiddling. I have the following in + my .emacs: + +(setq slime-lisp-implementations + '((mit-scheme ("mit-scheme") :init mit-scheme-init))) + +(defun mit-scheme-init (file encoding) + (format "%S\n\n" + `(begin + (load-option 'format) + (load-option 'sos) + (eval + '(create-package-from-description + (make-package-description '(swank) (list (list)) + (vector) (vector) (vector) false)) + (->environment '(package))) + (load ,(expand-file-name + ".../contrib/swank-mit-scheme.scm" ; <-- insert your path + slime-path) + (->environment '(swank))) + (eval '(start-swank ,file) (->environment '(swank)))))) + +(defun mit-scheme () + (interactive) + (slime 'mit-scheme)) + +(defun find-mit-scheme-package () + (save-excursion + (let ((case-fold-search t)) + (and (re-search-backward "^[;]+ package: \\((.+)\\).*$" nil t) + (match-string-no-properties 1))))) + +(setq slime-find-buffer-package-function 'find-mit-scheme-package) +(add-hook 'scheme-mode-hook (lambda () (slime-mode 1))) + + The `mit-scheme-init' function first loads the SOS and FORMAT + libraries, then creates a package "(swank)", and loads this file + into that package. Finally it starts the server. + + `find-mit-scheme-package' tries to figure out which package the + buffer belongs to, assuming that ";;; package: (FOO)" appears + somewhere in the file. Luckily, this assumption is true for many of + MIT Scheme's own files. Alternatively, you could add Emacs style + -*- slime-buffer-package: "(FOO)" -*- file variables. + +4. Start everything with `M-x mit-scheme'. + +|# + +;;; package: (swank) + +(if (< (car (get-subsystem-version "Release")) + '9) + (error "This file requires MIT Scheme Release 9")) + +(define (swank port) + (accept-connections (or port 4005) #f)) + +;; ### hardcoded port number for now. netcat-openbsd doesn't print +;; the listener port anymore. +(define (start-swank port-file) + (accept-connections 4055 port-file) + ) + +;;;; Networking + +(define (accept-connections port port-file) + (let ((sock (open-tcp-server-socket port (host-address-loopback)))) + (format #t "Listening on port: ~s~%" port) + (if port-file (write-port-file port port-file)) + (dynamic-wind + (lambda () #f) + (lambda () (serve (tcp-server-connection-accept sock #t #f))) + (lambda () (close-tcp-server-socket sock))))) + +(define (write-port-file portnumber filename) + (call-with-output-file filename (lambda (p) (write portnumber p)))) + +(define *top-level-restart* #f) +(define (serve socket) + (with-simple-restart + 'disconnect "Close connection." + (lambda () + (with-keyboard-interrupt-handler + (lambda () (main-loop socket)))))) + +(define (disconnect) + (format #t "Disconnecting ...~%") + (invoke-restart (find-restart 'disconnect))) + +(define (main-loop socket) + (do () (#f) + (with-simple-restart + 'abort "Return to SLIME top-level." + (lambda () + (fluid-let ((*top-level-restart* (find-restart 'abort))) + (dispatch (read-packet socket) socket 0)))))) + +(define (with-keyboard-interrupt-handler fun) + (define (set-^G-handler exp) + (eval `(vector-set! keyboard-interrupt-vector (char->ascii #\G) ,exp) + (->environment '(runtime interrupt-handler)))) + (dynamic-wind + (lambda () #f) + (lambda () + (set-^G-handler + `(lambda (char) (with-simple-restart + 'continue "Continue from interrupt." + (lambda () (error "Keyboard Interrupt."))))) + (fun)) + (lambda () + (set-^G-handler '^G-interrupt-handler)))) + + +;;;; Reading/Writing of SLIME packets + +(define (read-packet in) + "Read an S-expression from STREAM using the SLIME protocol." + (let* ((len (read-length in)) + (buffer (make-string len))) + (fill-buffer! in buffer) + (read-from-string buffer))) + +(define (write-packet message out) + (let* ((string (write-to-string message))) + (log-event "WRITE: [~a]~s~%" (string-length string) string) + (write-length (string-length string) out) + (write-string string out) + (flush-output out))) + +(define (fill-buffer! in buffer) + (read-string! buffer in)) + +(define (read-length in) + (if (eof-object? (peek-char in)) (disconnect)) + (do ((len 6 (1- len)) + (sum 0 (+ (* sum 16) (char->hex-digit (read-char in))))) + ((zero? len) sum))) + +(define (ldb size position integer) + "LoaD a Byte of SIZE bits at bit position POSITION from INTEGER." + (fix:and (fix:lsh integer (- position)) + (1- (fix:lsh 1 size)))) + +(define (write-length len out) + (do ((pos 20 (- pos 4))) + ((< pos 0)) + (write-hex-digit (ldb 4 pos len) out))) + +(define (write-hex-digit n out) + (write-char (hex-digit->char n) out)) + +(define (hex-digit->char n) + (digit->char n 16)) + +(define (char->hex-digit c) + (char->digit c 16)) + + +;;;; Event dispatching + +(define (dispatch request socket level) + (log-event "READ: ~s~%" request) + (case (car request) + ((:emacs-rex) (apply emacs-rex socket level (cdr request))))) + +(define (swank-package) + (or (name->package '(swank)) + (name->package '(user)))) + +(define *buffer-package* #f) +(define (find-buffer-package name) + (if (elisp-false? name) + #f + (let ((v (ignore-errors + (lambda () (name->package (read-from-string name)))))) + (and (package? v) v)))) + +(define swank-env (->environment (swank-package))) +(define (user-env buffer-package) + (cond ((string? buffer-package) + (let ((p (find-buffer-package buffer-package))) + (if (not p) (error "Invalid package name: " buffer-package)) + (package/environment p))) + (else (nearest-repl/environment)))) + +;; quote keywords +(define (hack-quotes list) + (map (lambda (x) + (cond ((symbol? x) `(quote ,x)) + (#t x))) + list)) + +(define (emacs-rex socket level sexp package thread id) + (let ((ok? #f) (result #f) (condition #f)) + (dynamic-wind + (lambda () #f) + (lambda () + (bind-condition-handler + (list condition-type:serious-condition) + (lambda (c) (set! condition c) (invoke-sldb socket (1+ level) c)) + (lambda () + (fluid-let ((*buffer-package* package)) + (set! result + (eval (cons* (car sexp) socket (hack-quotes (cdr sexp))) + swank-env)) + (set! ok? #t))))) + (lambda () + (write-packet `(:return + ,(if ok? `(:ok ,result) + `(:abort + ,(if condition + (format #f "~a" + (condition/type condition)) + ""))) + ,id) + socket))))) + +(define (swank:connection-info _) + (let ((p (environment->package (user-env #f)))) + `(:pid ,(unix/current-pid) + :package (:name ,(write-to-string (package/name p)) + :prompt ,(write-to-string (package/name p))) + :lisp-implementation + (:type "MIT Scheme" :version ,(get-subsystem-version-string "release")) + :encoding (:coding-systems ("iso-8859-1")) + ))) + +(define (swank:quit-lisp _) + (%exit)) + + +;;;; Evaluation + +(define (swank-repl:listener-eval socket string) + ;;(call-with-values (lambda () (eval-region string socket)) + ;; (lambda values `(:values . ,(map write-to-string values)))) + `(:values ,(write-to-string (eval-region string socket)))) + +(define (eval-region string socket) + (let ((sexp (read-from-string string))) + (if (eof-object? exp) + (values) + (with-output-to-repl socket + (lambda () (eval sexp (user-env *buffer-package*))))))) + +(define (with-output-to-repl socket fun) + (let ((p (make-port repl-port-type socket))) + (dynamic-wind + (lambda () #f) + (lambda () (with-output-to-port p fun)) + (lambda () (flush-output p))))) + +(define (swank:interactive-eval socket string) + ;;(call-with-values (lambda () (eval-region string)) format-for-echo-area) + (format-values (eval-region string socket)) + ) + +(define (format-values . values) + (if (null? values) + "; No value" + (with-string-output-port + (lambda (out) + (write-string "=> " out) + (do ((vs values (cdr vs))) ((null? vs)) + (write (car vs) out) + (if (not (null? (cdr vs))) + (write-string ", " out))))))) + +(define (swank:pprint-eval _ string) + (pprint-to-string (eval (read-from-string string) + (user-env *buffer-package*)))) + +(define (swank:interactive-eval-region socket string) + (format-values (eval-region string socket))) + +(define (swank:set-package _ package) + (set-repl/environment! (nearest-repl) + (->environment (read-from-string package))) + (let* ((p (environment->package (user-env #f))) + (n (write-to-string (package/name p)))) + (list n n))) + + +(define (repl-write-substring port string start end) + (cond ((< start end) + (write-packet `(:write-string ,(substring string start end)) + (port/state port)))) + (- end start)) + +(define (repl-write-char port char) + (write-packet `(:write-string ,(string char)) + (port/state port))) + +(define repl-port-type + (make-port-type `((write-substring ,repl-write-substring) + (write-char ,repl-write-char)) #f)) + +(define (swank-repl:create-repl socket . _) + (let* ((env (user-env #f)) + (name (format #f "~a" (package/name (environment->package env))))) + (list name name))) + + +;;;; Compilation + +(define (swank:compile-string-for-emacs _ string . x) + (apply + (lambda (errors seconds) + `(:compilation-result ,errors t ,seconds nil nil)) + (call-compiler + (lambda () + (let* ((sexps (snarf-string string)) + (env (user-env *buffer-package*)) + (scode (syntax `(begin ,@sexps) env)) + (compiled-expression (compile-scode scode #t))) + (scode-eval compiled-expression env)))))) + +(define (snarf-string string) + (with-input-from-string string + (lambda () + (let loop () + (let ((e (read))) + (if (eof-object? e) '() (cons e (loop)))))))) + +(define (call-compiler fun) + (let ((time #f)) + (with-timings fun + (lambda (run-time gc-time real-time) + (set! time real-time))) + (list 'nil (internal-time/ticks->seconds time)))) + +(define (swank:compiler-notes-for-emacs _) nil) + +(define (swank:compile-file-for-emacs socket file load?) + (apply + (lambda (errors seconds) + (list ':compilation-result errors 't seconds load? + (->namestring (pathname-name file)))) + (call-compiler + (lambda () (with-output-to-repl socket (lambda () (compile-file file))))))) + +(define (swank:load-file socket file) + (with-output-to-repl socket + (lambda () + (pprint-to-string + (load file (user-env *buffer-package*)))))) + +(define (swank:disassemble-form _ string) + (let ((sexp (let ((sexp (read-from-string string))) + (cond ((and (pair? sexp) (eq? (car sexp) 'quote)) + (cadr sexp)) + (#t sexp))))) + (with-output-to-string + (lambda () + (compiler:disassemble + (eval sexp (user-env *buffer-package*))))))) + +(define (swank:disassemble-symbol _ string) + (with-output-to-string + (lambda () + (compiler:disassemble + (eval (read-from-string string) + (user-env *buffer-package*)))))) + + +;;;; Macroexpansion + +(define (swank:swank-macroexpand-all _ string) + (with-output-to-string + (lambda () + (pp (syntax (read-from-string string) + (user-env *buffer-package*)))))) +(define swank:swank-macroexpand-1 swank:swank-macroexpand-all) +(define swank:swank-macroexpand swank:swank-macroexpand-all) + + +;;; Arglist + +(define (swank:operator-arglist socket name pack) + (let ((v (ignore-errors + (lambda () + (string-trim-right + (with-output-to-string + (lambda () + (carefully-pa + (eval (read-from-string name) (user-env pack)))))))))) + (if (condition? v) 'nil v))) + +(define (carefully-pa o) + (cond ((arity-dispatched-procedure? o) + ;; MIT Scheme crashes for (pa /) + (display "arity-dispatched-procedure")) + ((procedure? o) (pa o)) + (else (error "Not a procedure")))) + + +;;; Some unimplemented stuff. +(define (swank:buffer-first-change . _) nil) +(define (swank:filename-to-modulename . _) nil) +(define (swank:swank-require . _) nil) + +;; M-. is beyond my capabilities. +(define (swank:find-definitions-for-emacs . _) nil) + + +;;; Debugger + +(define-structure (sldb-state (conc-name sldb-state.)) condition restarts) + +(define *sldb-state* #f) +(define (invoke-sldb socket level condition) + (fluid-let ((*sldb-state* (make-sldb-state condition (bound-restarts)))) + (dynamic-wind + (lambda () #f) + (lambda () + (write-packet `(:debug 0 ,level ,@(sldb-info *sldb-state* 0 20)) + socket) + (sldb-loop level socket)) + (lambda () + (write-packet `(:debug-return 0 ,level nil) socket))))) + +(define (sldb-loop level socket) + (write-packet `(:debug-activate 0 ,level) socket) + (with-simple-restart + 'abort (format #f "Return to SLDB level ~a." level) + (lambda () (dispatch (read-packet socket) socket level))) + (sldb-loop level socket)) + +(define (sldb-info state start end) + (let ((c (sldb-state.condition state)) + (rs (sldb-state.restarts state))) + (list (list (condition/report-string c) + (format #f " [~a]" (%condition-type/name (condition/type c))) + nil) + (sldb-restarts rs) + (sldb-backtrace c start end) + ;;'((0 "dummy frame")) + '()))) + +(define %condition-type/name + (eval '%condition-type/name (->environment '(runtime error-handler)))) + +(define (sldb-restarts restarts) + (map (lambda (r) + (list (symbol->string (restart/name r)) + (with-string-output-port + (lambda (p) (write-restart-report r p))))) + restarts)) + +(define (swank:throw-to-toplevel . _) + (invoke-restart *top-level-restart*)) + +(define (swank:sldb-abort . _) + (abort (sldb-state.restarts *sldb-state*))) + +(define (swank:sldb-continue . _) + (continue (sldb-state.restarts *sldb-state*))) + +(define (swank:invoke-nth-restart-for-emacs _ _sldb-level n) + (invoke-restart (list-ref (sldb-state.restarts *sldb-state*) n))) + +(define (swank:debugger-info-for-emacs _ from to) + (sldb-info *sldb-state* from to)) + +(define (swank:backtrace _ from to) + (sldb-backtrace (sldb-state.condition *sldb-state*) from to)) + +(define (sldb-backtrace condition from to) + (sldb-backtrace-aux (condition/continuation condition) from to)) + +(define (sldb-backtrace-aux k from to) + (let ((l (map frame>string (substream (continuation>frames k) from to)))) + (let loop ((i from) (l l)) + (if (null? l) + '() + (cons (list i (car l)) (loop (1+ i) (cdr l))))))) + +;; Stack parser fails for this: +;; (map (lambda (x) x) "/tmp/x.x") + +(define (continuation>frames k) + (let loop ((frame (continuation->stack-frame k))) + (cond ((not frame) (stream)) + (else + (let ((next (ignore-errors + (lambda () (stack-frame/next-subproblem frame))))) + (cons-stream frame + (if (condition? next) + (stream next) + (loop next)))))))) + +(define (frame>string frame) + (if (condition? frame) + (format #f "Bogus frame: ~a ~a" frame + (condition/report-string frame)) + (with-string-output-port (lambda (p) (print-frame frame p))))) + +(define (print-frame frame port) + (define (invalid-subexpression? subexpression) + (or (debugging-info/undefined-expression? subexpression) + (debugging-info/unknown-expression? subexpression))) + (define (invalid-expression? expression) + (or (debugging-info/undefined-expression? expression) + (debugging-info/compiled-code? expression))) + (with-values (lambda () (stack-frame/debugging-info frame)) + (lambda (expression environment subexpression) + (cond ((debugging-info/compiled-code? expression) + (write-string ";unknown compiled code" port)) + ((not (debugging-info/undefined-expression? expression)) + (fluid-let ((*unparse-primitives-by-name?* #t)) + (write + (unsyntax (if (invalid-subexpression? subexpression) + expression + subexpression)) + port))) + ((debugging-info/noise? expression) + (write-string ";" port) + (write-string ((debugging-info/noise expression) #f) + port)) + (else + (write-string ";undefined expression" port)))))) + +(define (substream s from to) + (let loop ((i 0) (l '()) (s s)) + (cond ((or (= i to) (stream-null? s)) (reverse l)) + ((< i from) (loop (1+ i) l (stream-cdr s))) + (else (loop (1+ i) (cons (stream-car s) l) (stream-cdr s)))))) + +(define (swank:frame-locals-and-catch-tags _ frame) + (list (map frame-var>elisp (frame-vars (sldb-get-frame frame))) + '())) + +(define (frame-vars frame) + (with-values (lambda () (stack-frame/debugging-info frame)) + (lambda (expression environment subexpression) + (cond ((environment? environment) + (environment>frame-vars environment)) + (else '()))))) + +(define (environment>frame-vars environment) + (let loop ((e environment)) + (cond ((environment->package e) '()) + (else (append (environment-bindings e) + (if (environment-has-parent? e) + (loop (environment-parent e)) + '())))))) + +(define (frame-var>elisp b) + (list ':name (write-to-string (car b)) + ':value (cond ((null? (cdr b)) "{unavailable}") + (else (>line (cadr b)))) + ':id 0)) + +(define (sldb-get-frame index) + (stream-ref (continuation>frames + (condition/continuation + (sldb-state.condition *sldb-state*))) + index)) + +(define (frame-var-value frame var) + (let ((binding (list-ref (frame-vars frame) var))) + (cond ((cdr binding) (cadr binding)) + (else unspecific)))) + +(define (swank:inspect-frame-var _ frame var) + (reset-inspector) + (inspect-object (frame-var-value (sldb-get-frame frame) var))) + + +;;;; Completion + +(define (swank:simple-completions _ string package) + (let ((strings (all-completions string (user-env package) string-prefix?))) + (list (sort strings stringstring (environment-names env)))) + (keep-matching-items ss (lambda (s) (match? pattern s))))) + +;; symbol->string is too slow +(define %symbol->string symbol-name) + +(define (environment-names env) + (append (environment-bound-names env) + (if (environment-has-parent? env) + (environment-names (environment-parent env)) + '()))) + +(define (longest-common-prefix strings) + (define (common-prefix s1 s2) + (substring s1 0 (string-match-forward s1 s2))) + (reduce common-prefix "" strings)) + + +;;;; Apropos + +(define (swank:apropos-list-for-emacs _ name #!optional + external-only case-sensitive package) + (let* ((pkg (and (string? package) + (find-package (read-from-string package)))) + (parent (and (not (default-object? external-only)) + (elisp-false? external-only))) + (ss (append-map (lambda (p) + (map (lambda (s) (cons p s)) + (apropos-list name p (and pkg parent)))) + (if pkg (list pkg) (all-packages)))) + (ss (sublist ss 0 (min (length ss) 200)))) + (map (lambda (e) + (let ((p (car e)) (s (cdr e))) + (list ':designator (format #f "~a ~a" s (package/name p)) + ':variable (>line + (ignore-errors + (lambda () (package-lookup p s))))))) + ss))) + +(define (swank:list-all-package-names . _) + (map (lambda (p) (write-to-string (package/name p))) + (all-packages))) + +(define (all-packages) + (define (package-and-children package) + (append (list package) + (append-map package-and-children (package/children package)))) + (package-and-children system-global-package)) + + +;;;; Inspector + +(define-structure (inspector-state (conc-name istate.)) + object parts next previous content) + +(define istate #f) + +(define (reset-inspector) + (set! istate #f)) + +(define (swank:init-inspector _ string) + (reset-inspector) + (inspect-object (eval (read-from-string string) + (user-env *buffer-package*)))) + +(define (inspect-object o) + (let ((previous istate) + (content (inspect o)) + (parts (make-eqv-hash-table))) + (set! istate (make-inspector-state o parts #f previous content)) + (if previous (set-istate.next! previous istate)) + (istate>elisp istate))) + +(define (istate>elisp istate) + (list ':title (>line (istate.object istate)) + ':id (assign-index (istate.object istate) (istate.parts istate)) + ':content (prepare-range (istate.parts istate) + (istate.content istate) + 0 500))) + +(define (assign-index o parts) + (let ((i (hash-table/count parts))) + (hash-table/put! parts i o) + i)) + +(define (prepare-range parts content from to) + (let* ((cs (substream content from to)) + (ps (prepare-parts cs parts))) + (list ps + (if (< (length cs) (- to from)) + (+ from (length cs)) + (+ to 1000)) + from to))) + +(define (prepare-parts ps parts) + (define (line label value) + `(,(format #f "~a: " label) + (:value ,(>line value) ,(assign-index value parts)) + "\n")) + (append-map (lambda (p) + (cond ((string? p) (list p)) + ((symbol? p) (list (symbol->string p))) + (#t + (case (car p) + ((line) (apply line (cdr p))) + (else (error "Invalid part:" p)))))) + ps)) + +(define (swank:inspect-nth-part _ index) + (inspect-object (hash-table/get (istate.parts istate) index 'no-such-part))) + +(define (swank:quit-inspector _) + (reset-inspector)) + +(define (swank:inspector-pop _) + (cond ((istate.previous istate) + (set! istate (istate.previous istate)) + (istate>elisp istate)) + (else 'nil))) + +(define (swank:inspector-next _) + (cond ((istate.next istate) + (set! istate (istate.next istate)) + (istate>elisp istate)) + (else 'nil))) + +(define (swank:inspector-range _ from to) + (prepare-range (istate.parts istate) + (istate.content istate) + from to)) + +(define-syntax stream* + (syntax-rules () + ((stream* tail) tail) + ((stream* e1 e2 ...) (cons-stream e1 (stream* e2 ...))))) + +(define (iline label value) `(line ,label ,value)) + +(define-generic inspect (o)) + +(define-method inspect ((o )) + (cond ((environment? o) (inspect-environment o)) + ((vector? o) (inspect-vector o)) + ((procedure? o) (inspect-procedure o)) + ((compiled-code-block? o) (inspect-code-block o)) + ;;((system-pair? o) (inspect-system-pair o)) + ((probably-scode? o) (inspect-scode o)) + (else (inspect-fallback o)))) + +(define (inspect-fallback o) + (let* ((class (object-class o)) + (slots (class-slots class))) + (stream* + (iline "Class" class) + (let loop ((slots slots)) + (cond ((null? slots) (stream)) + (else + (let ((n (slot-name (car slots)))) + (stream* (iline n (slot-value o n)) + (loop (cdr slots)))))))))) + +(define-method inspect ((o )) + (if (or (pair? (cdr o)) (null? (cdr o))) + (inspect-list o) + (inspect-cons o))) + +(define (inspect-cons o) + (stream (iline "car" (car o)) + (iline "cdr" (cdr o)))) + +(define (inspect-list o) + (let loop ((i 0) (o o)) + (cond ((null? o) (stream)) + ((or (pair? (cdr o)) (null? (cdr o))) + (stream* (iline i (car o)) + (loop (1+ i) (cdr o)))) + (else + (stream (iline i (car o)) + (iline "tail" (cdr o))))))) + +(define (inspect-environment o) + (stream* + (iline "(package)" (environment->package o)) + (let loop ((bs (environment-bindings o))) + (cond ((null? bs) + (if (environment-has-parent? o) + (stream (iline "()" (environment-parent o))) + (stream))) + (else + (let* ((b (car bs)) (s (car b))) + (cond ((null? (cdr b)) + (stream* s " {" (environment-reference-type o s) "}\n" + (loop (cdr bs)))) + (else + (stream* (iline s (cadr b)) + (loop (cdr bs))))))))))) + +(define (inspect-vector o) + (let ((len (vector-length o))) + (let loop ((i 0)) + (cond ((= i len) (stream)) + (else (stream* (iline i (vector-ref o i)) + (loop (1+ i)))))))) + +(define (inspect-procedure o) + (cond ((primitive-procedure? o) + (stream (iline "name" (primitive-procedure-name o)) + (iline "arity" (primitive-procedure-arity o)) + (iline "doc" (primitive-procedure-documentation o)))) + ((compound-procedure? o) + (stream (iline "arity" (procedure-arity o)) + (iline "lambda" (procedure-lambda o)) + (iline "env" (ignore-errors + (lambda () (procedure-environment o)))))) + (else + (stream + (iline "block" (compiled-entry/block o)) + (with-output-to-string (lambda () (compiler:disassemble o))))))) + +(define (inspect-code-block o) + (stream-append + (let loop ((i (compiled-code-block/constants-start o))) + (cond ((>= i (compiled-code-block/constants-end o)) (stream)) + (else + (stream* + (iline i (system-vector-ref o i)) + (loop (+ i compiled-code-block/bytes-per-object)))))) + (stream (iline "debuginfo" (compiled-code-block/debugging-info o)) + (iline "env" (compiled-code-block/environment o)) + (with-output-to-string (lambda () (compiler:disassemble o)))))) + +(define (inspect-scode o) + (stream (pprint-to-string o))) + +(define (probably-scode? o) + (define tests (list access? assignment? combination? comment? + conditional? definition? delay? disjunction? lambda? + quotation? sequence? the-environment? variable?)) + (let loop ((tests tests)) + (cond ((null? tests) #f) + (((car tests) o)) + (else (loop (cdr tests)))))) + +(define (inspect-system-pair o) + (stream (iline "car" (system-pair-car o)) + (iline "cdr" (system-pair-cdr o)))) + + +;;;; Auxilary functions + +(define nil '()) +(define t 't) +(define (elisp-false? o) (member o '(nil ()))) +(define (elisp-true? o) (not (elisp-false? o))) +(define (>line o) + (let ((r (write-to-string o 100))) + (cond ((not (car r)) (cdr r)) + (else (string-append (cdr r) " .."))))) +;; Must compile >line otherwise we can't write unassigend-reference-traps. +(set! >line (compile-procedure >line)) +(define (read-from-string s) (with-input-from-string s read)) +(define (pprint-to-string o) + (with-string-output-port + (lambda (p) + (fluid-let ((*unparser-list-breadth-limit* 10) + (*unparser-list-depth-limit* 4) + (*unparser-string-length-limit* 100)) + (pp o p))))) +;(define (1+ n) (+ n 1)) +(define (1- n) (- n 1)) +(define (package-lookup package name) + (let ((p (if (package? package) package (find-package package)))) + (environment-lookup (package/environment p) name))) +(define log-port (current-output-port)) +(define (log-event fstring . args) + ;;(apply format log-port fstring args) + #f + ) + +;;; swank-mit-scheme.scm ends here diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-mlworks.sml b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-mlworks.sml new file mode 100644 index 0000000..3efac53 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-mlworks.sml @@ -0,0 +1,348 @@ +(* swank-mlworks.sml -- SWANK server for MLWorks + * + * This code has been placed in the Public Domain. + *) + +(* This is an experiment to see how the interfaces/modules would look + * in a language with a supposedly "good" module system. + * + * MLWorks is probably the only SML implementation that tries to + * support "interactive programming". Since MLWorks wasn't maintained + * the last 15 or so years, big chunks of the SML Basis Library are + * missing or not the way as required by the standard. That makes it + * rather hard to do anything; it also shows that MLWorks hasn't been + * "used in anger" for a long time. + *) + +structure Swank = struct + + structure Util = struct + fun utf8ToString (v:Word8Vector.vector) : string = Byte.bytesToString v + fun stringToUtf8 s = Byte.stringToBytes s + end + + structure Map = struct + datatype ('a, 'b) map = Alist of {list: ('a * 'b) list ref, + eq: ('a * 'a) -> bool} + + fun stringMap () = + Alist {list = ref [], + eq = (fn (x:string,y:string) => x = y)} + + + fun lookup (Alist {list, eq}, key) = + let fun search [] = NONE + | search ((key', value) :: xs) = + if eq (key', key) then SOME value + else search xs + in search (!list) + end + + fun put (Alist {list, eq}, key, value) = + let val l = (key, value) :: (!list) + in list := l + end + + end + + structure CharBuffer = struct + local + structure C = CharArray + datatype buffer = B of {array : C.array ref, + index: int ref} + in + + fun new hint = B {array = ref (C.array (hint, #"\000")), + index = ref 0} + + fun append (buffer as B {array, index}, char) = + let val a = !array + val i = !index + val len = C.length a + in if i < len then + (C.update (a, i, char); + index := i + 1; + ()) + else let val aa = C.array (2 * len, #"\000") + fun copy (src, dst) = + let val len = C.length src + fun loop i = + if i = len then () + else (C.update (dst, i, C.sub (src, i)); + loop (i + 1)) + in loop 0 end + in copy (a, aa); + C.update (aa, i, char); + array := aa; + index := i + 1; + () + end + end + + fun toString (B {array, index}) = + let val a = !array + val i = !index + in CharVector.tabulate (i, fn i => C.sub (a, i)) end + + end + + end + + + structure Sexp = struct + structure Type = struct + datatype sexp = Int of int + | Str of string + | Lst of sexp list + | Sym of string + | QSym of string * string + | T + | Nil + | Quote + end + open Type + + exception ReadError + + fun fromUtf8 v = + let val len = Word8Vector.length v + val index = ref 0 + fun getc () = + case getc' () of + SOME c => c + | NONE => raise ReadError + and getc' () = + let val i = !index + in if i = len then NONE + else (index := i + 1; + SOME (Byte.byteToChar (Word8Vector.sub (v, i)))) + end + and ungetc () = index := !index - 1 + and sexp () : sexp = + case getc () of + #"\"" => string (CharBuffer.new 100) + | #"(" => lst () + | #"'" => Lst [Quote, sexp ()] + | _ => (ungetc(); token ()) + and string buf : sexp = + case getc () of + #"\"" => Str (CharBuffer.toString buf) + | #"\\" => (CharBuffer.append (buf, getc ()); string buf) + | c => (CharBuffer.append (buf, c); string buf) + and lst () = + let val x = sexp () + in case getc () of + #")" => Lst [x] + | #" " => let val Lst y = lst () in Lst (x :: y) end + | _ => raise ReadError + end + and token () = + let val tok = token' (CharBuffer.new 50) + val c0 = String.sub (tok, 0) + in if Char.isDigit c0 then (case Int.fromString tok of + SOME i => Int i + | NONE => raise ReadError) + else + Sym (tok) + end + and token' buf : string = + case getc' () of + NONE => CharBuffer.toString buf + | SOME #"\\" => (CharBuffer.append (buf, getc ()); + token' buf) + | SOME #" " => (ungetc (); CharBuffer.toString buf) + | SOME #")" => (ungetc (); CharBuffer.toString buf) + | SOME c => (CharBuffer.append (buf, c); token' buf) + in + sexp () + end + + fun toString sexp = + case sexp of + (Str s) => "\"" ^ String.toCString s ^ "\"" + | (Lst []) => "nil" + | (Lst xs) => "(" ^ String.concatWith " " (map toString xs) ^ ")" + | Sym (name) => name + | QSym (pkg, name) => pkg ^ ":" ^ name + | Quote => "quote" + | T => "t" + | Nil => "nil" + | Int i => Int.toString i + + fun toUtf8 sexp = Util.stringToUtf8 (toString sexp) + end + + structure Net = struct + local + structure S = Socket + structure I = INetSock + structure W = Word8Vector + + fun createSocket (port) = + let val sock : S.passive I.stream_sock = I.TCP.socket () + val SOME localhost = NetHostDB.fromString "127.0.0.1" + in + S.Ctl.setREUSEADDR (sock, true); + S.bind (sock, I.toAddr (localhost, port)); + S.listen (sock, 2); + sock + end + + fun addrToString sockAddr = + let val (ip, port) = I.fromAddr sockAddr + in NetHostDB.toString ip ^ ":" ^ Int.toString port + end + + exception ShortRead of W.vector + exception InvalidHexString of string + in + + fun acceptConnection port = + let val sock = createSocket port + val addr = S.Ctl.getSockName sock + val _ = print ("Listening on: " ^ addrToString addr ^ "\n") + val (peer, addr) = S.accept sock + in + S.close sock; + print ("Connection from: " ^ addrToString addr ^ "\n"); + peer + end + + fun receivePacket socket = + let val v = S.recvVec (socket, 6) + val _ = if W.length v = 6 then () + else raise ShortRead v + val s = Util.utf8ToString v + val _ = print ("s = " ^ s ^ "\n") + val len = + case StringCvt.scanString (Int.scan StringCvt.HEX) s of + SOME len => len + | NONE => raise InvalidHexString s + val _ = print ("len = " ^ Int.toString len ^ "\n") + val payload = S.recvVec (socket, len) + val plen = W.length payload + val _ = print ("plen = " ^ Int.toString plen ^ "\n") + val _ = if plen = len then () + else raise ShortRead payload + in + payload + end + + fun nibbleToHex i:string = Int.fmt StringCvt.HEX i + + fun loadNibble i pos = + Word32.toInt (Word32.andb (Word32.>> (Word32.fromInt i, + Word.fromInt (pos * 4)), + 0wxf)) + + fun hexDigit i pos = nibbleToHex (loadNibble i pos) + + fun lenToHex i = + concat [hexDigit i 5, + hexDigit i 4, + hexDigit i 3, + hexDigit i 2, + hexDigit i 1, + hexDigit i 0] + + fun sendPacket (payload:W.vector, socket) = + let val len = W.length payload + val header = Util.stringToUtf8 (lenToHex len) + val packet = W.concat [header, payload] + in print ("len = " ^ Int.toString len ^ "\n" + ^ "header = " ^ lenToHex len ^ "\n" + ^ "paylad = " ^ Util.utf8ToString payload ^ "\n"); + S.sendVec (socket, {buf = packet, i = 0, sz = NONE}) + end + + end + end + + structure Rpc = struct + open Sexp.Type + + val funTable : (string, sexp list -> sexp) Map.map + = Map.stringMap () + + fun define name f = Map.put (funTable, name, f) + + exception UnknownFunction of string + fun call (name, args) = + (print ("call: " ^ name ^ "\n"); + case Map.lookup (funTable, name) of + SOME f => f args + | NONE => raise UnknownFunction name) + + + local fun getpid () = + Word32.toInt (Posix.Process.pidToWord (Posix.ProcEnv.getpid ())) + in + fun connectionInfo [] = + Lst [Sym ":pid", Int (getpid ()), + Sym ":lisp-implementation", Lst [Sym ":type", Str "MLWorks", + Sym ":name", Str "mlworks", + Sym ":version", Str "2.x"], + Sym ":machine", Lst [Sym ":instance", Str "", + Sym ":type", Str "", + Sym ":version", Str ""], + Sym ":features", Nil, + Sym ":package", Lst [Sym ":name", Str "root", + Sym ":prompt", Str "-"]] + end + + fun nyi _ = Nil + + local structure D = Shell.Dynamic + in + fun interactiveEval [Str string] = + let val x = D.eval string + in Str (concat [D.printValue x, " : ", D.printType (D.getType x)]) + end + end + + val _ = + (define "swank:connection-info" connectionInfo; + define "swank:swank-require" nyi; + define "swank:interactive-eval" interactiveEval; + ()) + end + + structure EventLoop = struct + open Sexp.Type + + fun execute (sexp, pkg) = + (print ("sexp = " ^ (Sexp.toString sexp) ^ "\n"); + case sexp of + Lst (Sym name :: args) => Rpc.call (name, args)) + + fun emacsRex (sexp, pkg, id as Int _, sock) = + let val result = (Lst [Sym (":ok"), execute (sexp, pkg)] + handle exn => (Lst [Sym ":abort", + Str (exnName exn ^ ": " + ^ exnMessage exn)])) + val reply = Lst [Sym ":return", result, id] + in Net.sendPacket (Sexp.toUtf8 reply, sock) + end + + fun dispatch (Lst ((Sym key) :: args), sock) = + case key of + ":emacs-rex" => let val [sexp, pkg, _, id] = args + in emacsRex (sexp, pkg, id, sock) + end + + fun processRequests socket:unit = + let val sexp = Sexp.fromUtf8 (Net.receivePacket socket) + in print ("request: " + ^ Util.utf8ToString (Sexp.toUtf8 sexp) + ^ "\n"); + dispatch (sexp, socket); + processRequests socket + end + + end + + (* val _ = EventLoop.processRequests (Net.acceptConnection 4005) *) + val _ = () + end + +(* (Swank.EventLoop.processRequests (Swank.Net.acceptConnection 4005)) *) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-mrepl.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-mrepl.lisp new file mode 100644 index 0000000..cc8ce81 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-mrepl.lisp @@ -0,0 +1,162 @@ +;;; swank-mrepl.lisp +;; +;; Licence: public domain + +(in-package :swank) +(eval-when (:compile-toplevel :load-toplevel :execute) + (let ((api '( + *emacs-connection* + channel + channel-id + define-channel-method + defslimefun + dcase + log-event + process-requests + send-to-remote-channel + use-threads-p + wait-for-event + with-bindings + with-connection + with-top-level-restart + with-slime-interrupts + ))) + (eval `(defpackage #:swank-api + (:use) + (:import-from #:swank . ,api) + (:export . ,api))))) + +(defpackage :swank-mrepl + (:use :cl :swank-api) + (:export #:create-mrepl)) + +(in-package :swank-mrepl) + +(defclass listener-channel (channel) + ((remote :initarg :remote) + (env :initarg :env) + (mode :initform :eval) + (tag :initform nil))) + +(defun package-prompt (package) + (reduce (lambda (x y) (if (<= (length x) (length y)) x y)) + (cons (package-name package) (package-nicknames package)))) + +(defslimefun create-mrepl (remote) + (let* ((pkg *package*) + (conn *emacs-connection*) + (thread (if (use-threads-p) + (spawn-listener-thread conn) + nil)) + (ch (make-instance 'listener-channel :remote remote :thread thread))) + (setf (slot-value ch 'env) (initial-listener-env ch)) + (when thread + (swank/backend:send thread `(:serve-channel ,ch))) + (list (channel-id ch) + (swank/backend:thread-id (or thread (swank/backend:current-thread))) + (package-name pkg) + (package-prompt pkg)))) + +(defun initial-listener-env (listener) + `((*package* . ,*package*) + (*standard-output* . ,(make-listener-output-stream listener)) + (*standard-input* . ,(make-listener-input-stream listener)))) + +(defun spawn-listener-thread (connection) + (swank/backend:spawn + (lambda () + (with-connection (connection) + (dcase (swank/backend:receive) + ((:serve-channel c) + (loop + (with-top-level-restart (connection (drop-unprocessed-events c)) + (process-requests nil))))))) + :name "mrepl thread")) + +(defun drop-unprocessed-events (channel) + (with-slots (mode) channel + (let ((old-mode mode)) + (setf mode :drop) + (unwind-protect + (process-requests t) + (setf mode old-mode))) + (send-prompt channel))) + +(define-channel-method :process ((c listener-channel) string) + (log-event ":process ~s~%" string) + (with-slots (mode remote) c + (ecase mode + (:eval (mrepl-eval c string)) + (:read (mrepl-read c string)) + (:drop)))) + +(defun mrepl-eval (channel string) + (with-slots (remote env) channel + (let ((aborted t)) + (with-bindings env + (unwind-protect + (let ((result (with-slime-interrupts (read-eval-print string)))) + (send-to-remote-channel remote `(:write-result ,result)) + (setq aborted nil)) + (setf env (loop for (sym) in env + collect (cons sym (symbol-value sym)))) + (cond (aborted + (send-to-remote-channel remote `(:evaluation-aborted))) + (t + (send-prompt channel)))))))) + +(defun send-prompt (channel) + (with-slots (env remote) channel + (let ((pkg (or (cdr (assoc '*package* env)) *package*)) + (out (cdr (assoc '*standard-output* env))) + (in (cdr (assoc '*standard-input* env)))) + (when out (force-output out)) + (when in (clear-input in)) + (send-to-remote-channel remote `(:prompt ,(package-name pkg) + ,(package-prompt pkg)))))) + +(defun mrepl-read (channel string) + (with-slots (tag) channel + (assert tag) + (throw tag string))) + +(defun read-eval-print (string) + (with-input-from-string (in string) + (setq / ()) + (loop + (let* ((form (read in nil in))) + (cond ((eq form in) (return)) + (t (setq / (multiple-value-list (eval (setq + form)))))))) + (force-output) + (if / + (format nil "~{~s~%~}" /) + "; No values"))) + +(defun make-listener-output-stream (channel) + (let ((remote (slot-value channel 'remote))) + (swank/backend:make-output-stream + (lambda (string) + (send-to-remote-channel remote `(:write-string ,string)))))) + +(defun make-listener-input-stream (channel) + (swank/backend:make-input-stream (lambda () (read-input channel)))) + +(defun set-mode (channel new-mode) + (with-slots (mode remote) channel + (unless (eq mode new-mode) + (send-to-remote-channel remote `(:set-read-mode ,new-mode))) + (setf mode new-mode))) + +(defun read-input (channel) + (with-slots (mode tag remote) channel + (force-output) + (let ((old-mode mode) + (old-tag tag)) + (setf tag (cons nil nil)) + (set-mode channel :read) + (unwind-protect + (catch tag (process-requests nil)) + (setf tag old-tag) + (set-mode channel old-mode))))) + +(provide :swank-mrepl) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-package-fu.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-package-fu.lisp new file mode 100644 index 0000000..a22807a --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-package-fu.lisp @@ -0,0 +1,65 @@ + +(in-package :swank) + +(defslimefun package= (string1 string2) + (let* ((pkg1 (guess-package string1)) + (pkg2 (guess-package string2))) + (and pkg1 pkg2 (eq pkg1 pkg2)))) + +(defslimefun export-symbol-for-emacs (symbol-str package-str) + (let ((package (guess-package package-str))) + (when package + (let ((*buffer-package* package)) + (export `(,(from-string symbol-str)) package))))) + +(defslimefun unexport-symbol-for-emacs (symbol-str package-str) + (let ((package (guess-package package-str))) + (when package + (let ((*buffer-package* package)) + (unexport `(,(from-string symbol-str)) package))))) + +#+sbcl +(defun list-structure-symbols (name) + (let ((dd (sb-kernel:find-defstruct-description name ))) + (list* name + (sb-kernel:dd-default-constructor dd) + (sb-kernel:dd-predicate-name dd) + (sb-kernel::dd-copier-name dd) + (mapcar #'sb-kernel:dsd-accessor-name + (sb-kernel:dd-slots dd))))) + +#+ccl +(defun list-structure-symbols (name) + (let ((definition (gethash name ccl::%defstructs%))) + (list* name + (ccl::sd-constructor definition) + (ccl::sd-refnames definition)))) + +(defun list-class-symbols (name) + (let* ((class (find-class name)) + (slots (swank-mop:class-direct-slots class))) + (labels ((extract-symbol (name) + (if (and (consp name) (eql (car name) 'setf)) + (cadr name) + name)) + (slot-accessors (slot) + (nintersection (copy-list (swank-mop:slot-definition-readers slot)) + (copy-list (swank-mop:slot-definition-readers slot)) + :key #'extract-symbol))) + (list* (class-name class) + (mapcan #'slot-accessors slots))))) + +(defslimefun export-structure (name package) + (let ((*package* (guess-package package))) + (when *package* + (let* ((name (from-string name)) + (symbols (cond #+(or sbcl ccl) + ((or (not (find-class name nil)) + (subtypep name 'structure-object)) + (list-structure-symbols name)) + (t + (list-class-symbols name))))) + (export symbols) + symbols)))) + +(provide :swank-package-fu) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-presentation-streams.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-presentation-streams.lisp new file mode 100644 index 0000000..93a6d1d --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-presentation-streams.lisp @@ -0,0 +1,334 @@ +;;; swank-presentation-streams.lisp --- Streams that allow attaching object identities +;;; to portions of output +;;; +;;; Authors: Alan Ruttenberg +;;; Matthias Koeppe +;;; Helmut Eller +;;; +;;; License: This code has been placed in the Public Domain. All warranties +;;; are disclaimed. + +(in-package :swank) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (swank-require :swank-presentations)) + +;; This file contains a mechanism for printing to the slime repl so +;; that the printed result remembers what object it is associated +;; with. This extends the recording of REPL results. +;; +;; There are two methods: +;; +;; 1. Depends on the ilisp bridge code being installed and ready to +;; intercept messages in the printed stream. We encode the +;; information with a message saying that we are starting to print +;; an object corresponding to a given id and another when we are +;; done. The process filter notices these and adds the necessary +;; text properties to the output. +;; +;; 2. Use separate protocol messages :presentation-start and +;; :presentation-end for sending presentations. +;; +;; We only do this if we know we are printing to a slime stream, +;; checked with the method slime-stream-p. Initially this checks for +;; the knows slime streams looking at *connections*. In cmucl, sbcl, and +;; openmcl it also checks if it is a pretty-printing stream which +;; ultimately prints to a slime stream. +;; +;; Method 1 seems to be faster, but the printed escape sequences can +;; disturb the column counting, and thus the layout in pretty-printing. +;; We use method 1 when a dedicated output stream is used. +;; +;; Method 2 is cleaner and works with pretty printing if the pretty +;; printers support "annotations". We use method 2 when no dedicated +;; output stream is used. + +;; Control +(defvar *enable-presenting-readable-objects* t + "set this to enable automatically printing presentations for some +subset of readable objects, such as pathnames." ) + +;; doing it + +(defmacro presenting-object (object stream &body body) + "What you use in your code. Wrap this around some printing and that text will +be sensitive and remember what object it is in the repl" + `(presenting-object-1 ,object ,stream #'(lambda () ,@body))) + +(defmacro presenting-object-if (predicate object stream &body body) + "What you use in your code. Wrap this around some printing and that text will +be sensitive and remember what object it is in the repl if predicate is true" + (let ((continue (gensym))) + `(let ((,continue #'(lambda () ,@body))) + (if ,predicate + (presenting-object-1 ,object ,stream ,continue) + (funcall ,continue))))) + +;;; Get pretty printer patches for SBCL at load (not compile) time. +#+#:disable-dangerous-patching ; #+sbcl +(eval-when (:load-toplevel) + (handler-bind ((simple-error + (lambda (c) + (declare (ignore c)) + (let ((clobber-it (find-restart 'sb-kernel::clobber-it))) + (when clobber-it (invoke-restart clobber-it)))))) + (sb-ext:without-package-locks + (swank/sbcl::with-debootstrapping + (load (make-pathname + :name "sbcl-pprint-patch" + :type "lisp" + :directory (pathname-directory + swank-loader:*source-directory*))))))) + +(let ((last-stream nil) + (last-answer nil)) + (defun slime-stream-p (stream) + "Check if stream is one of the slime streams, since if it isn't we +don't want to present anything. +Two special return values: +:DEDICATED -- Output ends up on a dedicated output stream +:REPL-RESULT -- Output ends up on the :repl-results target. +" + (if (eq last-stream stream) + last-answer + (progn + (setq last-stream stream) + (if (eq stream t) + (setq stream *standard-output*)) + (setq last-answer + (or #+openmcl + (and (typep stream 'ccl::xp-stream) + ;(slime-stream-p (ccl::xp-base-stream (slot-value stream 'ccl::xp-structure))) + (slime-stream-p (ccl::%svref (slot-value stream 'ccl::xp-structure) 1))) + #+cmu + (or (and (typep stream 'lisp::indenting-stream) + (slime-stream-p (lisp::indenting-stream-stream stream))) + (and (typep stream 'pretty-print::pretty-stream) + (fboundp 'pretty-print::enqueue-annotation) + (let ((slime-stream-p + (slime-stream-p (pretty-print::pretty-stream-target stream)))) + (and ;; Printing through CMUCL pretty + ;; streams is only cleanly + ;; possible if we are using the + ;; bridge-less protocol with + ;; annotations, because the bridge + ;; escape sequences disturb the + ;; pretty printer layout. + (not (eql slime-stream-p :dedicated-output)) + ;; If OK, return the return value + ;; we got from slime-stream-p on + ;; the target stream (could be + ;; :repl-result): + slime-stream-p)))) + #+sbcl + (let () + (declare (notinline sb-pretty::pretty-stream-target)) + (and (typep stream (find-symbol "PRETTY-STREAM" 'sb-pretty)) + (find-symbol "ENQUEUE-ANNOTATION" 'sb-pretty) + (not *use-dedicated-output-stream*) + (slime-stream-p (sb-pretty::pretty-stream-target stream)))) + #+allegro + (and (typep stream 'excl:xp-simple-stream) + (slime-stream-p (excl::stream-output-handle stream))) + (loop for connection in *connections* + thereis (or (and (eq stream (connection.dedicated-output connection)) + :dedicated) + (eq stream (connection.socket-io connection)) + (eq stream (connection.user-output connection)) + (eq stream (connection.user-io connection)) + (and (eq stream (connection.repl-results connection)) + :repl-result))))))))) + +(defun can-present-readable-objects (&optional stream) + (declare (ignore stream)) + *enable-presenting-readable-objects*) + +;; If we are printing to an XP (pretty printing) stream, printing the +;; escape sequences directly would mess up the layout because column +;; counting is disturbed. Use "annotations" instead. +#+allegro +(defun write-annotation (stream function arg) + (if (typep stream 'excl:xp-simple-stream) + (excl::schedule-annotation stream function arg) + (funcall function arg stream nil))) +#+cmu +(defun write-annotation (stream function arg) + (if (and (typep stream 'pp:pretty-stream) + (fboundp 'pp::enqueue-annotation)) + (pp::enqueue-annotation stream function arg) + (funcall function arg stream nil))) +#+sbcl +(defun write-annotation (stream function arg) + (let ((enqueue-annotation + (find-symbol "ENQUEUE-ANNOTATION" 'sb-pretty))) + (if (and enqueue-annotation + (typep stream (find-symbol "PRETTY-STREAM" 'sb-pretty))) + (funcall enqueue-annotation stream function arg) + (funcall function arg stream nil)))) +#-(or allegro cmu sbcl) +(defun write-annotation (stream function arg) + (funcall function arg stream nil)) + +(defstruct presentation-record + (id) + (printed-p) + (target)) + +(defun presentation-start (record stream truncatep) + (unless truncatep + ;; Don't start new presentations when nothing is going to be + ;; printed due to *print-lines*. + (let ((pid (presentation-record-id record)) + (target (presentation-record-target record))) + (case target + (:dedicated + ;; Use bridge protocol + (write-string "<" stream) + (prin1 pid stream) + (write-string "" stream)) + (t + (finish-output stream) + (send-to-emacs `(:presentation-start ,pid ,target))))) + (setf (presentation-record-printed-p record) t))) + +(defun presentation-end (record stream truncatep) + (declare (ignore truncatep)) + ;; Always end old presentations that were started. + (when (presentation-record-printed-p record) + (let ((pid (presentation-record-id record)) + (target (presentation-record-target record))) + (case target + (:dedicated + ;; Use bridge protocol + (write-string ">" stream) + (prin1 pid stream) + (write-string "" stream)) + (t + (finish-output stream) + (send-to-emacs `(:presentation-end ,pid ,target))))))) + +(defun presenting-object-1 (object stream continue) + "Uses the bridge mechanism with two messages >id and ) + (pp-end-block stream ">")) + nil)) + (defmethod print-object :around ((pathname pathname) stream) + (swank::presenting-object-if + (swank::can-present-readable-objects stream) + pathname stream (call-next-method)))) + (ccl::def-load-pointers clear-presentations () + (swank::clear-presentation-tables))) + +(in-package :swank) + +#+cmu +(progn + (fwrappers:define-fwrapper presenting-unreadable-wrapper (object stream type identity body) + (presenting-object object stream + (fwrappers:call-next-function))) + + (fwrappers:define-fwrapper presenting-pathname-wrapper (pathname stream depth) + (presenting-object-if (can-present-readable-objects stream) pathname stream + (fwrappers:call-next-function))) + + (defun monkey-patch-stream-printing () + (fwrappers::fwrap 'lisp::%print-pathname #'presenting-pathname-wrapper) + (fwrappers::fwrap 'lisp::%print-unreadable-object #'presenting-unreadable-wrapper))) + +#+sbcl +(progn + (defvar *saved-%print-unreadable-object* + (fdefinition 'sb-impl::%print-unreadable-object)) + + (defun monkey-patch-stream-printing () + (sb-ext:without-package-locks + (when (eq (fdefinition 'sb-impl::%print-unreadable-object) + *saved-%print-unreadable-object*) + (setf (fdefinition 'sb-impl::%print-unreadable-object) + (lambda (object stream &rest args) + (presenting-object object stream + (apply *saved-%print-unreadable-object* + object stream args))))) + (defmethod print-object :around ((object pathname) stream) + (presenting-object object stream + (call-next-method)))))) + +#+allegro +(progn + (excl:def-fwrapper presenting-unreadable-wrapper (object stream type identity continuation) + (swank::presenting-object object stream (excl:call-next-fwrapper))) + (excl:def-fwrapper presenting-pathname-wrapper (pathname stream depth) + (presenting-object-if (can-present-readable-objects stream) pathname stream + (excl:call-next-fwrapper))) + (defun monkey-patch-stream-printing () + (excl:fwrap 'excl::print-unreadable-object-1 + 'print-unreadable-present 'presenting-unreadable-wrapper) + (excl:fwrap 'excl::pathname-printer + 'print-pathname-present 'presenting-pathname-wrapper))) + +#-(or allegro sbcl cmu openmcl) +(defun monkey-patch-stream-printing () + (values)) + +;; Hook into SWANK. + +(defslimefun init-presentation-streams () + (monkey-patch-stream-printing) + ;; FIXME: import/use swank-repl to avoid package qualifier. + (setq swank-repl:*send-repl-results-function* + 'present-repl-results-via-presentation-streams)) + +(provide :swank-presentation-streams) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-presentations.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-presentations.lisp new file mode 100644 index 0000000..11326af --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-presentations.lisp @@ -0,0 +1,246 @@ +;;; swank-presentations.lisp --- imitate LispM's presentations +;; +;; Authors: Alan Ruttenberg +;; Luke Gorrie +;; Helmut Eller +;; Matthias Koeppe +;; +;; License: This code has been placed in the Public Domain. All warranties +;; are disclaimed. +;; + +(in-package :swank) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (swank-require :swank-repl)) + +;;;; Recording and accessing results of computations + +(defvar *record-repl-results* t + "Non-nil means that REPL results are saved for later lookup.") + +(defvar *object-to-presentation-id* + (make-weak-key-hash-table :test 'eq) + "Store the mapping of objects to numeric identifiers") + +(defvar *presentation-id-to-object* + (make-weak-value-hash-table :test 'eql) + "Store the mapping of numeric identifiers to objects") + +(defun clear-presentation-tables () + (clrhash *object-to-presentation-id*) + (clrhash *presentation-id-to-object*)) + +(defvar *presentation-counter* 0 "identifier counter") + +(defvar *nil-surrogate* (make-symbol "nil-surrogate")) + +;; XXX thread safety? [2006-09-13] mb: not in the slightest (fwiw the +;; rest of slime isn't thread safe either), do we really care? +(defun save-presented-object (object) + "Save OBJECT and return the assigned id. +If OBJECT was saved previously return the old id." + (let ((object (if (null object) *nil-surrogate* object))) + ;; We store *nil-surrogate* instead of nil, to distinguish it from + ;; an object that was garbage collected. + (or (gethash object *object-to-presentation-id*) + (let ((id (incf *presentation-counter*))) + (setf (gethash id *presentation-id-to-object*) object) + (setf (gethash object *object-to-presentation-id*) id) + id)))) + +(defslimefun lookup-presented-object (id) + "Retrieve the object corresponding to ID. +The secondary value indicates the absence of an entry." + (etypecase id + (integer + ;; + (multiple-value-bind (object foundp) + (gethash id *presentation-id-to-object*) + (cond + ((eql object *nil-surrogate*) + ;; A stored nil object + (values nil t)) + ((null object) + ;; Object that was replaced by nil in the weak hash table + ;; when the object was garbage collected. + (values nil nil)) + (t + (values object foundp))))) + (cons + (dcase id + ((:frame-var thread-id frame index) + (declare (ignore thread-id)) ; later + (handler-case + (frame-var-value frame index) + (t (condition) + (declare (ignore condition)) + (values nil nil)) + (:no-error (value) + (values value t)))) + ((:inspected-part part-index) + (inspector-nth-part part-index)))))) + +(defslimefun lookup-presented-object-or-lose (id) + "Get the result of the previous REPL evaluation with ID." + (multiple-value-bind (object foundp) (lookup-presented-object id) + (cond (foundp object) + (t (error "Attempt to access unrecorded object (id ~D)." id))))) + +(defslimefun lookup-and-save-presented-object-or-lose (id) + "Get the object associated with ID and save it in the presentation tables." + (let ((obj (lookup-presented-object-or-lose id))) + (save-presented-object obj))) + +(defslimefun clear-repl-results () + "Forget the results of all previous REPL evaluations." + (clear-presentation-tables) + t) + +(defun present-repl-results (values) + ;; Override a function in swank.lisp, so that + ;; presentations are associated with every REPL result. + (flet ((send (value) + (let ((id (and *record-repl-results* + (save-presented-object value)))) + (send-to-emacs `(:presentation-start ,id :repl-result)) + (send-to-emacs `(:write-string ,(prin1-to-string value) + :repl-result)) + (send-to-emacs `(:presentation-end ,id :repl-result)) + (send-to-emacs `(:write-string ,(string #\Newline) + :repl-result))))) + (fresh-line) + (finish-output) + (if (null values) + (send-to-emacs `(:write-string "; No value" :repl-result)) + (mapc #'send values)))) + + +;;;; Presentation menu protocol +;; +;; To define a menu for a type of object, define a method +;; menu-choices-for-presentation on that object type. This function +;; should return a list of two element lists where the first element is +;; the name of the menu action and the second is a function that will be +;; called if the menu is chosen. The function will be called with 3 +;; arguments: +;; +;; choice: The string naming the action from above +;; +;; object: The object +;; +;; id: The presentation id of the object +;; +;; You might want append (when (next-method-p) (call-next-method)) to +;; pick up the Menu actions of superclasses. +;; + +(defvar *presentation-active-menu* nil) + +(defun menu-choices-for-presentation-id (id) + (multiple-value-bind (ob presentp) (lookup-presented-object id) + (cond ((not presentp) 'not-present) + (t + (let ((menu-and-actions (menu-choices-for-presentation ob))) + (setq *presentation-active-menu* (cons id menu-and-actions)) + (mapcar 'car menu-and-actions)))))) + +(defun swank-ioify (thing) + (cond ((keywordp thing) thing) + ((and (symbolp thing)(not (find #\: (symbol-name thing)))) + (intern (symbol-name thing) 'swank-io-package)) + ((consp thing) (cons (swank-ioify (car thing)) + (swank-ioify (cdr thing)))) + (t thing))) + +(defun execute-menu-choice-for-presentation-id (id count item) + (let ((ob (lookup-presented-object id))) + (assert (equal id (car *presentation-active-menu*)) () + "Bug: Execute menu call for id ~a but menu has id ~a" + id (car *presentation-active-menu*)) + (let ((action (second (nth (1- count) (cdr *presentation-active-menu*))))) + (swank-ioify (funcall action item ob id))))) + + +(defgeneric menu-choices-for-presentation (object) + (:method (ob) (declare (ignore ob)) nil)) ; default method + +;; Pathname +(defmethod menu-choices-for-presentation ((ob pathname)) + (let* ((file-exists (ignore-errors (probe-file ob))) + (lisp-type (make-pathname :type "lisp")) + (source-file (and (not (member (pathname-type ob) '("lisp" "cl") + :test 'equal)) + (let ((source (merge-pathnames lisp-type ob))) + (and (ignore-errors (probe-file source)) + source)))) + (fasl-file (and file-exists + (equal (ignore-errors + (namestring + (truename + (compile-file-pathname + (merge-pathnames lisp-type ob))))) + (namestring (truename ob)))))) + (remove nil + (list* + (and (and file-exists (not fasl-file)) + (list "Edit this file" + (lambda(choice object id) + (declare (ignore choice id)) + (ed-in-emacs (namestring (truename object))) + nil))) + (and file-exists + (list "Dired containing directory" + (lambda (choice object id) + (declare (ignore choice id)) + (ed-in-emacs (namestring + (truename + (merge-pathnames + (make-pathname :name "" :type "") + object)))) + nil))) + (and fasl-file + (list "Load this fasl file" + (lambda (choice object id) + (declare (ignore choice id object)) + (load ob) + nil))) + (and fasl-file + (list "Delete this fasl file" + (lambda (choice object id) + (declare (ignore choice id object)) + (let ((nt (namestring (truename ob)))) + (when (y-or-n-p-in-emacs "Delete ~a? " nt) + (delete-file nt))) + nil))) + (and source-file + (list "Edit lisp source file" + (lambda (choice object id) + (declare (ignore choice id object)) + (ed-in-emacs (namestring (truename source-file))) + nil))) + (and source-file + (list "Load lisp source file" + (lambda(choice object id) + (declare (ignore choice id object)) + (load source-file) + nil))) + (and (next-method-p) (call-next-method)))))) + +(defmethod menu-choices-for-presentation ((ob function)) + (list (list "Disassemble" + (lambda (choice object id) + (declare (ignore choice id)) + (disassemble object))))) + +(defslimefun inspect-presentation (id reset-p) + (let ((what (lookup-presented-object-or-lose id))) + (when reset-p + (reset-inspector)) + (inspect-object what))) + +(defslimefun init-presentations () + ;; FIXME: import/use swank-repl to avoid package qualifier. + (setq swank-repl:*send-repl-results-function* 'present-repl-results)) + +(provide :swank-presentations) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-quicklisp.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-quicklisp.lisp new file mode 100644 index 0000000..3654599 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-quicklisp.lisp @@ -0,0 +1,17 @@ +;;; swank-quicklisp.lisp -- Quicklisp support +;; +;; Authors: Matthew Kennedy +;; License: Public Domain +;; + +(in-package :swank) + +(defslimefun list-quicklisp-systems () + "Returns the Quicklisp systems list." + (if (member :quicklisp *features*) + (let ((ql-dist-name (find-symbol "NAME" "QL-DIST")) + (ql-system-list (find-symbol "SYSTEM-LIST" "QL"))) + (mapcar ql-dist-name (funcall ql-system-list))) + (error "Could not find Quicklisp already loaded."))) + +(provide :swank-quicklisp) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-r6rs.scm b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-r6rs.scm new file mode 100644 index 0000000..4e48050 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-r6rs.scm @@ -0,0 +1,416 @@ +;; swank-r6rs.sls --- Shareable code between swank-ikarus and swank-larceny +;; +;; Licence: public domain +;; Author: Helmut Eller +;; +;; This is a Swank server barely capable enough to process simple eval +;; requests from Emacs before dying. No fancy features like +;; backtraces, module redefintion, M-. etc. are implemented. Don't +;; even think about pc-to-source mapping. +;; +;; Despite standard modules, this file uses (swank os) and (swank sys) +;; which define implementation dependend functionality. There are +;; multiple modules in this files, which is probably not standardized. +;; + +;; Naive FORMAT implementation which supports: ~a ~s ~d ~x ~c +(library (swank format) + (export format printf fprintf) + (import (rnrs)) + + (define (format f . args) + (call-with-string-output-port + (lambda (port) (apply fprintf port f args)))) + + (define (printf f . args) + (let ((port (current-output-port))) + (apply fprintf port f args) + (flush-output-port port))) + + (define (fprintf port f . args) + (let ((len (string-length f))) + (let loop ((i 0) (args args)) + (cond ((= i len) (assert (null? args))) + ((and (char=? (string-ref f i) #\~) + (< (+ i 1) len)) + (dispatch-format (string-ref f (+ i 1)) port (car args)) + (loop (+ i 2) (cdr args))) + (else + (put-char port (string-ref f i)) + (loop (+ i 1) args)))))) + + (define (dispatch-format char port arg) + (let ((probe (assoc char format-dispatch-table))) + (cond (probe ((cdr probe) arg port)) + (else (error "invalid format char: " char))))) + + (define format-dispatch-table + `((#\a . ,display) + (#\s . ,write) + (#\d . ,(lambda (arg port) (put-string port (number->string arg 10)))) + (#\x . ,(lambda (arg port) (put-string port (number->string arg 16)))) + (#\c . ,(lambda (arg port) (put-char port arg)))))) + + +;; CL-style restarts to let us continue after errors. +(library (swank restarts) + (export with-simple-restart compute-restarts invoke-restart restart-name + write-restart-report) + (import (rnrs)) + + (define *restarts* '()) + + (define-record-type restart + (fields name reporter continuation)) + + (define (with-simple-restart name reporter thunk) + (call/cc + (lambda (k) + (let ((old-restarts *restarts*) + (restart (make-restart name (coerce-to-reporter reporter) k))) + (dynamic-wind + (lambda () (set! *restarts* (cons restart old-restarts))) + thunk + (lambda () (set! *restarts* old-restarts))))))) + + (define (compute-restarts) *restarts*) + + (define (invoke-restart restart . args) + (apply (restart-continuation restart) args)) + + (define (write-restart-report restart port) + ((restart-reporter restart) port)) + + (define (coerce-to-reporter obj) + (cond ((string? obj) (lambda (port) (put-string port obj))) + (#t (assert (procedure? obj)) obj))) + + ) + +;; This module encodes & decodes messages from the wire and queues them. +(library (swank event-queue) + (export make-event-queue wait-for-event enqueue-event + read-event write-event) + (import (rnrs) + (rnrs mutable-pairs) + (swank format)) + + (define-record-type event-queue + (fields (mutable q) wait-fun) + (protocol (lambda (init) + (lambda (wait-fun) + (init '() wait-fun))))) + + (define (wait-for-event q pattern) + (or (poll q pattern) + (begin + ((event-queue-wait-fun q) q) + (wait-for-event q pattern)))) + + (define (poll q pattern) + (let loop ((lag #f) + (l (event-queue-q q))) + (cond ((null? l) #f) + ((event-match? (car l) pattern) + (cond (lag + (set-cdr! lag (cdr l)) + (car l)) + (else + (event-queue-q-set! q (cdr l)) + (car l)))) + (else (loop l (cdr l)))))) + + (define (event-match? event pattern) + (cond ((or (number? pattern) + (member pattern '(t nil))) + (equal? event pattern)) + ((symbol? pattern) #t) + ((pair? pattern) + (case (car pattern) + ((quote) (equal? event (cadr pattern))) + ((or) (exists (lambda (p) (event-match? event p)) (cdr pattern))) + (else (and (pair? event) + (event-match? (car event) (car pattern)) + (event-match? (cdr event) (cdr pattern)))))) + (else (error "Invalid pattern: " pattern)))) + + (define (enqueue-event q event) + (event-queue-q-set! q + (append (event-queue-q q) + (list event)))) + + (define (write-event event port) + (let ((payload (call-with-string-output-port + (lambda (port) (write event port))))) + (write-length (string-length payload) port) + (put-string port payload) + (flush-output-port port))) + + (define (write-length len port) + (do ((i 24 (- i 4))) + ((= i 0)) + (put-string port + (number->string (bitwise-bit-field len (- i 4) i) + 16)))) + + (define (read-event port) + (let* ((header (string-append (get-string-n port 2) + (get-string-n port 2) + (get-string-n port 2))) + (_ (printf "header: ~s\n" header)) + (len (string->number header 16)) + (_ (printf "len: ~s\n" len)) + (payload (get-string-n port len))) + (printf "payload: ~s\n" payload) + (read (open-string-input-port payload)))) + + ) + +;; Entry points for SLIME commands. +(library (swank rpc) + (export connection-info interactive-eval + ;;compile-string-for-emacs + throw-to-toplevel sldb-abort + operator-arglist buffer-first-change + create-repl listener-eval) + (import (rnrs) + (rnrs eval) + (only (rnrs r5rs) scheme-report-environment) + (swank os) + (swank format) + (swank restarts) + (swank sys) + ) + + (define (connection-info . _) + `(,@'() + :pid ,(getpid) + :package (:name ">" :prompt ">") + :lisp-implementation (,@'() + :name ,(implementation-name) + :type "R6RS-Scheme"))) + + (define (interactive-eval string) + (call-with-values + (lambda () + (eval-in-interaction-environment (read-from-string string))) + (case-lambda + (() "; no value") + ((value) (format "~s" value)) + (values (format "values: ~s" values))))) + + (define (throw-to-toplevel) (invoke-restart-by-name-or-nil 'toplevel)) + + (define (sldb-abort) (invoke-restart-by-name-or-nil 'abort)) + + (define (invoke-restart-by-name-or-nil name) + (let ((r (find (lambda (r) (eq? (restart-name r) name)) + (compute-restarts)))) + (if r (invoke-restart r) 'nil))) + + (define (create-repl target) + (list "" "")) + + (define (listener-eval string) + (call-with-values (lambda () (eval-region string)) + (lambda values `(:values ,@(map (lambda (v) (format "~s" v)) values))))) + + (define (eval-region string) + (let ((sexp (read-from-string string))) + (if (eof-object? exp) + (values) + (eval-in-interaction-environment sexp)))) + + (define (read-from-string string) + (call-with-port (open-string-input-port string) read)) + + (define (operator-arglist . _) 'nil) + (define (buffer-first-change . _) 'nil) + + ) + +;; The server proper. Does the TCP stuff and exception handling. +(library (swank) + (export start-server) + (import (rnrs) + (rnrs eval) + (swank os) + (swank format) + (swank event-queue) + (swank restarts)) + + (define-record-type connection + (fields in-port out-port event-queue)) + + (define (start-server port) + (accept-connections (or port 4005) #f)) + + (define (start-server/port-file port-file) + (accept-connections #f port-file)) + + (define (accept-connections port port-file) + (let ((sock (make-server-socket port))) + (printf "Listening on port: ~s\n" (local-port sock)) + (when port-file + (write-port-file (local-port sock) port-file)) + (let-values (((in out) (accept sock (latin-1-codec)))) + (dynamic-wind + (lambda () #f) + (lambda () + (close-socket sock) + (serve in out)) + (lambda () + (close-port in) + (close-port out)))))) + + (define (write-port-file port port-file) + (call-with-output-file + (lambda (file) + (write port file)))) + + (define (serve in out) + (let ((err (current-error-port)) + (q (make-event-queue + (lambda (q) + (let ((e (read-event in))) + (printf "read: ~s\n" e) + (enqueue-event q e)))))) + (dispatch-loop (make-connection in out q)))) + + (define-record-type sldb-state + (fields level condition continuation next)) + + (define (dispatch-loop conn) + (let ((event (wait-for-event (connection-event-queue conn) 'x))) + (case (car event) + ((:emacs-rex) + (with-simple-restart + 'toplevel "Return to SLIME's toplevel" + (lambda () + (apply emacs-rex conn #f (cdr event))))) + (else (error "Unhandled event: ~s" event)))) + (dispatch-loop conn)) + + (define (recover thunk on-error-thunk) + (let ((ok #f)) + (dynamic-wind + (lambda () #f) + (lambda () + (call-with-values thunk + (lambda vals + (set! ok #t) + (apply values vals)))) + (lambda () + (unless ok + (on-error-thunk)))))) + + ;; Couldn't resist to exploit the prefix feature. + (define rpc-entries (environment '(prefix (swank rpc) swank:))) + + (define (emacs-rex conn sldb-state form package thread tag) + (let ((out (connection-out-port conn))) + (recover + (lambda () + (with-exception-handler + (lambda (condition) + (call/cc + (lambda (k) + (sldb-exception-handler conn condition k sldb-state)))) + (lambda () + (let ((value (apply (eval (car form) rpc-entries) (cdr form)))) + (write-event `(:return (:ok ,value) ,tag) out))))) + (lambda () + (write-event `(:return (:abort) ,tag) out))))) + + (define (sldb-exception-handler connection condition k sldb-state) + (when (serious-condition? condition) + (let ((level (if sldb-state (+ (sldb-state-level sldb-state) 1) 1)) + (out (connection-out-port connection))) + (write-event `(:debug 0 ,level ,@(debugger-info condition connection)) + out) + (dynamic-wind + (lambda () #f) + (lambda () + (sldb-loop connection + (make-sldb-state level condition k sldb-state))) + (lambda () (write-event `(:debug-return 0 ,level nil) out)))))) + + (define (sldb-loop connection state) + (apply emacs-rex connection state + (cdr (wait-for-event (connection-event-queue connection) + '(':emacs-rex . _)))) + (sldb-loop connection state)) + + (define (debugger-info condition connection) + (list `(,(call-with-string-output-port + (lambda (port) (print-condition condition port))) + ,(format " [type ~s]" (if (record? condition) + (record-type-name (record-rtd condition)) + )) + ()) + (map (lambda (r) + (list (format "~a" (restart-name r)) + (call-with-string-output-port + (lambda (port) + (write-restart-report r port))))) + (compute-restarts)) + '() + '())) + + (define (print-condition obj port) + (cond ((condition? obj) + (let ((list (simple-conditions obj))) + (case (length list) + ((0) + (display "Compuond condition with zero components" port)) + ((1) + (assert (eq? obj (car list))) + (print-simple-condition (car list) port)) + (else + (display "Compound condition:\n" port) + (for-each (lambda (c) + (display " " port) + (print-simple-condition c port) + (newline port)) + list))))) + (#t + (fprintf port "Non-condition object: ~s" obj)))) + + (define (print-simple-condition condition port) + (fprintf port "~a" (record-type-name (record-rtd condition))) + (case (count-record-fields condition) + ((0) #f) + ((1) + (fprintf port ": ") + (do-record-fields condition (lambda (name value) (write value port)))) + (else + (fprintf port ":") + (do-record-fields condition (lambda (name value) + (fprintf port "\n~a: ~s" name value)))))) + + ;; Call FUN with RECORD's rtd and parent rtds. + (define (do-record-rtds record fun) + (do ((rtd (record-rtd record) (record-type-parent rtd))) + ((not rtd)) + (fun rtd))) + + ;; Call FUN with RECORD's field names and values. + (define (do-record-fields record fun) + (do-record-rtds + record + (lambda (rtd) + (let* ((names (record-type-field-names rtd)) + (len (vector-length names))) + (do ((i 0 (+ 1 i))) + ((= i len)) + (fun (vector-ref names i) ((record-accessor rtd i) record))))))) + + ;; Return the number of fields in RECORD + (define (count-record-fields record) + (let ((i 0)) + (do-record-rtds + record (lambda (rtd) + (set! i (+ i (vector-length (record-type-field-names rtd)))))) + i)) + + ) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-repl.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-repl.lisp new file mode 100644 index 0000000..259c9ea --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-repl.lisp @@ -0,0 +1,441 @@ +;;; swank-repl.lisp --- Server side part of the Lisp listener. +;; +;; License: public domain +(in-package swank) + +(defpackage swank-repl + (:use cl swank/backend) + (:export *send-repl-results-function*) + (:import-from + swank + + *default-worker-thread-bindings* + + *loopback-interface* + + add-hook + *connection-closed-hook* + + eval-region + with-buffer-syntax + + connection + connection.socket-io + connection.repl-results + connection.user-input + connection.user-output + connection.user-io + connection.trace-output + connection.dedicated-output + connection.env + + multithreaded-connection + mconn.active-threads + mconn.repl-thread + mconn.auto-flush-thread + use-threads-p + + *emacs-connection* + default-connection + with-connection + + send-to-emacs + *communication-style* + handle-requests + wait-for-event + make-tag + thread-for-evaluation + socket-quest + + authenticate-client + encode-message + + auto-flush-loop + clear-user-input + + current-thread-id + cat + with-struct* + with-retry-restart + with-bindings + + package-string-for-prompt + find-external-format-or-lose + + defslimefun + + ;; FIXME: those should be exported from swank-repl only, but how to + ;; do that whithout breaking init files? + *use-dedicated-output-stream* + *dedicated-output-stream-port* + *globally-redirect-io*)) + +(in-package swank-repl) + +(defvar *use-dedicated-output-stream* nil + "When T swank will attempt to create a second connection to Emacs +which is used just to send output.") + +(defvar *dedicated-output-stream-port* 0 + "Which port we should use for the dedicated output stream.") + +(defvar *dedicated-output-stream-buffering* + (if (eq *communication-style* :spawn) t nil) + "The buffering scheme that should be used for the output stream. +Valid values are nil, t, :line") + +(defvar *globally-redirect-io* :started-from-emacs + "When T globally redirect all standard streams to Emacs. +When :STARTED-FROM-EMACS redirect when launched by M-x slime") + +(defun globally-redirect-io-p () + (case *globally-redirect-io* + ((t) t) + (:started-from-emacs swank-loader:*started-from-emacs*))) + +(defun open-streams (connection properties) + "Return the 5 streams for IO redirection: +DEDICATED-OUTPUT INPUT OUTPUT IO REPL-RESULTS" + (let* ((input-fn + (lambda () + (with-connection (connection) + (with-simple-restart (abort-read + "Abort reading input from Emacs.") + (read-user-input-from-emacs))))) + (dedicated-output (if *use-dedicated-output-stream* + (open-dedicated-output-stream + connection + (getf properties :coding-system)))) + (in (make-input-stream input-fn)) + (out (or dedicated-output + (make-output-stream (make-output-function connection)))) + (io (make-two-way-stream in out)) + (repl-results (swank:make-output-stream-for-target connection + :repl-result))) + (typecase connection + (multithreaded-connection + (setf (mconn.auto-flush-thread connection) + (make-auto-flush-thread out)))) + (values dedicated-output in out io repl-results))) + +(defun make-output-function (connection) + "Create function to send user output to Emacs." + (lambda (string) + (with-connection (connection) + (send-to-emacs `(:write-string ,string))))) + +(defun open-dedicated-output-stream (connection coding-system) + "Open a dedicated output connection to the Emacs on SOCKET-IO. +Return an output stream suitable for writing program output. + +This is an optimized way for Lisp to deliver output to Emacs." + (let ((socket (socket-quest *dedicated-output-stream-port* nil)) + (ef (find-external-format-or-lose coding-system))) + (unwind-protect + (let ((port (local-port socket))) + (encode-message `(:open-dedicated-output-stream ,port + ,coding-system) + (connection.socket-io connection)) + (let ((dedicated (accept-connection + socket + :external-format ef + :buffering *dedicated-output-stream-buffering* + :timeout 30))) + (authenticate-client dedicated) + (close-socket socket) + (setf socket nil) + dedicated)) + (when socket + (close-socket socket))))) + +(defmethod thread-for-evaluation ((connection multithreaded-connection) + (id (eql :find-existing))) + (or (car (mconn.active-threads connection)) + (find-repl-thread connection))) + +(defmethod thread-for-evaluation ((connection multithreaded-connection) + (id (eql :repl-thread))) + (find-repl-thread connection)) + +(defun find-repl-thread (connection) + (cond ((not (use-threads-p)) + (current-thread)) + (t + (let ((thread (mconn.repl-thread connection))) + (cond ((not thread) nil) + ((thread-alive-p thread) thread) + (t + (setf (mconn.repl-thread connection) + (spawn-repl-thread connection "new-repl-thread")))))))) + +(defun spawn-repl-thread (connection name) + (spawn (lambda () + (with-bindings *default-worker-thread-bindings* + (repl-loop connection))) + :name name)) + +(defun repl-loop (connection) + (handle-requests connection)) + +;;;;; Redirection during requests +;;; +;;; We always redirect the standard streams to Emacs while evaluating +;;; an RPC. This is done with simple dynamic bindings. + +(defslimefun create-repl (target &key coding-system) + (assert (eq target nil)) + (let ((conn *emacs-connection*)) + (initialize-streams-for-connection conn `(:coding-system ,coding-system)) + (with-struct* (connection. @ conn) + (setf (@ env) + `((*standard-input* . ,(@ user-input)) + ,@(unless (globally-redirect-io-p) + `((*standard-output* . ,(@ user-output)) + (*trace-output* . ,(or (@ trace-output) (@ user-output))) + (*error-output* . ,(@ user-output)) + (*debug-io* . ,(@ user-io)) + (*query-io* . ,(@ user-io)) + (*terminal-io* . ,(@ user-io)))))) + (maybe-redirect-global-io conn) + (add-hook *connection-closed-hook* 'update-redirection-after-close) + (typecase conn + (multithreaded-connection + (setf (mconn.repl-thread conn) + (spawn-repl-thread conn "repl-thread")))) + (list (package-name *package*) + (package-string-for-prompt *package*))))) + +(defun initialize-streams-for-connection (connection properties) + (multiple-value-bind (dedicated in out io repl-results) + (open-streams connection properties) + (setf (connection.dedicated-output connection) dedicated + (connection.user-io connection) io + (connection.user-output connection) out + (connection.user-input connection) in + (connection.repl-results connection) repl-results) + connection)) + +(defun read-user-input-from-emacs () + (let ((tag (make-tag))) + (force-output) + (send-to-emacs `(:read-string ,(current-thread-id) ,tag)) + (let ((ok nil)) + (unwind-protect + (prog1 (caddr (wait-for-event `(:emacs-return-string ,tag value))) + (setq ok t)) + (unless ok + (send-to-emacs `(:read-aborted ,(current-thread-id) ,tag))))))) + +;;;;; Listener eval + +(defvar *listener-eval-function* 'repl-eval) + +(defvar *listener-saved-value* nil) + +(defslimefun listener-save-value (slimefun &rest args) + "Apply SLIMEFUN to ARGS and save the value. +The saved value should be visible to all threads and retrieved via +LISTENER-GET-VALUE." + (setq *listener-saved-value* (apply slimefun args)) + t) + +(defslimefun listener-get-value () + "Get the last value saved by LISTENER-SAVE-VALUE. +The value should be produced as if it were requested through +LISTENER-EVAL directly, so that spacial variables *, etc are set." + (listener-eval (let ((*package* (find-package :keyword))) + (write-to-string '*listener-saved-value*)))) + +(defslimefun listener-eval (string &key (window-width nil window-width-p)) + (if window-width-p + (let ((*print-right-margin* window-width)) + (funcall *listener-eval-function* string)) + (funcall *listener-eval-function* string))) + +(defslimefun clear-repl-variables () + (let ((variables '(*** ** * /// // / +++ ++ +))) + (loop for variable in variables + do (setf (symbol-value variable) nil)))) + +(defvar *send-repl-results-function* 'send-repl-results-to-emacs) + +(defun repl-eval (string) + (clear-user-input) + (with-buffer-syntax () + (with-retry-restart (:msg "Retry SLIME REPL evaluation request.") + (track-package + (lambda () + (multiple-value-bind (values last-form) (eval-region string) + (setq *** ** ** * * (car values) + /// // // / / values + +++ ++ ++ + + last-form) + (funcall *send-repl-results-function* values)))))) + nil) + +(defun track-package (fun) + (let ((p *package*)) + (unwind-protect (funcall fun) + (unless (eq *package* p) + (send-to-emacs (list :new-package (package-name *package*) + (package-string-for-prompt *package*))))))) + +(defun send-repl-results-to-emacs (values) + (finish-output) + (if (null values) + (send-to-emacs `(:write-string "; No value" :repl-result)) + (dolist (v values) + (send-to-emacs `(:write-string ,(cat (prin1-to-string v) #\newline) + :repl-result))))) + +(defslimefun redirect-trace-output (target) + (setf (connection.trace-output *emacs-connection*) + (swank:make-output-stream-for-target *emacs-connection* target)) + nil) + + + +;;;; IO to Emacs +;;; +;;; This code handles redirection of the standard I/O streams +;;; (`*standard-output*', etc) into Emacs. The `connection' structure +;;; contains the appropriate streams, so all we have to do is make the +;;; right bindings. + +;;;;; Global I/O redirection framework +;;; +;;; Optionally, the top-level global bindings of the standard streams +;;; can be assigned to be redirected to Emacs. When Emacs connects we +;;; redirect the streams into the connection, and they keep going into +;;; that connection even if more are established. If the connection +;;; handling the streams closes then another is chosen, or if there +;;; are no connections then we revert to the original (real) streams. +;;; +;;; It is slightly tricky to assign the global values of standard +;;; streams because they are often shadowed by dynamic bindings. We +;;; solve this problem by introducing an extra indirection via synonym +;;; streams, so that *STANDARD-INPUT* is a synonym stream to +;;; *CURRENT-STANDARD-INPUT*, etc. We never shadow the "current" +;;; variables, so they can always be assigned to affect a global +;;; change. + +;;;;; Global redirection setup + +(defvar *saved-global-streams* '() + "A plist to save and restore redirected stream objects. +E.g. the value for '*standard-output* holds the stream object +for *standard-output* before we install our redirection.") + +(defun setup-stream-indirection (stream-var &optional stream) + "Setup redirection scaffolding for a global stream variable. +Supposing (for example) STREAM-VAR is *STANDARD-INPUT*, this macro: + +1. Saves the value of *STANDARD-INPUT* in `*SAVED-GLOBAL-STREAMS*'. + +2. Creates *CURRENT-STANDARD-INPUT*, initially with the same value as +*STANDARD-INPUT*. + +3. Assigns *STANDARD-INPUT* to a synonym stream pointing to +*CURRENT-STANDARD-INPUT*. + +This has the effect of making *CURRENT-STANDARD-INPUT* contain the +effective global value for *STANDARD-INPUT*. This way we can assign +the effective global value even when *STANDARD-INPUT* is shadowed by a +dynamic binding." + (let ((current-stream-var (prefixed-var '#:current stream-var)) + (stream (or stream (symbol-value stream-var)))) + ;; Save the real stream value for the future. + (setf (getf *saved-global-streams* stream-var) stream) + ;; Define a new variable for the effective stream. + ;; This can be reassigned. + (proclaim `(special ,current-stream-var)) + (set current-stream-var stream) + ;; Assign the real binding as a synonym for the current one. + (let ((stream (make-synonym-stream current-stream-var))) + (set stream-var stream) + (set-default-initial-binding stream-var `(quote ,stream))))) + +(defun prefixed-var (prefix variable-symbol) + "(PREFIXED-VAR \"FOO\" '*BAR*) => SWANK::*FOO-BAR*" + (let ((basename (subseq (symbol-name variable-symbol) 1))) + (intern (format nil "*~A-~A" (string prefix) basename) :swank))) + +(defvar *standard-output-streams* + '(*standard-output* *error-output* *trace-output*) + "The symbols naming standard output streams.") + +(defvar *standard-input-streams* + '(*standard-input*) + "The symbols naming standard input streams.") + +(defvar *standard-io-streams* + '(*debug-io* *query-io* *terminal-io*) + "The symbols naming standard io streams.") + +(defun init-global-stream-redirection () + (when (globally-redirect-io-p) + (cond (*saved-global-streams* + (warn "Streams already redirected.")) + (t + (mapc #'setup-stream-indirection + (append *standard-output-streams* + *standard-input-streams* + *standard-io-streams*)))))) + +(defun globally-redirect-io-to-connection (connection) + "Set the standard I/O streams to redirect to CONNECTION. +Assigns *CURRENT-* for all standard streams." + (dolist (o *standard-output-streams*) + (set (prefixed-var '#:current o) + (connection.user-output connection))) + ;; FIXME: If we redirect standard input to Emacs then we get the + ;; regular Lisp top-level trying to read from our REPL. + ;; + ;; Perhaps the ideal would be for the real top-level to run in a + ;; thread with local bindings for all the standard streams. Failing + ;; that we probably would like to inhibit it from reading while + ;; Emacs is connected. + ;; + ;; Meanwhile we just leave *standard-input* alone. + #+NIL + (dolist (i *standard-input-streams*) + (set (prefixed-var '#:current i) + (connection.user-input connection))) + (dolist (io *standard-io-streams*) + (set (prefixed-var '#:current io) + (connection.user-io connection)))) + +(defun revert-global-io-redirection () + "Set *CURRENT-* to *REAL-* for all standard streams." + (dolist (stream-var (append *standard-output-streams* + *standard-input-streams* + *standard-io-streams*)) + (set (prefixed-var '#:current stream-var) + (getf *saved-global-streams* stream-var)))) + +;;;;; Global redirection hooks + +(defvar *global-stdio-connection* nil + "The connection to which standard I/O streams are globally redirected. +NIL if streams are not globally redirected.") + +(defun maybe-redirect-global-io (connection) + "Consider globally redirecting to CONNECTION." + (when (and (globally-redirect-io-p) (null *global-stdio-connection*) + (connection.user-io connection)) + (unless *saved-global-streams* + (init-global-stream-redirection)) + (setq *global-stdio-connection* connection) + (globally-redirect-io-to-connection connection))) + +(defun update-redirection-after-close (closed-connection) + "Update redirection after a connection closes." + (check-type closed-connection connection) + (when (eq *global-stdio-connection* closed-connection) + (if (and (default-connection) (globally-redirect-io-p)) + ;; Redirect to another connection. + (globally-redirect-io-to-connection (default-connection)) + ;; No more connections, revert to the real streams. + (progn (revert-global-io-redirection) + (setq *global-stdio-connection* nil))))) + +(provide :swank-repl) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-sbcl-exts.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-sbcl-exts.lisp new file mode 100644 index 0000000..6cbe09d --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-sbcl-exts.lisp @@ -0,0 +1,67 @@ +;;; swank-sbcl-exts.lisp --- Misc extensions for SBCL +;; +;; Authors: Tobias C. Rittweiler +;; +;; License: Public Domain +;; + +(in-package :swank) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (swank-require :swank-arglists)) + +;; We need to do this so users can place `slime-sbcl-exts' into their +;; ~/.emacs, and still use any implementation they want. +#+sbcl +(progn + +;;; Display arglist of instructions. +;;; +(defmethod compute-enriched-decoded-arglist ((operator-form (eql 'sb-assem:inst)) + argument-forms) + (flet ((decode-instruction-arglist (instr-name instr-arglist) + (let ((decoded-arglist (decode-arglist instr-arglist))) + ;; The arglist of INST is (instruction ...INSTR-ARGLIST...). + (push 'sb-assem::instruction (arglist.required-args decoded-arglist)) + (values decoded-arglist + (list instr-name) + t)))) + (if (null argument-forms) + (call-next-method) + (destructuring-bind (instruction &rest args) argument-forms + (declare (ignore args)) + (let* ((instr-name + (typecase instruction + (arglist-dummy + (string-upcase (arglist-dummy.string-representation instruction))) + (symbol + (string-downcase instruction)))) + (instr-fn + #+#.(swank/backend:with-symbol 'op-encoder-name 'sb-assem) + (or (sb-assem::op-encoder-name instr-name) + (sb-assem::op-encoder-name (string-upcase instr-name))) + #+#.(swank/backend:with-symbol 'inst-emitter-symbol 'sb-assem) + (sb-assem::inst-emitter-symbol instr-name) + #+(and + (not #.(swank/backend:with-symbol 'inst-emitter-symbol 'sb-assem)) + #.(swank/backend:with-symbol '*assem-instructions* 'sb-assem)) + (gethash instr-name sb-assem:*assem-instructions*))) + (cond ((functionp instr-fn) + (with-available-arglist (arglist) (arglist instr-fn) + (decode-instruction-arglist instr-name arglist))) + ((fboundp instr-fn) + (with-available-arglist (arglist) (arglist instr-fn) + ;; SB-ASSEM:INST invokes a symbolic INSTR-FN with + ;; current segment and current vop implicitly. + (decode-instruction-arglist instr-name + (if (or (get instr-fn :macro) + (macro-function instr-fn)) + arglist + (cddr arglist))))) + (t + (call-next-method)))))))) + + +) ; PROGN + +(provide :swank-sbcl-exts) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-snapshot.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-snapshot.lisp new file mode 100644 index 0000000..52a87ed --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-snapshot.lisp @@ -0,0 +1,67 @@ + +(defpackage swank-snapshot + (:use cl) + (:export restore-snapshot save-snapshot background-save-snapshot) + (:import-from swank defslimefun)) +(in-package swank-snapshot) + +(defslimefun save-snapshot (image-file) + (swank/backend:save-image image-file + (let ((c swank::*emacs-connection*)) + (lambda () (resurrect c)))) + (format nil "Dumped lisp to ~A" image-file)) + +(defslimefun restore-snapshot (image-file) + (let* ((conn swank::*emacs-connection*) + (stream (swank::connection.socket-io conn)) + (clone (swank/backend:dup (swank/backend:socket-fd stream))) + (style (swank::connection.communication-style conn)) + (repl (if (swank::connection.user-io conn) t)) + (args (list "--swank-fd" (format nil "~d" clone) + "--swank-style" (format nil "~s" style) + "--swank-repl" (format nil "~s" repl)))) + (swank::close-connection conn nil nil) + (swank/backend:exec-image image-file args))) + +(defslimefun background-save-snapshot (image-file) + (let ((connection swank::*emacs-connection*)) + (flet ((complete (success) + (let ((swank::*emacs-connection* connection)) + (swank::background-message + "Dumping lisp image ~A ~:[failed!~;succeeded.~]" + image-file success))) + (awaken () + (resurrect connection))) + (swank/backend:background-save-image image-file + :restart-function #'awaken + :completion-function #'complete) + (format nil "Started dumping lisp to ~A..." image-file)))) + +(in-package :swank) + +(defun swank-snapshot::resurrect (old-connection) + (setq *log-output* nil) + (init-log-output) + (clear-event-history) + (setq *connections* (delete old-connection *connections*)) + (format *error-output* "args: ~s~%" (command-line-args)) + (let* ((fd (read-command-line-arg "--swank-fd")) + (style (read-command-line-arg "--swank-style")) + (repl (read-command-line-arg "--swank-repl")) + (* (format *error-output* "fd=~s style=~s~%" fd style)) + (stream (make-fd-stream fd nil)) + (connection (make-connection nil stream style))) + (let ((*emacs-connection* connection)) + (when repl (swank-repl:create-repl nil)) + (background-message "~A" "Lisp image restored")) + (serve-requests connection) + (simple-repl))) + +(defun read-command-line-arg (name) + (let* ((args (command-line-args)) + (pos (position name args :test #'equal))) + (read-from-string (elt args (1+ pos))))) + +(in-package :swank-snapshot) + +(provide :swank-snapshot) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-sprof.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-sprof.lisp new file mode 100644 index 0000000..675240f --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-sprof.lisp @@ -0,0 +1,154 @@ +;;; swank-sprof.lisp +;; +;; Authors: Juho Snellman +;; +;; License: MIT +;; + +(in-package :swank) + +#+sbcl +(eval-when (:compile-toplevel :load-toplevel :execute) + (require :sb-sprof)) + +#+sbcl(progn + +(defvar *call-graph* nil) +(defvar *node-numbers* nil) +(defvar *number-nodes* nil) + +(defun frame-name (name) + (if (consp name) + (case (first name) + ((sb-c::xep sb-c::tl-xep + sb-c::&more-processor + sb-c::top-level-form + sb-c::&optional-processor) + (second name)) + (sb-pcl::fast-method + (cdr name)) + ((flet labels lambda) + (let* ((in (member :in name))) + (if (stringp (cadr in)) + (append (ldiff name in) (cddr in)) + name))) + (t + name)) + name)) + +(defun pretty-name (name) + (let ((*package* (find-package :common-lisp-user)) + (*print-right-margin* most-positive-fixnum)) + (format nil "~S" (frame-name name)))) + +(defun samples-percent (count) + (sb-sprof::samples-percent *call-graph* count)) + +(defun node-values (node) + (values (pretty-name (sb-sprof::node-name node)) + (samples-percent (sb-sprof::node-count node)) + (samples-percent (sb-sprof::node-accrued-count node)))) + +(defun filter-swank-nodes (nodes) + (let ((swank-packages (load-time-value + (mapcar #'find-package + '(swank swank/rpc swank/mop + swank/match swank/backend))))) + (remove-if (lambda (node) + (let ((name (sb-sprof::node-name node))) + (and (symbolp name) + (member (symbol-package name) swank-packages + :test #'eq)))) + nodes))) + +(defun serialize-call-graph (&key exclude-swank) + (let ((nodes (sb-sprof::call-graph-flat-nodes *call-graph*))) + (when exclude-swank + (setf nodes (filter-swank-nodes nodes))) + (setf nodes (sort (copy-list nodes) #'> + ;; :key #'sb-sprof::node-count))) + :key #'sb-sprof::node-accrued-count)) + (setf *number-nodes* (make-hash-table)) + (setf *node-numbers* (make-hash-table)) + (loop for node in nodes + for i from 1 + with total = 0 + collect (multiple-value-bind (name self cumulative) + (node-values node) + (setf (gethash node *node-numbers*) i + (gethash i *number-nodes*) node) + (incf total self) + (list i name self cumulative total)) into list + finally (return + (let ((rest (- 100 total))) + (return (append list + `((nil "Elsewhere" ,rest nil nil))))))))) + +(defslimefun swank-sprof-get-call-graph (&key exclude-swank) + (when (setf *call-graph* (sb-sprof:report :type nil)) + (serialize-call-graph :exclude-swank exclude-swank))) + +(defslimefun swank-sprof-expand-node (index) + (let* ((node (gethash index *number-nodes*))) + (labels ((caller-count (v) + (loop for e in (sb-sprof::vertex-edges v) do + (when (eq (sb-sprof::edge-vertex e) node) + (return-from caller-count (sb-sprof::call-count e)))) + 0) + (serialize-node (node count) + (etypecase node + (sb-sprof::cycle + (list (sb-sprof::cycle-index node) + (sb-sprof::cycle-name node) + (samples-percent count))) + (sb-sprof::node + (let ((name (node-values node))) + (list (gethash node *node-numbers*) + name + (samples-percent count))))))) + (list :callers (loop for node in + (sort (copy-list (sb-sprof::node-callers node)) #'> + :key #'caller-count) + collect (serialize-node node + (caller-count node))) + :calls (let ((edges (sort (copy-list (sb-sprof::vertex-edges node)) + #'> + :key #'sb-sprof::call-count))) + (loop for edge in edges + collect + (serialize-node (sb-sprof::edge-vertex edge) + (sb-sprof::call-count edge)))))))) + +(defslimefun swank-sprof-disassemble (index) + (let* ((node (gethash index *number-nodes*)) + (debug-info (sb-sprof::node-debug-info node))) + (with-output-to-string (s) + (typecase debug-info + (sb-impl::code-component + (sb-disassem::disassemble-memory (sb-vm::code-instructions debug-info) + (sb-vm::%code-code-size debug-info) + :stream s)) + (sb-di::compiled-debug-fun + (let ((component (sb-di::compiled-debug-fun-component debug-info))) + (sb-disassem::disassemble-code-component component :stream s))) + (t `(:error "No disassembly available")))))) + +(defslimefun swank-sprof-source-location (index) + (let* ((node (gethash index *number-nodes*)) + (debug-info (sb-sprof::node-debug-info node))) + (or (when (typep debug-info 'sb-di::compiled-debug-fun) + (let* ((component (sb-di::compiled-debug-fun-component debug-info)) + (function (sb-kernel::%code-entry-points component))) + (when function + (find-source-location function)))) + `(:error "No source location available")))) + +(defslimefun swank-sprof-start (&key (mode :cpu)) + (sb-sprof:start-profiling :mode mode)) + +(defslimefun swank-sprof-stop () + (sb-sprof:stop-profiling)) + +) + +(provide :swank-sprof) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-trace-dialog.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-trace-dialog.lisp new file mode 100644 index 0000000..5cf95fd --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-trace-dialog.lisp @@ -0,0 +1,264 @@ +(defpackage :swank-trace-dialog + (:use :cl) + (:import-from :swank :defslimefun :from-string :to-string) + (:export #:clear-trace-tree + #:dialog-toggle-trace + #:dialog-trace + #:dialog-traced-p + #:dialog-untrace + #:dialog-untrace-all + #:inspect-trace-part + #:report-partial-tree + #:report-specs + #:report-total + #:report-trace-detail + #:report-specs + #:trace-format + #:still-inside + #:exited-non-locally + #:*record-backtrace* + #:*traces-per-report* + #:*dialog-trace-follows-trace* + #:find-trace-part + #:find-trace)) + +(in-package :swank-trace-dialog) + +(defparameter *record-backtrace* nil + "Record a backtrace of the last 20 calls for each trace. + +Beware that this may have a drastic performance impact on your +program.") + +(defparameter *traces-per-report* 150 + "Number of traces to report to emacs in each batch.") + + +;;;; `trace-entry' model +;;;; +(defvar *traces* (make-array 1000 :fill-pointer 0 + :adjustable t)) + +(defvar *trace-lock* (swank/backend:make-lock :name "swank-trace-dialog lock")) + +(defvar *current-trace-by-thread* (make-hash-table)) + +(defclass trace-entry () + ((id :reader id-of) + (children :accessor children-of :initform nil) + (backtrace :accessor backtrace-of :initform (when *record-backtrace* + (useful-backtrace))) + + (spec :initarg :spec :accessor spec-of + :initform (error "must provide a spec")) + (args :initarg :args :accessor args-of + :initform (error "must provide args")) + (parent :initarg :parent :reader parent-of + :initform (error "must provide a parent, even if nil")) + (retlist :initarg :retlist :accessor retlist-of + :initform 'still-inside))) + +(defmethod initialize-instance :after ((entry trace-entry) &rest initargs) + (declare (ignore initargs)) + (if (parent-of entry) + (nconc (children-of (parent-of entry)) (list entry))) + (swank/backend:call-with-lock-held + *trace-lock* + #'(lambda () + (setf (slot-value entry 'id) (fill-pointer *traces*)) + (vector-push-extend entry *traces*)))) + +(defmethod print-object ((entry trace-entry) stream) + (print-unreadable-object (entry stream) + (format stream "~a: ~a" (id-of entry) (spec-of entry)))) + +(defun completed-p (trace) (not (eq (retlist-of trace) 'still-inside))) + +(defun find-trace (id) + (when (<= 0 id (1- (length *traces*))) + (aref *traces* id))) + +(defun find-trace-part (id part-id type) + (let* ((trace (find-trace id)) + (l (and trace + (ecase type + (:arg (args-of trace)) + (:retval (swank::ensure-list (retlist-of trace))))))) + (values (nth part-id l) + (< part-id (length l))))) + +(defun useful-backtrace () + (swank/backend:call-with-debugging-environment + #'(lambda () + (loop for i from 0 + for frame in (swank/backend:compute-backtrace 0 20) + collect (list i (swank::frame-to-string frame)))))) + +(defun current-trace () + (gethash (swank/backend:current-thread) *current-trace-by-thread*)) + +(defun (setf current-trace) (trace) + (setf (gethash (swank/backend:current-thread) *current-trace-by-thread*) + trace)) + + +;;;; Control of traced specs +;;; +(defvar *traced-specs* '()) + +(defslimefun dialog-trace (spec) + (flet ((before-hook (args) + (setf (current-trace) (make-instance 'trace-entry + :spec spec + :args args + :parent (current-trace)))) + (after-hook (retlist) + (let ((trace (current-trace))) + (when trace + ;; the current trace might have been wiped away if the + ;; user cleared the tree in the meantime. no biggie, + ;; don't do anything. + ;; + (setf (retlist-of trace) retlist + (current-trace) (parent-of trace)))))) + (when (dialog-traced-p spec) + (warn "~a is apparently already traced! Untracing and retracing." spec) + (dialog-untrace spec)) + (swank/backend:wrap spec 'trace-dialog + :before #'before-hook + :after #'after-hook) + (pushnew spec *traced-specs*) + (format nil "~a is now traced for trace dialog" spec))) + +(defslimefun dialog-untrace (spec) + (swank/backend:unwrap spec 'trace-dialog) + (setq *traced-specs* (remove spec *traced-specs* :test #'equal)) + (format nil "~a is now untraced for trace dialog" spec)) + +(defslimefun dialog-toggle-trace (spec) + (if (dialog-traced-p spec) + (dialog-untrace spec) + (dialog-trace spec))) + +(defslimefun dialog-traced-p (spec) + (find spec *traced-specs* :test #'equal)) + +(defslimefun dialog-untrace-all () + (untrace) + (mapcar #'dialog-untrace *traced-specs*)) + +(defparameter *dialog-trace-follows-trace* nil) + +(setq swank:*after-toggle-trace-hook* + #'(lambda (spec traced-p) + (when *dialog-trace-follows-trace* + (cond (traced-p + (dialog-trace spec) + "traced for trace dialog as well") + (t + (dialog-untrace spec) + "untraced for the trace dialog as well"))))) + + +;;;; A special kind of trace call +;;; +(defun trace-format (format-spec &rest format-args) + "Make a string from FORMAT-SPEC and FORMAT-ARGS and as a trace." + (let* ((line (apply #'format nil format-spec format-args))) + (make-instance 'trace-entry :spec line + :args format-args + :parent (current-trace) + :retlist nil))) + + +;;;; Reporting to emacs +;;; +(defparameter *visitor-idx* 0) + +(defparameter *visitor-key* nil) + +(defvar *unfinished-traces* '()) + +(defun describe-trace-for-emacs (trace) + `(,(id-of trace) + ,(and (parent-of trace) (id-of (parent-of trace))) + ,(spec-of trace) + ,(loop for arg in (args-of trace) + for i from 0 + collect (list i (swank::to-line arg))) + ,(loop for retval in (swank::ensure-list (retlist-of trace)) + for i from 0 + collect (list i (swank::to-line retval))))) + +(defslimefun report-partial-tree (key) + (unless (equal key *visitor-key*) + (setq *visitor-idx* 0 + *visitor-key* key)) + (let* ((recently-finished + (loop with i = 0 + for trace in *unfinished-traces* + while (< i *traces-per-report*) + when (completed-p trace) + collect trace + and do + (incf i) + (setq *unfinished-traces* + (remove trace *unfinished-traces*)))) + (new (loop for i + from (length recently-finished) + below *traces-per-report* + while (< *visitor-idx* (length *traces*)) + for trace = (aref *traces* *visitor-idx*) + collect trace + unless (completed-p trace) + do (push trace *unfinished-traces*) + do (incf *visitor-idx*)))) + (list + (mapcar #'describe-trace-for-emacs + (append recently-finished new)) + (- (length *traces*) *visitor-idx*) + key))) + +(defslimefun report-trace-detail (trace-id) + (swank::call-with-bindings + swank::*inspector-printer-bindings* + #'(lambda () + (let ((trace (find-trace trace-id))) + (when trace + (append + (describe-trace-for-emacs trace) + (list (backtrace-of trace) + (swank::to-line trace)))))))) + +(defslimefun report-specs () + (sort (copy-list *traced-specs*) + #'string< + :key #'princ-to-string)) + +(defslimefun report-total () + (length *traces*)) + +(defslimefun clear-trace-tree () + (setf *current-trace-by-thread* (clrhash *current-trace-by-thread*) + *visitor-key* nil + *unfinished-traces* nil) + (swank/backend:call-with-lock-held + *trace-lock* + #'(lambda () (setf (fill-pointer *traces*) 0))) + nil) + +;; HACK: `swank::*inspector-history*' is unbound by default and needs +;; a reset in that case so that it won't error `swank::inspect-object' +;; before any other object is inspected in the slime session. +;; +(unless (boundp 'swank::*inspector-history*) + (swank::reset-inspector)) + +(defslimefun inspect-trace-part (trace-id part-id type) + (multiple-value-bind (obj found) + (find-trace-part trace-id part-id type) + (if found + (swank::inspect-object obj) + (error "No object found with ~a, ~a and ~a" trace-id part-id type)))) + +(provide :swank-trace-dialog) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-util.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-util.lisp new file mode 100644 index 0000000..72743ba --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank-util.lisp @@ -0,0 +1,63 @@ +;;; swank-util.lisp --- stuff of questionable utility +;; +;; License: public domain + +(in-package :swank) + +(defmacro do-symbols* ((var &optional (package '*package*) result-form) + &body body) + "Just like do-symbols, but makes sure a symbol is visited only once." + (let ((seen-ht (gensym "SEEN-HT"))) + `(let ((,seen-ht (make-hash-table :test #'eq))) + (do-symbols (,var ,package ,result-form) + (unless (gethash ,var ,seen-ht) + (setf (gethash ,var ,seen-ht) t) + (tagbody ,@body)))))) + +(defun classify-symbol (symbol) + "Returns a list of classifiers that classify SYMBOL according to its +underneath objects (e.g. :BOUNDP if SYMBOL constitutes a special +variable.) The list may contain the following classification +keywords: :BOUNDP, :FBOUNDP, :CONSTANT, :GENERIC-FUNCTION, +:TYPESPEC, :CLASS, :MACRO, :SPECIAL-OPERATOR, and/or :PACKAGE" + (check-type symbol symbol) + (flet ((type-specifier-p (s) + (or (documentation s 'type) + (not (eq (type-specifier-arglist s) :not-available))))) + (let (result) + (when (boundp symbol) (push (if (constantp symbol) + :constant :boundp) result)) + (when (fboundp symbol) (push :fboundp result)) + (when (type-specifier-p symbol) (push :typespec result)) + (when (find-class symbol nil) (push :class result)) + (when (macro-function symbol) (push :macro result)) + (when (special-operator-p symbol) (push :special-operator result)) + (when (find-package symbol) (push :package result)) + (when (and (fboundp symbol) + (typep (ignore-errors (fdefinition symbol)) + 'generic-function)) + (push :generic-function result)) + result))) + +(defun symbol-classification-string (symbol) + "Return a string in the form -f-c---- where each letter stands for +boundp fboundp generic-function class macro special-operator package" + (let ((letters "bfgctmsp") + (result (copy-seq "--------"))) + (flet ((flip (letter) + (setf (char result (position letter letters)) + letter))) + (when (boundp symbol) (flip #\b)) + (when (fboundp symbol) + (flip #\f) + (when (typep (ignore-errors (fdefinition symbol)) + 'generic-function) + (flip #\g))) + (when (type-specifier-p symbol) (flip #\t)) + (when (find-class symbol nil) (flip #\c) ) + (when (macro-function symbol) (flip #\m)) + (when (special-operator-p symbol) (flip #\s)) + (when (find-package symbol) (flip #\p)) + result))) + +(provide :swank-util) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank.rb b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank.rb new file mode 100644 index 0000000..6993649 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/swank.rb @@ -0,0 +1,385 @@ +# swank.rb --- swank server for Ruby. +# +# This is my first Ruby program and looks probably rather strange. Some +# people write Scheme interpreters when learning new languages, I +# write swank backends. +# +# Only a few things work. +# 1. Start the server with something like: ruby -r swank -e swank +# 2. Use M-x slime-connect to establish a connection + +require "socket" + +def swank(port=4005) + accept_connections port, false +end + +def start_swank(port_file) + accept_connections false, port_file +end + +def accept_connections(port, port_file) + server = TCPServer.new("localhost", port || 0) + puts "Listening on #{server.addr.inspect}\n" + if port_file + write_port_file server.addr[1], port_file + end + socket = begin server.accept ensure server.close end + begin + serve socket.to_io + ensure + socket.close + end +end + +def write_port_file(port, filename) + File.open(filename, File::CREAT|File::EXCL|File::WRONLY) do |f| + f.puts port + end +end + +def serve(io) + main_loop(io) +end + +def main_loop(io) + c = Connection.new(io) + while true + catch :swank_top_level do + c.dispatch(read_packet(io)) + end + end +end + +class Connection + + def initialize(io) + @io = io + end + + def dispatch(event) + puts "dispatch: %s\n" % event.inspect + case event[0] + when :":emacs-rex" + emacs_rex *event[1..4] + else raise "Unhandled event: #{event.inspect}" + end + end + + def send_to_emacs(obj) + payload = write_sexp_to_string(obj) + @io.write("%06x" % payload.length) + @io.write payload + @io.flush + end + + def emacs_rex(form, pkg, thread, id) + proc = $rpc_entries[form[0]] + args = form[1..-1]; + begin + raise "Undefined function: #{form[0]}" unless proc + value = proc[*args] + rescue Exception => exc + begin + pseudo_debug exc + ensure + send_to_emacs [:":return", [:":abort"], id] + end + else + send_to_emacs [:":return", [:":ok", value], id] + end + end + + def pseudo_debug(exc) + level = 1 + send_to_emacs [:":debug", 0, level] + sldb_info(exc, 0, 20) + begin + sldb_loop exc + ensure + send_to_emacs [:":debug-return", 0, level, :nil] + end + end + + def sldb_loop(exc) + $sldb_context = [self,exc] + while true + dispatch(read_packet(@io)) + end + end + + def sldb_info(exc, start, _end) + [[exc.to_s, + " [%s]" % exc.class.name, + :nil], + sldb_restarts(exc), + sldb_backtrace(exc, start, _end), + []] + end + + def sldb_restarts(exc) + [["Quit", "SLIME top-level."]] + end + + def sldb_backtrace(exc, start, _end) + bt = [] + exc.backtrace[start.._end].each_with_index do |frame, i| + bt << [i, frame] + end + bt + end + + def frame_src_loc(exc, frame) + string = exc.backtrace[frame] + match = /([^:]+):([0-9]+)/.match(string) + if match + file,line = match[1..2] + [:":location", [:":file", file], [:":line", line.to_i], :nil] + else + [:":error", "no src-loc for frame: #{string}"] + end + end + +end + +$rpc_entries = Hash.new + +$rpc_entries[:"swank:connection-info"] = lambda do || + [:":pid", $$, + :":package", [:":name", "ruby", :":prompt", "ruby> "], + :":lisp-implementation", [:":type", "Ruby", + :":name", "ruby", + :":version", RUBY_VERSION]] +end + +def swank_interactive_eval(string) + eval(string,TOPLEVEL_BINDING).inspect +end + +$rpc_entries[:"swank:interactive-eval"] = \ +$rpc_entries[:"swank:interactive-eval-region"] = \ +$rpc_entries[:"swank:pprint-eval"] = lambda { |string| + swank_interactive_eval string +} + +$rpc_entries[:"swank:throw-to-toplevel"] = lambda { + throw :swank_top_level +} + +$rpc_entries[:"swank:backtrace"] = lambda do |from, to| + conn, exc = $sldb_context + conn.sldb_backtrace(exc, from, to) +end + +$rpc_entries[:"swank:frame-source-location"] = lambda do |frame| + conn, exc = $sldb_context + conn.frame_src_loc(exc, frame) +end + +#ignored +$rpc_entries[:"swank:buffer-first-change"] = \ +$rpc_entries[:"swank:operator-arglist"] = lambda do + :nil +end + +$rpc_entries[:"swank:simple-completions"] = lambda do |prefix, pkg| + swank_simple_completions prefix, pkg +end + +# def swank_simple_completions(prefix, pkg) + +def read_packet(io) + header = read_chunk(io, 6) + len = header.hex + payload = read_chunk(io, len) + #$deferr.puts payload.inspect + read_sexp_from_string(payload) +end + +def read_chunk(io, len) + buffer = io.read(len) + raise "short read" if buffer.length != len + buffer +end + +def write_sexp_to_string(obj) + string = "" + write_sexp_to_string_loop obj, string + string +end + +def write_sexp_to_string_loop(obj, string) + if obj.is_a? String + string << "\"" + string << obj.gsub(/(["\\])/,'\\\\\1') + string << "\"" + elsif obj.is_a? Array + string << "(" + max = obj.length-1 + obj.each_with_index do |e,i| + write_sexp_to_string_loop e, string + string << " " unless i == max + end + string << ")" + elsif obj.is_a? Symbol or obj.is_a? Numeric + string << obj.to_s + elsif obj == false + string << "nil" + elsif obj == true + string << "t" + else raise "Can't write: #{obj.inspect}" + end +end + +def read_sexp_from_string(string) + stream = StringInputStream.new(string) + reader = LispReader.new(stream) + reader.read +end + +class LispReader + def initialize(io) + @io = io + end + + def read(allow_consing_dot=false) + skip_whitespace + c = @io.getc + case c + when ?( then read_list(true) + when ?" then read_string + when ?' then read_quote + when nil then raise EOFError.new("EOF during read") + else + @io.ungetc(c) + obj = read_number_or_symbol + if obj == :"." and not allow_consing_dot + raise "Consing-dot in invalid context" + end + obj + end + end + + def read_list(head) + list = [] + loop do + skip_whitespace + c = @io.readchar + if c == ?) + break + else + @io.ungetc(c) + obj = read(!head) + if obj == :"." + error "Consing-dot not implemented" # would need real conses + end + head = false + list << obj + end + end + list + end + + def read_string + string = "" + loop do + c = @io.getc + case c + when ?" + break + when ?\\ + c = @io.getc + case c + when ?\\, ?" then string << c + else raise "Invalid escape char: \\%c" % c + end + else + string << c + end + end + string + end + + def read_quote + [:quote, read] + end + + def read_number_or_symbol + token = read_token + if token.empty? + raise EOFError.new + elsif /^[0-9]+$/.match(token) + token.to_i + elsif /^[0-9]+\.[0-9]+$/.match(token) + token.to_f + else + token.intern + end + end + + def read_token + token = "" + loop do + c = @io.getc + if c.nil? + break + elsif terminating?(c) + @io.ungetc(c) + break + else + token << c + end + end + token + end + + def skip_whitespace + loop do + c = @io.getc + case c + when ?\s, ?\n, ?\t then next + when nil then break + else @io.ungetc(c); break + end + end + end + + def terminating?(char) + " \n\t()\"'".include?(char) + end + +end + + +class StringInputStream + def initialize(string) + @string = string + @pos = 0 + @max = string.length + end + + def pos() @pos end + + def getc + if @pos == @max + nil + else + c = @string[@pos] + @pos += 1 + c + end + end + + def readchar + getc or raise EOFError.new + end + + def ungetc(c) + if @pos > 0 && @string[@pos-1] == c + @pos -= 1 + else + raise "Invalid argument: %c [at %d]" % [c, @pos] + end + end + +end + diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-autodoc-tests.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-autodoc-tests.el new file mode 100644 index 0000000..1f4b199 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-autodoc-tests.el @@ -0,0 +1,199 @@ +(require 'slime-autodoc) +(require 'slime-tests) +(require 'cl-lib) + +(defun slime-autodoc-to-string () + "Retrieve and return autodoc for form at point." + (let ((autodoc (car (slime-eval + `(swank:autodoc + ',(slime-autodoc--parse-context) + :print-right-margin + ,(window-width (minibuffer-window))))))) + (if (eq autodoc :not-available) + :not-available + (slime-autodoc--canonicalize-whitespace autodoc)))) + +(defun slime-check-autodoc-at-point (arglist) + (slime-test-expect (format "Autodoc in `%s' (at %d) is as expected" + (buffer-string) (point)) + arglist + (slime-autodoc-to-string))) + +(defmacro define-autodoc-tests (&rest specs) + `(progn + ,@(cl-loop + for (buffer-sexpr wished-arglist . options) + in specs + for fails-for = (plist-get options :fails-for) + for skip-trailing-test-p = (plist-get options :skip-trailing-test-p) + for i from 1 + when (featurep 'ert) + collect `(define-slime-ert-test ,(intern (format "autodoc-tests-%d" i)) + () + ,(format "Check autodoc works ok for %s" buffer-sexpr) + ,@(if fails-for + `(:expected-result + '(satisfies + (lambda (result) + (ert-test-result-type-p + result + (if (member (slime-lisp-implementation-name) + ',fails-for) + :failed + :passed)))))) + (slime-sync-to-top-level 0.3) + (slime-check-top-level) + (with-temp-buffer + (setq slime-buffer-package "COMMON-LISP-USER") + (lisp-mode) + (insert ,buffer-sexpr) + (search-backward "*HERE*") + (delete-region (match-beginning 0) (match-end 0)) + (should (equal ,wished-arglist + (slime-autodoc-to-string))) + (unless ,skip-trailing-test-p + (insert ")") (backward-char) + (should (equal ,wished-arglist + (slime-autodoc-to-string))))) + (slime-sync-to-top-level 0.3))))) + +(define-autodoc-tests + ;; Test basics + ("(swank::emacs-connected*HERE*" "(emacs-connected)") + ("(swank::emacs-connected *HERE*" "(emacs-connected)") + ("(swank::create-socket*HERE*" + "(create-socket host port &key backlog)") + ("(swank::create-socket *HERE*" + "(create-socket ===> host <=== port &key backlog)") + ("(swank::create-socket foo *HERE*" + "(create-socket host ===> port <=== &key backlog)") + + ;; Test that autodoc differentiates between exported and + ;; unexported symbols. + ("(swank:create-socket*HERE*" :not-available) + + ;; Test if cursor is on non-existing required parameter + ("(swank::create-socket foo bar *HERE*" + "(create-socket host port &key backlog)") + + ;; Test cursor in front of opening parenthesis + ("(swank::with-struct *HERE*(foo. x y) *struct* body1)" + "(with-struct (conc-name &rest names) obj &body body)" + :skip-trailing-test-p t) + + ;; Test variable content display + ("(progn swank::default-server-port*HERE*" + "DEFAULT-SERVER-PORT => 4005") + + ;; Test that "variable content display" is not triggered for + ;; trivial constants. + ("(swank::create-socket t*HERE*" + "(create-socket ===> host <=== port &key backlog)") + ("(swank::create-socket :foo*HERE*" + "(create-socket ===> host <=== port &key backlog)") + + ;; Test with syntactic sugar + ("#'(lambda () (swank::create-socket*HERE*" + "(create-socket host port &key backlog)") + ("`(lambda () ,(swank::create-socket*HERE*" + "(create-socket host port &key backlog)") + ("(remove-if #'(lambda () (swank::create-socket*HERE*" + "(create-socket host port &key backlog)") + ("`(remove-if #'(lambda () ,@(swank::create-socket*HERE*" + "(create-socket host port &key backlog)") + + ;; Test &optional + ("(swank::symbol-status foo *HERE*" + "(symbol-status symbol &optional\ + ===> (package (symbol-package symbol)) <===)" :fails-for ("allegro" "ccl")) + + ;; Test context-sensitive autodoc (DEFMETHOD) + ("(defmethod swank::arglist-dispatch (*HERE*" + "(defmethod arglist-dispatch\ + (===> operator <=== arguments) &body body)") + ("(defmethod swank::arglist-dispatch :before (*HERE*" + "(defmethod arglist-dispatch :before\ + (===> operator <=== arguments) &body body)") + + ;; Test context-sensitive autodoc (APPLY) + ("(apply 'swank::eval-for-emacs*HERE*" + "(apply 'eval-for-emacs &optional form buffer-package id &rest args)") + ("(apply #'swank::eval-for-emacs*HERE*" + "(apply #'eval-for-emacs &optional form buffer-package id &rest args)" :fails-for ("ccl")) + ("(apply 'swank::eval-for-emacs foo *HERE*" + "(apply 'eval-for-emacs &optional form\ + ===> buffer-package <=== id &rest args)") + ("(apply #'swank::eval-for-emacs foo *HERE*" + "(apply #'eval-for-emacs &optional form\ + ===> buffer-package <=== id &rest args)" :fails-for ("ccl")) + + ;; Test context-sensitive autodoc (ERROR, CERROR) + ("(error 'simple-condition*HERE*" + "(error 'simple-condition &rest arguments\ + &key format-arguments format-control)" :fails-for ("ccl")) + ("(cerror \"Foo\" 'simple-condition*HERE*" + "(cerror \"Foo\" 'simple-condition\ + &rest arguments &key format-arguments format-control)" + :fails-for ("allegro" "ccl")) + + ;; Test &KEY and nested arglists + ("(swank::with-retry-restart (:msg *HERE*" + "(with-retry-restart (&key ===> (msg \"Retry.\") <===) &body body)" + :fails-for ("allegro" "ccl")) + ("(swank::with-retry-restart (:msg *HERE*(foo" + "(with-retry-restart (&key ===> (msg \"Retry.\") <===) &body body)" + :skip-trailing-test-p t + :fails-for ("allegro" "ccl")) + ("(swank::start-server \"/tmp/foo\" :dont-close *HERE*" + "(start-server port-file &key (style swank:*communication-style*)\ + ===> (dont-close swank:*dont-close*) <===)" + :fails-for ("allegro" "ccl")) + + ;; Test declarations and type specifiers + ("(declare (string *HERE*" + "(declare (string &rest ===> variables <===))" + :fails-for ("allegro") :fails-for ("ccl")) + ("(declare ((string *HERE*" + "(declare ((string &optional ===> size <===) &rest variables))") + ("(declare (type (string *HERE*" + "(declare (type (string &optional ===> size <===) &rest variables))") + + ;; Test local functions + ("(flet ((foo (x y) (+ x y))) (foo *HERE*" "(foo ===> x <=== y)") + ("(macrolet ((foo (x y) `(+ ,x ,y))) (foo *HERE*" "(foo ===> x <=== y)") + ("(labels ((foo (x y) (+ x y))) (foo *HERE*" "(foo ===> x <=== y)") + ("(labels ((foo (x y) (+ x y)) + (bar (y) (foo *HERE*" + "(foo ===> x <=== y)" :fails-for ("cmucl" "sbcl" "allegro" "ccl"))) + +(def-slime-test autodoc-space + (input-keys expected-message) + "Emulate the inserting something followed by the space key +event and verify that the right thing appears in the echo +area (after a short delay)." + '(("( s w a n k : : o p e r a t o r - a r g l i s t SPC" + "(operator-arglist name package)")) + (when noninteractive + (slime-skip-test "Can't use unread-command-events in batch mode")) + (let* ((keys (eval `(kbd ,input-keys))) + (tag (cons nil nil)) + (timerfun (lambda (tag) (throw tag nil))) + (timer (run-with-timer 0.1 nil timerfun tag))) + (with-temp-buffer + (lisp-mode) + (unwind-protect + (catch tag + (message nil) + (select-window (display-buffer (current-buffer) t)) + (setq unread-command-events (listify-key-sequence keys)) + (accept-process-output) + (recursive-edit)) + (setq unread-command-events nil) + (cancel-timer timer)) + (slime-test-expect "Message after SPC" + expected-message (current-message)) + (accept-process-output nil (* eldoc-idle-delay 2)) + (slime-test-expect "Message after edloc delay" + expected-message (current-message))))) + +(provide 'slime-autodoc-tests) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-c-p-c-tests.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-c-p-c-tests.el new file mode 100644 index 0000000..772cc40 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-c-p-c-tests.el @@ -0,0 +1,140 @@ +(require 'slime-c-p-c) +(require 'slime-tests) + +(def-slime-test completions + (prefix expected-completions) + "Find the completions of a symbol-name prefix." + '(("cl:compile" (("cl:compile" "cl:compile-file" "cl:compile-file-pathname" + "cl:compiled-function" "cl:compiled-function-p" + "cl:compiler-macro" "cl:compiler-macro-function") + "cl:compile")) + ("cl:foobar" nil) + ("swank::compile-file" (("swank::compile-file" + "swank::compile-file-for-emacs" + "swank::compile-file-if-needed" + "swank::compile-file-output" + "swank::compile-file-pathname") + "swank::compile-file")) + ("cl:m-v-l" (("cl:multiple-value-list" "cl:multiple-values-limit") "cl:multiple-value")) + ("common-lisp" (("common-lisp-user:" "common-lisp:") "common-lisp"))) + (let ((completions (slime-completions prefix))) + (slime-test-expect "Completion set" expected-completions completions))) + +(def-slime-test complete-symbol* + (buffer-sexp wished-completion &optional chosen-completion fancy unambiguous) + "Ensure that completions are correctly inserted." + '(("cl:and" "cl:and") + ("(cl:and" "(cl:and") + ("(cl:and)" "(cl:and)") + ("(cl:and)" "(cl:and)" nil nil t) + ;; Fancy completion of a form that accepts arguments should + ;; insert a space after the completed form. + ("(cl:and)" "(cl:and )" nil t) + ;; ...but only for symbols in the funcall position. + ("cl:and" "cl:and" nil t) + ;; Fancy completion of a form without arguments should insert a + ;; closing paren. + ("(cl:get-internal-run-time" "(cl:get-internal-run-time)" nil t) + ;; ...but only for symbols in the funcall position. + ("cl:get-internal-run-time" "cl:get-internal-run-time" nil t) + ("cl:m-v-b" "cl:multiple-value-bind") + ("cl:m-v-l" "cl:multiple-value-list" "cl:multiple-value-list") + ;; Fancy completion is only done for unique completions. This is + ;; not a hard requirement, and might change in the future. This + ;; test is included merely to document the current behavior. + ("(cl:m-v-l)" "(cl:multiple-value-list)" "cl:multiple-value-list" t) + ("cl:mult" "cl:multiple-value-call" "cl:multiple-value-call") + ("cl:multiple-value" "cl:multiple-value-setq" "cl:multiple-value-setq") + ("cl:compile" "cl:compile" "cl:compile") + ("cl:compile" "cl:compile-file" "cl:compile-file") + ("cl:f-o" "cl:force-output" "cl:force-output") + ;; When `slime-c-p-c-unambiguous-prefix-p' is non nil, + ;; `slime-complete-symbol*' will move point back to the + ;; unambiguous portion of the prefix; however, the final result + ;; after choosing a completion candidate should be the same. + ("cl:f-o" "cl:force-output" "cl:force-output" nil t) + ("(cl:f-o)" "(cl:force-output)" "cl:force-output" nil t) + ;; Character completions + ("#\\N" "#\\Newline") + ("#\\R" "#\\Return" "#\\Return") + ("#\\R" "#\\Rubout" "#\\Rubout" nil t) + ;; Keyword completions + ("(cl:find 'x '() :)" "(cl:find 'x '() :START)" ":START") + ("(cl:find 'x '() :S)" "(cl:find 'x '() :START)") + ("(cl:find 'x '() :s)" "(cl:find 'x '() :start)") + ("(cl:find 'x '() :s)" "(cl:find 'x '() :start)" nil t) + ("(cl:find 'x '() :t)" "(cl:find 'x '() :test)" ":test") + ("(cl:find 'x '() :t)" "(cl:find 'x '() :test-not)" ":test-not" nil t)) + (slime-check-top-level) + (save-window-excursion + (with-temp-buffer + (lisp-mode) + (setq slime-buffer-package "SWANK") + (insert buffer-sexp) + (when (eq (char-before) ?\)) + (backward-char)) + (let ((slime-c-p-c-unambiguous-prefix-p unambiguous) + (slime-complete-symbol*-fancy fancy)) + (if (not fancy) + (slime-complete-symbol*) + ;; `slime-complete-symbol*-fancy-bit' may call + ;; `execute-kbd-macro', which ultimately operates on the + ;; buffer associated with the selected window, not + ;; necessarily the current buffer. Call `pop-to-buffer' to + ;; ensure that the current buffer is in the selected window + ;; before calling `slime-complete-symbol*'. Fancy completion + ;; might also kick off a `slime-eval-async' in + ;; `slime-echo-arglist', so ensure the output is consumed + ;; with `slime-sync-to-top-level' before continuing. + (pop-to-buffer (current-buffer)) + (slime-complete-symbol*) + (slime-sync-to-top-level 1))) + (when chosen-completion + (with-selected-window slime-completions-window + (goto-char (point-min)) + (search-forward chosen-completion) + (choose-completion))) + (slime-check-completed-form buffer-sexp wished-completion)))) + +(def-slime-test complete-form + (buffer-sexpr wished-completion &optional skip-trailing-test-p) + "" + '(("(defmethod arglist-dispatch *HERE*" + "(defmethod arglist-dispatch (operator arguments) body...)") + ("(with-struct *HERE*" + "(with-struct (conc-name names...) obj body...)") + ("(with-struct *HERE*" + "(with-struct (conc-name names...) obj body...)") + ("(with-struct (*HERE*" + "(with-struct (conc-name names...)" t) + ("(with-struct (foo. bar baz *HERE*" + "(with-struct (foo. bar baz names...)" t)) + (slime-check-top-level) + (with-temp-buffer + (lisp-mode) + (setq slime-buffer-package "SWANK") + (insert buffer-sexpr) + (search-backward "*HERE*") + (delete-region (match-beginning 0) (match-end 0)) + (slime-complete-form) + (slime-check-completed-form buffer-sexpr wished-completion) + + ;; Now the same but with trailing `)' for paredit users... + (unless skip-trailing-test-p + (erase-buffer) + (insert buffer-sexpr) + (search-backward "*HERE*") + (delete-region (match-beginning 0) (match-end 0)) + (insert ")") (backward-char) + (slime-complete-form) + (slime-check-completed-form (concat buffer-sexpr ")") wished-completion)) + )) + +(defun slime-check-completed-form (buffer-sexpr wished-completion) + (slime-test-expect (format "Completed form for `%s' is as expected" + buffer-sexpr) + wished-completion + (buffer-string) + 'equal)) + +(provide 'slime-c-p-c-tests) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-cl-indent-test.txt b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-cl-indent-test.txt new file mode 100644 index 0000000..71f8744 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-cl-indent-test.txt @@ -0,0 +1,1006 @@ +;;;; -*- mode: lisp -*- +;;;; +;;;; This file is .txt, because it's not meant to be evaluated. +;;;; common-lisp-run-indentation-tests in slime-cl-ident.el +;;;; parses this and runs the specified tests. + +;;; Test: indent-1 + +(defun foo () + t) + +;;; Test: indent-2 +;; +;; lisp-lambda-list-keyword-parameter-alignment: nil +;; lisp-lambda-list-keyword-alignment: nil + +(defun foo (foo &optional opt1 + opt2 + &rest rest) + (list foo opt1 opt2 + rest)) + +;;; Test: indent-3 +;; +;; lisp-lambda-list-keyword-parameter-alignment: t +;; lisp-lambda-list-keyword-alignment: nil + +(defun foo (foo &optional opt1 + opt2 + &rest rest) + (list foo opt1 opt2 + rest)) + +;;; Test: indent-4 +;; +;; lisp-lambda-list-keyword-parameter-alignment: nil +;; lisp-lambda-list-keyword-alignment: t + +(defun foo (foo &optional opt1 + opt2 + &rest rest) + (list foo opt1 opt2 + rest)) + +;;; Test: indent-5 +;; +;; lisp-lambda-list-keyword-parameter-alignment: t +;; lisp-lambda-list-keyword-alignment: t + +(defun foo (foo &optional opt1 + opt2 + &rest rest) + (list foo opt1 opt2 + rest)) + +;;; Test: indent-6 +;; +;; lisp-lambda-list-keyword-parameter-alignment: nil +;; lisp-lambda-list-keyword-alignment: nil + +(defmacro foo ((foo &optional opt1 + opt2 + &rest rest)) + (list foo opt1 opt2 + rest)) + +;;; Test: indent-7 +;; +;; lisp-lambda-list-keyword-parameter-alignment: t +;; lisp-lambda-list-keyword-alignment: nil + +(defmacro foo ((foo &optional opt1 + opt2 + &rest rest)) + (list foo opt1 opt2 + rest)) + +;;; Test: indent-8 +;; +;; lisp-lambda-list-keyword-parameter-alignment: nil +;; lisp-lambda-list-keyword-alignment: t + +(defmacro foo ((foo &optional opt1 + opt2 + &rest rest)) + (list foo opt1 opt2 + rest)) + +;;; Test: indent-9 +;; +;; lisp-lambda-list-keyword-parameter-alignment: t +;; lisp-lambda-list-keyword-alignment: t + +(defmacro foo ((foo &optional opt1 + opt2 + &rest rest)) + (list foo opt1 opt2 + rest)) + +;;; Test: indent-10 + +(let ((x y) + (foo #-foo (no-foo) + #+foo (yes-foo)) + (bar #-bar + (no-bar) + #+bar + (yes-bar))) + (list foo bar + x)) + +;;; Test: indent-11 +;; +;; lisp-loop-indent-subclauses: t + +(loop for i from 0 below 2 + for j from 0 below 2 + when foo + do (fubar) + (bar) + (moo) + and collect cash + into honduras + else do ;; this is the body of the first else + ;; the body is ... + (indented to the above comment) + (ZMACS gets this wrong) + and do this + and do that + and when foo + do the-other + and cry + when this-is-a-short-condition do + (body code of the when) + when here's something I used to botch do (here is a body) + (rest of body indented same) + do + (exdented loop body) + (I'm not sure I like this but it's compatible) + when funny-predicate do ;; Here's a comment + (body filled to comment)) + +;;; Test: indent-12 + +(defun foo (x) + (tagbody + foo + (bar) + baz + (when (losing) + (with-big-loser + (yow) + ((lambda () + foo) + big))) + (flet ((foo (bar baz zap) + (zip)) + (zot () + quux)) + (do () + ((lose) + (foo 1)) + (quux) + foo + (lose)) + (cond ((x) + (win 1 2 + (foo))) + (t + (lose + 3)))))) + +;;; Test: indent-13 + +(if* (eq t nil) + then () + () + elseif (dsf) + thenret x + else (balbkj) + (sdf)) + +;;; Test: indent-14 + +(list foo #+foo (foo) + #-foo (no-foo)) + +;;; Test: indent-15 +;; +;; lisp-loop-indent-subclauses: t + +(loop for x in foo1 + for y in quux1 + ) + +;;; Test: indent-16 +;; +;; lisp-loop-indent-subclauses: nil + +(loop for x in foo1 + for y in quux1 + ) + +;;; Test: indent-17 +;; +;; lisp-loop-indent-subclauses: nil +;; lisp-loop-indent-forms-like-keywords: t + +(loop for x in foo + for y in quux + finally (foo) + (fo) + (zoo) + do + (print x) + (print y) + (print 'ok!)) + +;;; Test: indent-18 +;; +;; lisp-loop-indent-subclauses: nil +;; lisp-loop-indent-forms-like-keywords: nil + +(loop for x in foo + for y in quux + finally (foo) + (fo) + (zoo) + do + (print x) + (print y) + (print 'ok!)) + +;;; Test: indent-19 +;; +;; lisp-loop-indent-subclauses: t +;; lisp-loop-indent-forms-like-keywords: nil + +(loop for x in foo + for y in quux + finally (foo) + (fo) + (zoo) + do + (print x) + (print y) + (print 'ok!)) + +;;; Test: indent-20 +;; +;; lisp-loop-indent-subclauses: nil +;; lisp-loop-indent-forms-like-keywords: nil + +(loop for f in files + collect (open f + :direction :output) + do (foo) (bar) + (quux)) + +;;; Test: indent-21 +;; +;; lisp-loop-indent-subclauses: t + +(loop for f in files + collect (open f + :direction :output) + do (foo) (bar) + (quux)) + +;;; Test: indent-22 + +(defsetf foo bar + "the doc string") + +;;; Test: indent-23 + +(defsetf foo + bar + "the doc string") + +;;; Test: indent-24 +;; +;; lisp-lambda-list-keyword-parameter-alignment: t + +(defsetf foo (x y &optional a + z) + (a b c) + stuff) + +;;; Test: indent-25 +;; +;; lisp-align-keywords-in-calls: t + +(make-instance 'foo :bar t :quux t + :zot t) + +;;; Test: indent-26 +;; +;; lisp-align-keywords-in-calls: nil + +(make-instance 'foo :bar t :quux t + :zot t) + +;;; Test: indent-27 +;; +;; lisp-lambda-list-indentation: nil + +(defun example (a b &optional o1 o2 + o3 o4 + &rest r + &key k1 k2 + k3 k4) + 'hello) + +;;; Test: indent-28 +;; +;; lisp-lambda-list-keyword-parameter-alignment: t +;; lisp-lambda-list-keyword-alignment: t + +(destructuring-bind (foo &optional x + y + &key bar + quux) + foo + body) + +;;; Test: indent-29 +;; +;; lisp-lambda-list-keyword-parameter-alignment: t +;; lisp-lambda-list-keyword-alignment: t + +(named-lambda foo + (x &optional y + z + &rest more) + body) + +;;; Test: indent-30 + +(foo fii + (or x + y) t + bar) + +;;; Test: indent-31 + +(foo + (bar)) + +;;; Test: indent-32 +;; +;; comment-indent-function: (lambda () nil) +;; comment-column: nil + +(unknown (;; KLUDGE: comment-indent hackery to get + ;; the comment right. Otherwise we get a + ;; space before the first ;. + bar quux + zot) + (#|fii|# + zot) + ( + quux)) + +;;; Test: indent-33 + +(complex-indent.1 ((x z + f + ((fox foo + foo)) + :note (ding bar quux + zot) + :wait (this! is + a funcall)) + ;; Not 100% sure this should not be a step left. + (abbb) + (abb)) + (bodyform) + (another)) + +;;; Test: indent-34 + +(complex-indent.2 (bar quux + zot) + (a b + c d) + (form1) + (form2)) + +;;; Test: indent-35 + +(complex-indent.3 (:wait fii + (this is + a funcall)) + (bodyform) + (another)) + +;;; Test: indent-36 + +(defmacro foo (body) + `(let (,@(stuff) + ,(more-stuff) + ,(even-more) + (foo foo)) + ,@bofy)) + +;;; Test: indent-37 + +(defun foo () + `(list foo bar + ,@(quux fo + foo))) + +;;; Test: indent-38 + +(defmacro foofoo (body) + `(foo + `(let (,',@,(stuff) + ,(more-stuff) + ,(even-more) + (foo foo)) + ,@bofy))) + +;;; Test: indent-39 +;; +;; lisp-lambda-list-keyword-parameter-alignment: t +;; lisp-lambda-list-keyword-alignment: t + +(defstruct (foo (:constructor make-foo (&optional bar + quux + &key zot + fii))) + bar + quux + zot + fii) + +;;; Test: indent-40 +;; +;; lisp-lambda-list-keyword-parameter-alignment: t +;; lisp-lambda-list-keyword-alignment: t + +(defmethod foo :around (zot &key x + y) + (list zot)) + +;;; Test: indent-41 +;; +;; lisp-lambda-list-keyword-parameter-alignment: t +;; lisp-lambda-list-keyword-alignment: t + +(progn + (defmethod foo :around (fii &key x + y) + (list fii))) + +;;; Test: indent-42 +;; +;; lisp-lambda-list-keyword-parameter-alignment: t +;; lisp-lambda-list-keyword-alignment: t + +(progn + (defgeneric foo (x y &optional a + b) + (:method :around (a b &optional x + y) + (list a b x y)))) + +;;; Test: indent-43 +;; +;; lisp-lambda-list-keyword-parameter-alignment: t +;; lisp-lambda-list-keyword-alignment: t + +(defgeneric foo (x &optional a b) + (:method (x y &optional a + b) + (list x y a b))) + +;;; Test: indent-44 + +(let (definer + foo + bar + quux) + ...) + +;;; Test: indent-45 + +(let (definition + foo + bar + quux) + ...) + +;;; Test: indent-46 + +(let (foo bar + quux) + ...) + +;;; Test: indent-47 + +(with-compilation-unit + (:foo t + :quux nil) + ...) + +;;; Test: indent-48 + +(cond + ((> x y) (foo) + ;; This isn't ideal -- I at least would align with (FOO here. + (bar) (quux) + (zot)) + (qux (foo) + (bar) + (zot)) + (zot + (foo) + (foo2)) + (t (foo) + (bar))) + +;;; Test: indent-49 + +(cond ((> x y) (foo) + ;; This isn't ideal -- I at least would align with (FOO here. + (bar)) + (qux (foo) + (bar)) + (zot + (foo)) + (t (foo) + (bar))) + +;;; Test: indent-50 +;; +;; lisp-lambda-list-keyword-parameter-alignment: nil +;; lisp-lambda-list-keyword-alignment: nil + +(defun foo (x &optional opt1 + opt2 + &rest rest + &allow-other-keys) + (list opt1 opt2 + rest)) + +;;; Test: indent-51 +;; +;; lisp-lambda-list-keyword-parameter-alignment: t +;; lisp-lambda-list-keyword-alignment: nil + +(defun foo (x &optional opt1 + opt2 + &rest rest + &allow-other-keys) + (list opt1 opt2 + rest)) + +;;; Test: indent-52 +;; +;; lisp-lambda-list-keyword-parameter-alignment: nil +;; lisp-lambda-list-keyword-alignment: t + +(defun foo (x &optional opt1 + opt2 + &rest rest + &allow-other-keys) + (list opt1 opt2 + rest)) + +;;; Test: indent-53 +;; +;; lisp-lambda-list-keyword-parameter-alignment: t +;; lisp-lambda-list-keyword-alignment: t + +(defun foo (x &optional opt1 + opt2 + &rest rest + &allow-other-keys) + (list opt1 opt2 + rest)) + +;;; Test: indent-54 +;; + +(loop (foo) + ;; comment + (bar) + (quux)) + +;;; Test: indent-55 +;; + +(loop ;; comment + (foo) + (bar)) + +;;; Test: indent-56 +;; + +(loop + (foo) + ;; comment + (bar)) + + +;;; Test: indent-57 +;; + +(loop + ;; comment + (foo) + (bar)) + +;;; Test: indent-58 +;; +;; lisp-loop-indent-subclauses: t + +(loop ;; comment at toplevel of the loop + with foo = t + do (foo foo) + (foo)) + +;;; Test: indent-59 +;; +;; lisp-loop-indent-subclauses: nil + +(loop ;; comment at toplevel of the loop + with foo = t + do (foo foo) + (foo)) + +;;; Test: indent-60 +;; +;; lisp-loop-indent-subclauses: t + +(loop + ;; comment at toplevel of the loop + with foo = t + do (foo foo)) + +;;; Test: indent-61 +;; +;; lisp-loop-indent-subclauses: nil + +(loop + ;; comment at toplevel of the loop + with foo = t + do (foo foo) + (foo)) + +;;; Test: indent-62 +;; +;; lisp-loop-indent-subclauses: t + +(loop with foo = t + do (foo foo) + ;; comment inside clause + (bar)) + +;;; Test: indent-63 +;; +;; lisp-loop-indent-subclauses: nil + +(loop with foo = t + do (foo foo) + ;; comment inside clause + (bar)) + + +;;; Test: indent-64 +;; +;; lisp-lambda-list-keyword-parameter-alignment: t +;; lisp-lambda-list-keyword-alignment: t + +(defmethod (setf foo) :around (zot &key x + y) + (list zot)) + +;;; Test: indent-65 +;; +;; lisp-lambda-list-keyword-parameter-alignment: t +;; lisp-lambda-list-keyword-alignment: t + +(defmethod (setf foo) + :around (zot &key x y) + (list zot)) + +;;; Test: indent-66 +;; + +(define-condition + foo + (bar quux + zot) + () + (:report "foo")) + +;;; Test: indent-67 +;; + +(defclass + foo + (bar quxx + xoo) + () + (:metaclass foo-class)) + + +;;; Test: indent-68 +;; +;; lisp-loop-indent-subclauses: nil + +(progn + (loop + repeat 1000 + do ;; This is the + ;; beginning + (foo)) + (loop repeat 100 ;; This too + ;; is a beginning + do (foo))) + +;;; Test: indent-69 +;; +;; lisp-loop-indent-subclauses: t + +(progn + (loop + repeat 1000 + do ;; This is the + ;; beginning + (foo)) + (loop repeat 100 ;; This too + ;; is a beginning + do (foo))) + +;;; Test: indent-70 +;; +;; lisp-loop-indent-subclauses: nil + +(progn + (loop + :repeat 1000 + #:do ;; This is the + ;; beginning + (foo)) + (loop #:repeat 100 ;; This too + ;; is a beginning + :do (foo))) + +;;; Test: indent-71 +;; +;; lisp-loop-indent-subclauses: t + +(progn + (loop + #:repeat 1000 + #:do ;; This is the + ;; beginning + (foo)) + (loop :repeat 100 ;; This too + ;; is a beginning + #:do (foo))) + +;;; Test: indent-72 +;; +;; lisp-lambda-list-keyword-parameter-alignment: nil +;; lisp-lambda-list-keyword-alignment: nil + +(flet ((foo (foo &optional opt1 + opt2 + &rest rest) + (list foo opt1 opt2 + rest))) + ...) + +;;; Test: indent-73 +;; +;; lisp-lambda-list-keyword-parameter-alignment: t +;; lisp-lambda-list-keyword-alignment: nil + +(flet ((foo (foo &optional opt1 + opt2 + &rest rest) + (list foo opt1 opt2 + rest))) + ...) + +;;; Test: indent-74 +;; +;; lisp-lambda-list-keyword-parameter-alignment: nil +;; lisp-lambda-list-keyword-alignment: t + +(flet ((foo (foo &optional opt1 + opt2 + &rest rest) + (list foo opt1 opt2 + rest))) + ...) + +;;; Test: indent-75 +;; +;; lisp-lambda-list-keyword-parameter-alignment: t +;; lisp-lambda-list-keyword-alignment: t + +(flet ((foo (foo &optional opt1 + opt2 + &rest rest) + (list foo opt1 opt2 + rest))) + ...) + +;;; Test: indent-76 +;; +;; lisp-lambda-list-keyword-parameter-alignment: t +;; lisp-lambda-list-keyword-alignment: t + +(macrolet ((foo + (foo (&optional xopt1 + xopt2 + &rest xrest) + &optional opt1 + opt2 + &rest rest) + (list foo opt1 opt2 + rest))) + ...) + +;;; Test: indent-77 +;; +;; lisp-align-keywords-in-calls: t + +(foo *foo* + :bar t + :quux #+quux t + #-quux nil + :zot t) + +;;; Test: indent-78 +;; +;; lisp-align-keywords-in-calls: t + +(foo *foo* :fii t + :bar t + :quux #+quux t + #+zot nil + :zot t) + +;;; Test: indent-79 + +(foo #+quux :quux #+quux t + #-quux :zoo #-quux t) + +;;; Test: indent-80 +;; +;; lisp-align-keywords-in-calls: t + +(foo *foo* :fii t + :bar t + #+quux :quux #+quux t + :zot t) + +;;; Test: indent-81 +;; +;; lisp-align-keywords-in-calls: t + +(foo *foo* :fii t + :bar t + #+quux #+quux :quux t + :zot t) + +;;; Test: indent-82 +;; +;; lisp-align-keywords-in-calls: t + +(foo *foo* :fii t + :bar t + #+quux + :quux #+quux t + :zot t) + +;;; Test: indent-83 +;; +;; lisp-align-keywords-in-calls: t + +(foo *foo* :fii t + :bar t + #+quux #+quux + :quux t + :zot t) + +;;; Test: indent-84 + +(and ;; Foo + (something) + ;; Quux + (more)) + +;;; Test: indent-85 + +(and ;; Foo + (something) + ;; Quux + (more)) + +;;; Test: indent-86 + +(foo ( + bar quux + zor)) + +;;; Test: indent-87 +;; +;; lisp-lambda-list-keyword-parameter-alignment: t +;; lisp-lambda-list-keyword-alignment: t + +(defmacro foo ((foo &optional (opt1 (or (this) + (that))) + (opt2 (the-default) + opt2-p) + (opt3 + (the-default (foo) + (bar))) + &rest rest)) + (list foo opt1 opt2 + rest)) + +;;; Test: indent-88 + +(defstruct (foo + (:constructor make-foo + (bar &aux (quux (quux-from-bar bar + :for 'foo))))) + bar + quux) + +;;; Test: indent-89 + +(define-tentative-thing foo + (bar) + quux) + +;;; Test: indent-90 + +(define-tentative-thing foo + bar + quux) + +;;; Test: indent-91 +;; +;; lisp-loop-indent-body-forms-relative-to-loop-start: t + +(loop for foo in bar + do + (progn foo + bar + baz)) + +;;; Test: indent-92 +;; +;; lisp-loop-indent-body-forms-relative-to-loop-start: t +;; lisp-loop-clauses-indentation: 4 + +(loop + for foo in bar + do + (progn foo + bar + baz)) + +;;; Test: indent-93 +;; +;; lisp-loop-clauses-indentation: 4 + +(loop + for foo in bar + doing + (progn foo + bar + baz)) + +;;; Test: indent-94 +;; +;; lisp-loop-clauses-indentation: 4 +;; lisp-loop-body-forms-indentation: 1 + +(loop + for foo in bar + doing + (list foo + bar + baz)) + +;;; Test: indent-95 +;; +;; lisp-loop-body-forms-indentation: 1 +;; lisp-loop-indent-body-forms-relative-to-loop-start: t + +(loop + for foo in bar + do + (list foo + bar + baz)) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-enclosing-context-tests.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-enclosing-context-tests.el new file mode 100644 index 0000000..41f50a7 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-enclosing-context-tests.el @@ -0,0 +1,46 @@ +(require 'slime-enclosing-context) +(require 'slime-tests) +(require 'cl-lib) + +(def-slime-test enclosing-context.1 + (buffer-sexpr wished-bound-names wished-bound-functions) + "Check that finding local definitions work." + '(("(flet ((,nil ())) + (let ((bar 13) + (,foo 42)) + *HERE*))" + ;; We used to return ,foo here, but we do not anymore. We + ;; still return ,nil for the `slime-enclosing-bound-functions', + ;; though. The first one is used for local M-., whereas the + ;; latter is used for local autodoc. It does not seem too + ;; important for local M-. to work on such names. \(The reason + ;; that it does not work anymore, is that + ;; `slime-symbol-at-point' now does TRT and does not return a + ;; leading comma anymore.\) + ("bar" nil nil) + ((",nil" "()"))) + ("(flet ((foo ())) + (quux) + (bar *HERE*))" + ("foo") + (("foo" "()")))) + (slime-check-top-level) + (with-temp-buffer + (let ((tmpbuf (current-buffer))) + (lisp-mode) + (insert buffer-sexpr) + (search-backward "*HERE*") + (cl-multiple-value-bind (bound-names points) + (slime-enclosing-bound-names) + (slime-check "Check enclosing bound names" + (cl-loop for name in wished-bound-names + always (member name bound-names)))) + (cl-multiple-value-bind (fn-names fn-arglists points) + (slime-enclosing-bound-functions) + (slime-check "Check enclosing bound functions" + (cl-loop for (name arglist) in wished-bound-functions + always (and (member name fn-names) + (member arglist fn-arglists))))) + ))) + +(provide 'slime-enclosing-context-tests) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-fontifying-fu-tests.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-fontifying-fu-tests.el new file mode 100644 index 0000000..9bc99af --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-fontifying-fu-tests.el @@ -0,0 +1,120 @@ +(require 'slime-fontifying-fu) +(require 'slime-tests) + +(def-slime-test font-lock-magic (buffer-content) + "Some testing for the font-lock-magic. *YES* should be + highlighted as a suppressed form, *NO* should not." + + '(("(defun *NO* (x y) (+ x y))") + ("(defun *NO*") + ("*NO*) #-(and) (*YES*) (*NO* *NO*") + ("\( +\(defun *NO*") + ("\) +\(defun *NO* + \( +\)") + ("#+#.foo +\(defun *NO* (x y) (+ x y))") + ("#+#.foo +\(defun *NO* (x ") + ("#+( +\(defun *NO* (x ") + ("#+(test) +\(defun *NO* (x ") + + ("(eval-when (...) +\(defun *NO* (x ") + + ("(eval-when (...) +#+(and) +\(defun *NO* (x ") + + ("#-(and) (defun *YES* (x y) (+ x y))") + (" +#-(and) (defun *YES* (x y) (+ x y)) +#+(and) (defun *NO* (x y) (+ x y))") + + ("#+(and) (defun *NO* (x y) #-(and) (+ *YES* y))") + ("#| #+(or) |# *NO*") + ("#| #+(or) x |# *NO*") + ("*NO* \"#| *NO* #+(or) x |# *NO*\" *NO*") + ("#+#.foo (defun foo (bar)) +#-(and) *YES* *NO* bar +") + ("#+(foo) (defun foo (bar)) +#-(and) *YES* *NO* bar") + ("#| #+(or) |# *NO* foo +#-(and) *YES* *NO*") + ("#- (and) +\(*YES*) +\(*NO*) +#-(and) +\(*YES*) +\(*NO*)") + ("#+nil (foo) + +#-(and) +#+nil ( + asdf *YES* a + fsdfad) + +\( asdf *YES* + + ) +\(*NO*) + +") + ("*NO* + +#-(and) \(progn + #-(and) + (defun *YES* ...) + + #+(and) + (defun *YES* ...) + + (defun *YES* ...) + + *YES* + + *YES* + + *YES* + + *YES* +\) + +*NO*") + ("#-(not) *YES* *NO* + +*NO* + +#+(not) *NO* *NO* + +*NO* + +#+(not a b c) *NO* *NO* + +*NO*")) + (slime-check-top-level) + (with-temp-buffer + (insert buffer-content) + (slime-initialize-lisp-buffer-for-test-suite + :autodoc t :font-lock-magic t) + ;; Can't use `font-lock-fontify-buffer' because for the case when + ;; `jit-lock-mode' is enabled. Jit-lock-mode fontifies only on + ;; actual display. + (font-lock-default-fontify-buffer) + (when (search-backward "*NO*" nil t) + (slime-test-expect "Not suppressed by reader conditional?" + 'slime-reader-conditional-face + (get-text-property (point) 'face) + #'(lambda (x y) (not (eq x y))))) + (goto-char (point-max)) + (when (search-backward "*YES*" nil t) + (slime-test-expect "Suppressed by reader conditional?" + 'slime-reader-conditional-face + (get-text-property (point) 'face))))) + +(provide 'slime-fontifying-fu-tests) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-indentation-tests.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-indentation-tests.el new file mode 100644 index 0000000..ad1e2c5 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-indentation-tests.el @@ -0,0 +1,81 @@ +(require 'slime-indentation) +(require 'slime-tests) + +(define-common-lisp-style "common-lisp-indent-test" + ;; Used to specify a few complex indentation specs for testing. + (:inherit "basic") + (:indentation + (complex-indent.1 ((&whole 4 (&whole 1 1 1 1 (&whole 1 1) &rest 1) + &body) &body)) + (complex-indent.2 (4 (&whole 4 &rest 1) &body)) + (complex-indent.3 (4 &body)))) + +(defun slime-indentation-mess-up-indentation () + (while (not (eobp)) + (forward-line 1) + (unless (looking-at "^$") + (cl-case (random 2) + (0 + ;; Delete all leading whitespace -- except for + ;; comment lines. + (while (and (looking-at " ") (not (looking-at " ;"))) + (delete-char 1))) + (1 + ;; Insert whitespace random. + (let ((n (1+ (random 24)))) + (while (> n 0) (cl-decf n) (insert " "))))))) + (buffer-string)) + +(eval-and-compile + (defun slime-indentation-test-form (test-name bindings expected) + `(define-slime-ert-test ,test-name () + ,(format "An indentation test named `%s'" test-name) + (with-temp-buffer + (lisp-mode) + (setq indent-tabs-mode nil) + (common-lisp-set-style "common-lisp-indent-test") + (let ,(cons `(expected ,expected) bindings) + (insert expected) + (goto-char (point-min)) + (let ((mess (slime-indentation-mess-up-indentation))) + (when (string= mess expected) + (ert-fail "Could not mess up indentation?")) + (indent-region (point-min) (point-max)) + (delete-trailing-whitespace) + (should (equal expected (buffer-string)))))))) + + (defun slime-indentation-test-forms-for-file (file) + (with-current-buffer + (find-file-noselect (concat slime-path + "/contrib/test/slime-cl-indent-test.txt")) + (goto-char (point-min)) + (cl-loop + while (re-search-forward ";;; Test:[\t\n\s]*\\(.*\\)[\t\n\s]" nil t) + for test-name = (intern (match-string-no-properties 1)) + for bindings = + (save-restriction + (narrow-to-region (point) + (progn (forward-comment + (point-max)) + (point))) + (save-excursion + (goto-char (point-min)) + (cl-loop while + (re-search-forward + "\\([^\s]*\\)[\t\n\s]*:[\t\n\s]*\\(.*\\)[\t\n\s]" nil t) + collect (list + (intern (match-string-no-properties 1)) + (car + (read-from-string (match-string-no-properties 2))))))) + for expected = (buffer-substring-no-properties (point) + (scan-sexps (point) + 1)) + collect (slime-indentation-test-form test-name bindings expected))))) + +(defmacro slime-indentation-define-tests () + `(progn + ,@(slime-indentation-test-forms-for-file "slime-cl-indent-test.txt"))) + +(slime-indentation-define-tests) + +(provide 'slime-indentation-tests) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-macrostep-tests.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-macrostep-tests.el new file mode 100644 index 0000000..3ceadd8 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-macrostep-tests.el @@ -0,0 +1,287 @@ +;; Tests for slime-macrostep. The following are expected failures: + +;; - Under CLISP, highlighting of macro sub-forms fails because our +;; pretty-printer dispatch table hacking causes infinite recursion: +;; see comment in swank-macrostep.lisp + +;; - COLLECT-MACRO-FORMS does not catch compiler macros under CLISP +;; and ABCL + +;; - Under CCL and ECL, compiler macro calls returned by +;; COLLECT-MACRO-FORMS are not EQ to the original form, and so are +;; not detected by the tracking pretty-printer mechanism. This +;; could be fixed by adding :TEST #'EQUAL to the POSITION call +;; within MAKE-TRACKING-PPRINT-DISPATCH, at the cost of introducing +;; false positives. + +;; ECL has two other issues: + +;; - it currently lacks a working SLIME defimplementation for +;; MACROEXPAND-ALL (Github issue #157), without which none of the +;; expand-in-context stuff works. + +;; - the environments consed up by its WALKER:MACROEXPAND-ALL +;; function are slightly broken, and do not work when passed to +;; MACROEXPAND-1 unless fixed up via + +;; (subst 'si::macro 'walker::macro env) + +(require 'slime-macrostep) +(require 'slime-tests) +(require 'cl-lib) + +(defun slime-macrostep-eval-definitions (definitions) + (slime-check-top-level) + (slime-compile-string definitions 0) + (slime-sync-to-top-level 5)) + +(defmacro slime-macrostep-with-text (buffer-text &rest body) + (declare (indent 1)) + `(with-temp-buffer + (lisp-mode) + (save-excursion + (insert ,buffer-text)) + ,@body)) + +(defun slime-macrostep-search (form) + "Search forward for FORM, leaving point at its first character." + (let ((case-fold-search t) + (search-spaces-regexp "\\s-+")) + (re-search-forward (regexp-quote form))) + (goto-char (match-beginning 0))) + + + +(def-slime-test (slime-macrostep-expand-defmacro) + (definition buffer-text original expansion) + "Test that simple macrostep expansion works." + '(("(defmacro macrostep-dummy-macro (&rest args) + `(expansion of ,@args))" + + "(progn + (first body form) + (second body form) + (macrostep-dummy-macro (first (argument)) second (third argument)) + (remaining body forms))" + + "(macrostep-dummy-macro (first (argument)) second (third argument))" + + "(expansion of (first (argument)) second (third argument))")) + (slime-macrostep-eval-definitions definition) + (slime-macrostep-with-text buffer-text + (slime-macrostep-search original) + (macrostep-expand) + (slime-test-expect "Macroexpansion is correct" + expansion + (downcase (slime-sexp-at-point)) + #'slime-test-macroexpansion=))) + +(def-slime-test (slime-macrostep-fontify-macros + (:fails-for "clisp" "ECL")) + (definition buffer-text original subform) + "Test that macro forms in expansions are font-locked" + '(("(defmacro macrostep-dummy-1 (&rest args) + `(expansion including (macrostep-dummy-2 ,@args))) + (defmacro macrostep-dummy-2 (&rest args) + `(final expansion of ,@args))" + + "(progn + (first body form) + (second body form) + (macrostep-dummy-1 (first (argument)) second (third argument)) + (remaining body forms))" + + "(macrostep-dummy-1 (first (argument)) second (third argument))" + + "(macrostep-dummy-2 (first (argument)) second (third argument))")) + (slime-macrostep-eval-definitions definition) + (slime-macrostep-with-text buffer-text + (slime-macrostep-search original) + (macrostep-expand) + (slime-macrostep-search subform) + (forward-char) ; move over open paren + (slime-check "Head of macro form in expansion is fontified correctly" + (eq (get-char-property (point) 'font-lock-face) + 'macrostep-macro-face)))) + +(def-slime-test (slime-macrostep-fontify-compiler-macros + (:fails-for "armedbear" "clisp" "ccl" "ECL")) + (definition buffer-text original subform) + "Test that compiler-macro forms in expansions are font-locked" + '(("(defmacro macrostep-dummy-3 (&rest args) + `(expansion including (macrostep-dummy-4 ,@args))) + (defun macrostep-dummy-4 (&rest args) + args) + (define-compiler-macro macrostep-dummy-4 (&rest args) + `(compile-time expansion of ,@args))" + + "(progn + (first body form) + (second body form) + (macrostep-dummy-3 first second third) + (remaining body forms))" + + "(macrostep-dummy-3 first second third)" + + "(macrostep-dummy-4 first second third)")) + (slime-macrostep-eval-definitions definition) + (slime-macrostep-with-text buffer-text + (slime-macrostep-search original) + (let ((macrostep-expand-compiler-macros t)) + (macrostep-expand)) + (slime-macrostep-search subform) + (forward-char) ; move over open paren + (slime-check "Head of compiler-macro in expansion is fontified correctly" + (eq (get-char-property (point) 'font-lock-face) + 'macrostep-compiler-macro-face)))) + +(def-slime-test (slime-macrostep-expand-macrolet + (:fails-for "ECL")) + (definitions buffer-text expansions) + "Test that calls to macrolet-defined macros are expanded." + '((nil + "(macrolet + ((test (&rest args) `(expansion of ,@args))) + (first body form) + (second body form) + (test (strawberry pie) and (apple pie)) + (final body form))" + (("(test (strawberry pie) and (apple pie))" + "(EXPANSION OF (STRAWBERRY PIE) AND (APPLE PIE))"))) + + ;; From swank.lisp: + (nil + "(macrolet ((define-xref-action (xref-type handler) + `(defmethod xref-doit ((type (eql ,xref-type)) thing) + (declare (ignorable type)) + (funcall ,handler thing)))) + (define-xref-action :calls #'who-calls) + (define-xref-action :calls-who #'calls-who) + (define-xref-action :references #'who-references) + (define-xref-action :binds #'who-binds) + (define-xref-action :macroexpands #'who-macroexpands) + (define-xref-action :specializes #'who-specializes) + (define-xref-action :callers #'list-callers) + (define-xref-action :callees #'list-callees))" + (("(define-xref-action :calls #'who-calls)" + "(DEFMETHOD XREF-DOIT ((TYPE (EQL :CALLS)) THING) + (DECLARE (IGNORABLE TYPE)) + (FUNCALL #'WHO-CALLS THING))") + ("(define-xref-action :macroexpands #'who-macroexpands)" + "(DEFMETHOD XREF-DOIT ((TYPE (EQL :MACROEXPANDS)) THING) + (DECLARE (IGNORABLE TYPE)) + (FUNCALL #'WHO-MACROEXPANDS THING))") + ("(define-xref-action :callees #'list-callees)" + "(DEFMETHOD XREF-DOIT ((TYPE (EQL :CALLEES)) THING) + (DECLARE (IGNORABLE TYPE)) + (FUNCALL #'LIST-CALLEES THING))"))) + + ;; Test expansion of shadowed definitions + (nil + "(macrolet + ((test-macro (&rest forms) (cons 'outer-definition forms))) + (test-macro first (call)) + (macrolet + ((test-macro (&rest forms) (cons 'inner-definition forms))) + (test-macro (second (call)))))" + (("(test-macro first (call))" + "(OUTER-DEFINITION FIRST (CALL))") + ("(test-macro (second (call)))" + "(INNER-DEFINITION (SECOND (CALL)))"))) + + ;; Expansion of macro-defined local macros + ("(defmacro with-local-dummy-macro (&rest body) + `(macrolet ((dummy (&rest args) `(expansion (of) ,@args))) + ,@body))" + "(with-local-dummy-macro + (dummy form (one)) + (dummy (form two)))" + (("(dummy form (one))" + "(EXPANSION (OF) FORM (ONE))") + ("(dummy (form two))" + "(EXPANSION (OF) (FORM TWO))")))) + + (when definitions + (slime-macrostep-eval-definitions definitions)) + (slime-macrostep-with-text buffer-text + ;; slime-test-macroexpansion= does not expect tab characters, + ;; so make sure that Emacs does not insert them + (let ((indent-tabs-mode nil)) + (cl-loop + for (original expansion) in expansions + do + (goto-char (point-min)) + (slime-macrostep-search original) + (macrostep-expand) + (slime-test-expect "Macroexpansion is correct" + expansion + (slime-sexp-at-point) + #'slime-test-macroexpansion=))))) + +(def-slime-test (slime-macrostep-fontify-local-macros + (:fails-for "clisp" "ECL")) + () + "Test that locally-bound macros are highlighted in expansions." + '(()) + (slime-macrostep-with-text + "(macrolet ((frob (&rest args) + (if (zerop (length args)) + nil + `(cons ,(car args) (frob ,@(cdr args)))))) + (frob 1 2 3 4 5))" + (let ((expansions + '(("(frob 1 2 3 4 5)" + "(CONS 1 (FROB 2 3 4 5))" + "(FROB 2 3 4 5)") + ("(FROB 2 3 4 5)" + "(CONS 2 (FROB 3 4 5))" + "(FROB 3 4 5)") + ("(FROB 3 4 5)" + "(CONS 3 (FROB 4 5))" + "(FROB 4 5)") + ("(FROB 4 5)" + "(CONS 4 (FROB 5))" + "(FROB 5)") + ("(FROB 5)" + "(CONS 5 (FROB))" + "(FROB)") + ;; ("(FROB)" + ;; "NIL" + ;; nil) + ))) + (cl-loop for (original expansion subform) in expansions + do + (goto-char (point-min)) + (slime-macrostep-search original) + (macrostep-expand) + (slime-test-expect "Macroexpansion is correct" + expansion + (slime-sexp-at-point) + #'slime-test-macroexpansion=) + (when subform + (slime-macrostep-search subform) + (forward-char) + (slime-check "Head of macro form in expansion is fontified correctly" + (eq (get-char-property (point) 'font-lock-face) + 'macrostep-macro-face))))))) + +(def-slime-test (slime-macrostep-handle-unreadable-objects) + (definitions buffer-text subform expansion) + "Check that macroexpansion succeeds in a context containing unreadable objects." + '(("(defmacro macrostep-dummy-5 (&rest args) + `(expansion of ,@args))" + "(progn + # + (macrostep-dummy-5 quux frob))" + "(macrostep-dummy-5 quux frob)" + "(EXPANSION OF QUUX FROB)")) + (slime-macrostep-eval-definitions definitions) + (slime-macrostep-with-text buffer-text + (slime-macrostep-search subform) + (macrostep-expand) + (slime-test-expect "Macroexpansion is correct" + expansion + (slime-sexp-at-point) + #'slime-test-macroexpansion=))) + +(provide 'slime-macrostep-tests) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-mdot-fu-tests.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-mdot-fu-tests.el new file mode 100644 index 0000000..cf27b29 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-mdot-fu-tests.el @@ -0,0 +1,43 @@ +(require 'slime-mdot-fu) +(require 'slime-tests) + +(def-slime-test find-local-definitions.1 + (buffer-sexpr definition target-regexp) + "Check that finding local definitions work." + '(((defun foo (x) + (let ((y (+ x 1))) + (- x y *HERE*))) + y + "(y (+ x 1))") + + ((defun bar (x) + (flet ((foo (z) (+ x z))) + (* x (foo *HERE*)))) + foo + "(foo (z) (+ x z))") + + ((defun quux (x) + (flet ((foo (z) (+ x z))) + (let ((foo (- 1 x))) + (+ x foo *HERE*)))) + foo + "(foo (- 1 x)") + + ((defun zurp (x) + (macrolet ((frob (x y) `(quux ,x ,y))) + (frob x *HERE*))) + frob + "(frob (x y)")) + (slime-check-top-level) + (with-temp-buffer + (let ((tmpbuf (current-buffer))) + (insert (prin1-to-string buffer-sexpr)) + (search-backward "*HERE*") + (slime-edit-local-definition (prin1-to-string definition)) + (slime-sync) + (slime-check "Check that we didnt leave the temp buffer." + (eq (current-buffer) tmpbuf)) + (slime-check "Check that we are at the local definition." + (looking-at (regexp-quote target-regexp)))))) + +(provide 'slime-mdot-fu-tests) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-parse-tests.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-parse-tests.el new file mode 100644 index 0000000..0b0ec7d --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-parse-tests.el @@ -0,0 +1,63 @@ +(require 'slime-parse) +(require 'slime-tests) + +(defun slime-check-buffer-form (result-form) + (slime-test-expect + (format "Buffer form correct in `%s' (at %d)" (buffer-string) (point)) + result-form + (slime-parse-form-upto-point 10))) + +(def-slime-test form-up-to-point.1 + (buffer-sexpr result-form &optional skip-trailing-test-p) + "" + `(("(char= #\\(*HERE*" + ("char=" "#\\(" ,slime-cursor-marker)) + ("(char= #\\( *HERE*" + ("char=" "#\\(" "" ,slime-cursor-marker)) + ("(char= #\\) *HERE*" + ("char=" "#\\)" "" ,slime-cursor-marker)) + ("(char= #\\*HERE*" + ("char=" "#\\" ,slime-cursor-marker) t) + ("(defun*HERE*" + ("defun" ,slime-cursor-marker)) + ("(defun foo*HERE*" + ("defun" "foo" ,slime-cursor-marker)) + ("(defun foo (x y)*HERE*" + ("defun" "foo" + ("x" "y") ,slime-cursor-marker)) + ("(defun foo (x y*HERE*" + ("defun" "foo" + ("x" "y" ,slime-cursor-marker))) + ("(apply 'foo*HERE*" + ("apply" "'foo" ,slime-cursor-marker)) + ("(apply #'foo*HERE*" + ("apply" "#'foo" ,slime-cursor-marker)) + ("(declare ((vector bit *HERE*" + ("declare" (("vector" "bit" "" ,slime-cursor-marker)))) + ("(with-open-file (*HERE*" + ("with-open-file" ("" ,slime-cursor-marker))) + ("(((*HERE*" + ((("" ,slime-cursor-marker)))) + ("(defun #| foo #| *HERE*" + ("defun" "" ,slime-cursor-marker)) + ("(defun #-(and) (bar) f*HERE*" + ("defun" "f" ,slime-cursor-marker)) + ("(remove-if #'(lambda (x)*HERE*" + ("remove-if" ("lambda" ("x") ,slime-cursor-marker))) + ("`(remove-if ,(lambda (x)*HERE*" + ("remove-if" ("lambda" ("x") ,slime-cursor-marker))) + ("`(remove-if ,@(lambda (x)*HERE*" + ("remove-if" ("lambda" ("x") ,slime-cursor-marker)))) + (slime-check-top-level) + (with-temp-buffer + (lisp-mode) + (insert buffer-sexpr) + (search-backward "*HERE*") + (delete-region (match-beginning 0) (match-end 0)) + (slime-check-buffer-form result-form) + (unless skip-trailing-test-p + (insert ")") (backward-char) + (slime-check-buffer-form result-form)) + )) + +(provide 'slime-parse-tests) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-presentations-tests.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-presentations-tests.el new file mode 100644 index 0000000..fad8d99 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-presentations-tests.el @@ -0,0 +1,61 @@ +(require 'slime-presentations) +(require 'slime-tests) +(require 'slime-repl-tests "test/slime-repl-tests") + +(define-slime-ert-test pick-up-presentation-at-point () + "Ensure presentations are found consistently." + (cl-labels ((assert-it (point &optional negate) + (let ((result + (cl-first + (slime-presentation-around-or-before-point point)))) + (unless (if negate (not result) result) + (ert-fail + (format "Failed to pick up presentation at point %s" + point)))))) + (with-temp-buffer + (slime-insert-presentation "1234567890" `(:inspected-part 42)) + (insert " ") + (assert-it 1) + (assert-it 2) + (assert-it 3) + (assert-it 4) + (assert-it 5) + (assert-it 10) + (assert-it 11) + (assert-it 12 t)))) + +(def-slime-test (pretty-presentation-results (:fails-for "allegro")) + (input result-contents) + "Test some more simple situations dealing with print-width and stuff. + +Very much like `repl-test-2', but should be more stable when +presentations are enabled, except in allegro." + '(("\ +(with-standard-io-syntax + (write (make-list 15 :initial-element '(1 . 2)) :pretty t :right-margin 75) + 0)" + "\ +SWANK> \ +(with-standard-io-syntax + (write (make-list 15 :initial-element '(1 . 2)) :pretty t :right-margin 75) + 0) +{((1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2) + (1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2)) +}0 +SWANK> *[]") + ;; Two times to test the effect of FRESH-LINE. + ("\ +(with-standard-io-syntax + (write (make-list 15 :initial-element '(1 . 2)) :pretty t :right-margin 75) + 0)" + "SWANK> \ +(with-standard-io-syntax + (write (make-list 15 :initial-element '(1 . 2)) :pretty t :right-margin 75) + 0) +{((1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2) + (1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2)) +}0 +SWANK> *[]")) + (slime-test-repl-test input result-contents)) + +(provide 'slime-presentations-tests) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-repl-tests.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-repl-tests.el new file mode 100644 index 0000000..dde08ae --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/contrib/test/slime-repl-tests.el @@ -0,0 +1,343 @@ +(require 'slime-repl) +(require 'slime-tests) +(require 'cl-lib) + +(defmacro slime-repl-test-markers (expected-string-spec &rest marker-specs) + "For (MARKER SIG FORM) in MARKER-SPECS, produce suitable `should' assertions. +The assertions compare values in symbols `expected-MARKER' and +`observed-MARKER'. The former is obtained by searching EXPECTED-STRING-SPEC +for the string sig SIG, the latter by evaling FORM in the test buffer." + (declare (indent 1)) + (cl-loop + for (marker signature observer-form) in marker-specs + for expected-sym = (make-symbol (format "expected-%s" marker)) + for observed-sym = (make-symbol (format "observed-%s" marker)) + + collect `(,expected-sym + (progn (goto-char (point-min)) + (when (search-forward ,signature nil t) + (replace-match "") + (point-marker)))) + into expected-bindings + collect `(,observed-sym ,observer-form) + into observed-bindings + collect `(when (and ,observed-sym (not ,expected-sym)) + (ert-fail + (format "Didn't expect to observe %s, but did and its %s" + ',marker ,observed-sym))) + into assertions + collect `(when (and (not ,observed-sym) ,expected-sym) + (ert-fail + (format "Expected %s to be %s, bit didn't observe anything" + ',marker ,expected-sym))) + into assertions + collect `(when (and ,observed-sym ,expected-sym) + (should (= ,observed-sym ,expected-sym))) + into assertions + finally + (return + `(progn + (let (,@observed-bindings + (observed-string (buffer-substring-no-properties (point-min) + (point-max)))) + (with-current-buffer (get-buffer-create "*slime-repl test buffer*") + (erase-buffer) + (insert ,expected-string-spec) + (let (,@expected-bindings) + (should + (equal observed-string (buffer-string))) + ,@assertions))))))) + +(defun slime-check-buffer-contents (_msg expected-string-spec) + (slime-repl-test-markers expected-string-spec + (point "*" (point)) + (output-start "{" (next-single-property-change + (point-min) 'slime-repl-output)) + (output-end "}" (previous-single-property-change + (point-max) 'slime-repl-output)) + (input-start "[" slime-repl-input-start-mark) + (point-max "]" (point-max)) + (next-input-start "^" nil))) + +(def-slime-test package-updating + (package-name nicknames) + "Test if slime-lisp-package is updated." + '(("COMMON-LISP" ("CL")) + ("KEYWORD" ("" "KEYWORD" "||")) + ("COMMON-LISP-USER" ("CL-USER"))) + (with-current-buffer (slime-output-buffer) + (let ((p (slime-eval + `(swank-repl:listener-eval + ,(format + "(cl:setq cl:*print-case* :upcase) + (cl:setq cl:*package* (cl:find-package %S)) + (cl:package-name cl:*package*)" package-name)) + (slime-lisp-package)))) + (slime-check ("slime-lisp-package is %S." package-name) + (equal (slime-lisp-package) package-name)) + (slime-check ("slime-lisp-package-prompt-string is in %S." nicknames) + (member (slime-lisp-package-prompt-string) nicknames))))) + +(defmacro with-canonicalized-slime-repl-buffer (&rest body) + "Evaluate BODY within a fresh REPL buffer. The REPL prompt is +canonicalized to \"SWANK\"---we do actually switch to that +package, though." + (declare (debug (&rest form)) (indent 0)) + `(let ((%old-prompt% (slime-lisp-package-prompt-string))) + (unwind-protect + (progn (with-current-buffer (slime-output-buffer) + (setf (slime-lisp-package-prompt-string) "SWANK")) + (kill-buffer (slime-output-buffer)) + (with-current-buffer (slime-output-buffer) + ,@body)) + (setf (slime-lisp-package-prompt-string) %old-prompt%)))) + +(def-slime-test repl-test + (input result-contents) + "Test simple commands in the minibuffer." + '(("(+ 1 2)" "SWANK> (+ 1 2) +3 +SWANK> *[]") + ("(princ 10)" "SWANK> (princ 10) +{10 +}10 +SWANK> *[]") + ("(princ 10)(princ 20)" "SWANK> (princ 10)(princ 20) +{1020 +}20 +SWANK> *[]") + ("(dotimes (i 10 77) (princ i) (terpri))" + "SWANK> (dotimes (i 10 77) (princ i) (terpri)) +{0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +}77 +SWANK> *[]") + ("(abort)" "SWANK> (abort) +; Evaluation aborted on NIL. +SWANK> *[]") + ("(progn (princ 10) (force-output) (abort))" + "SWANK> (progn (princ 10) (force-output) (abort)) +{10}; Evaluation aborted on NIL. +SWANK> *[]") + ("(progn (princ 10) (abort))" + ;; output can be flushed after aborting + "SWANK> (progn (princ 10) (abort)) +{10}; Evaluation aborted on NIL. +SWANK> *[]") + ("(if (fresh-line) 1 0)" + "SWANK> (if (fresh-line) 1 0) +{ +}1 +SWANK> *[]") + ("(values 1 2 3)" "SWANK> (values 1 2 3) +1 +2 +3 +SWANK> *[]")) + (with-canonicalized-slime-repl-buffer + (insert input) + (slime-check-buffer-contents "Buffer contains input" + (concat "SWANK> [" input "*]")) + (call-interactively 'slime-repl-return) + (slime-sync-to-top-level 5) + (slime-check-buffer-contents "Buffer contains result" result-contents))) + +(def-slime-test repl-test-2 + (input result-contents) + "Test some more simple situations dealing with print-width and stuff" + '(("(with-standard-io-syntax + (write (make-list 15 :initial-element '(1 . 2)) :pretty t) 0)" + "SWANK> (with-standard-io-syntax + (write (make-list 15 :initial-element '(1 . 2)) :pretty t) 0) +{((1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2) + (1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2)) +}0 +SWANK> *[]") + ;; Two times to test the effect of FRESH-LINE. + ("(with-standard-io-syntax + (write (make-list 15 :initial-element '(1 . 2)) :pretty t) 0)" + "SWANK> (with-standard-io-syntax + (write (make-list 15 :initial-element '(1 . 2)) :pretty t) 0) +{((1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2) + (1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2) (1 . 2)) +}0 +SWANK> *[]")) + (slime-skip-test "Repl test is unstable without the slime-presentations contrib.") + (slime-test-repl-test input result-contents)) + +(def-slime-test repl-return + (before after result-contents) + "Test if slime-repl-return sends the correct protion to Lisp even +if point is not at the end of the line." + '(("(+ 1 2)" "" "SWANK> (+ 1 2) +3 +SWANK> ") +("(+ 1 " "2)" "SWANK> (+ 1 2) +3 +SWANK> ") + +("(+ 1\n" "2)" "SWANK> (+ 1 +2) +3 +SWANK> ")) + (with-canonicalized-slime-repl-buffer + (insert before) + (save-excursion (insert after)) + (slime-test-expect "Buffer contains input" + (concat "SWANK> " before after) + (buffer-string)) + (call-interactively 'slime-repl-return) + (slime-sync-to-top-level 5) + (slime-test-expect "Buffer contains result" + result-contents (buffer-string)))) + +(def-slime-test repl-read + (prompt input result-contents) + "Test simple commands in the minibuffer." + '(("(read-line)" "foo" "SWANK> (values (read-line)) +foo +\"foo\" +SWANK> ") + ("(read-char)" "1" "SWANK> (values (read-char)) +1 +#\\1 +SWANK> ") + ("(read)" "(+ 2 3 +4)" "SWANK> (values (read)) +\(+ 2 3 +4) +\(+ 2 3 4) +SWANK> ")) + (with-canonicalized-slime-repl-buffer + (insert (format "(values %s)" prompt)) + (call-interactively 'slime-repl-return) + (slime-wait-condition "reading" #'slime-reading-p 5) + (insert input) + (call-interactively 'slime-repl-return) + (slime-sync-to-top-level 5) + (slime-test-expect "Buffer contains result" + result-contents (buffer-string)))) + +(def-slime-test repl-read-lines + (command inputs final-contents) + "Test reading multiple lines from the repl." + '(("(list (read-line) (read-line) (read-line))" + ("a" "b" "c") + "SWANK> (list (read-line) (read-line) (read-line)) +a +b +c +\(\"a\" \"b\" \"c\") +SWANK> ")) + (with-canonicalized-slime-repl-buffer + (insert command) + (call-interactively 'slime-repl-return) + (dolist (input inputs) + (slime-wait-condition "reading" #'slime-reading-p 5) + (insert input) + (call-interactively 'slime-repl-return)) + (slime-sync-to-top-level 5) + (slime-test-expect "Buffer contains result" + final-contents + (buffer-string) + #'equal))) + +(def-slime-test repl-type-ahead + (command input final-contents) + "Ensure that user input is preserved correctly. +In particular, input inserted while waiting for a result." + '(("(sleep 0.1)" "foo*" "SWANK> (sleep 0.1) +NIL +SWANK> [foo*]") + ("(sleep 0.1)" "*foo" "SWANK> (sleep 0.1) +NIL +SWANK> [*foo]") + ("(progn (sleep 0.1) (abort))" "*foo" "SWANK> (progn (sleep 0.1) (abort)) +; Evaluation aborted on NIL. +SWANK> [*foo]")) + (with-canonicalized-slime-repl-buffer + (insert command) + (call-interactively 'slime-repl-return) + (save-excursion (insert (cl-delete ?* input))) + (forward-char (cl-position ?* input)) + (slime-sync-to-top-level 5) + (slime-check-buffer-contents "Buffer contains result" final-contents))) + + +(def-slime-test interrupt-in-blocking-read + () + "Let's see what happens if we interrupt a blocking read operation." + '(()) + (slime-skip-test "TODO: skip for now, but analyse this failure!") + (slime-check-top-level) + (with-canonicalized-slime-repl-buffer + (insert "(read-char)") + (call-interactively 'slime-repl-return) + (slime-wait-condition "reading" #'slime-reading-p 5) + (slime-interrupt) + (slime-wait-condition "Debugger visible" + (lambda () + (and (slime-sldb-level= 1) + (get-buffer-window + (sldb-get-default-buffer)))) + 5) + (with-current-buffer (sldb-get-default-buffer) + (sldb-continue)) + (slime-wait-condition "reading" #'slime-reading-p 5) + (with-current-buffer (slime-output-buffer) + (insert "X") + (call-interactively 'slime-repl-return) + (slime-sync-to-top-level 5) + (slime-test-expect "Buffer contains result" + "SWANK> (read-char) +X +#\\X +SWANK> " (buffer-string))))) + +(def-slime-test move-around-and-be-nasty + () + "Test moving around in repl, and watching attempts to destroy prompt fail" + '(()) + (slime-skip-test "TODO: Test causes instability for other tests.") + (slime-check-top-level) + (with-canonicalized-slime-repl-buffer + (let ((start (point))) + (insert "foo") + (beginning-of-line) + (should (equal (buffer-substring-no-properties + (point-min) + (point-max)) "SWANK> foo")) + (should (equal (point) start)) + (unwind-protect + (progn + (let ((inhibit-field-text-motion t)) + (goto-char (line-beginning-position))) + (should-error (delete-char 1))) + (goto-char (line-end-position)))))) + +(def-slime-test mixed-output-and-results + (prompt eval-input result-contents) + "Test that output goes to the correct places." + '(("(princ 123)" (cl:loop repeat 2 do (cl:princ 456)) "SWANK> (princ 123) +123 +123 +456456 +SWANK> ")) + (with-canonicalized-slime-repl-buffer + (insert prompt) + (call-interactively 'slime-repl-return) + (slime-sync-to-top-level 5) + (slime-eval eval-input) + (slime-sync-to-top-level 5) + (slime-test-expect "Buffer contains result" + result-contents (buffer-string)))) + +(provide 'slime-repl-tests) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/doc/.cvsignore b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/doc/.cvsignore new file mode 100644 index 0000000..83078f7 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/doc/.cvsignore @@ -0,0 +1,21 @@ +contributors.texi +slime.aux +slime.cp +slime.dvi +slime.fn +slime.fns +slime.info +slime.ky +slime.kys +slime.log +slime.pdf +slime.pg +slime.ps +slime.tmp +slime.toc +slime.tp +slime.vr +slime.vrs +slime.html +html +html.tgz diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/doc/Makefile b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/doc/Makefile new file mode 100644 index 0000000..242a70b --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/doc/Makefile @@ -0,0 +1,116 @@ +# This file has been placed in the public domain. +# +# Where to put the info file(s). NB: the GNU Coding Standards (GCS) +# and the Filesystem Hierarchy Standard (FHS) differ on where info +# files belong. The GCS says /usr/local/info; the FHS says +# /usr/local/share/info. Many distros obey the FHS, but people who +# installed their emacs from source probably have a GCS-ish file +# hierarchy. +infodir=/usr/local/info + +# What command to use to install info file(s) +INSTALL_CMD=install -m 644 + +# Info files generated here. +infofiles=slime.info + +TEXI = slime.texi contributors.texi + +help: + @echo -e "\ +Most important targets:\n\ +all generate info, pdf, and html documents\n\ +slime.info generate the slime.info file\n\ +slime.html generate a single html file\n\ +html/index.html generate on html file per node in html/ directory\n\ +html.tgz create a tarball of all html files\n\ +clean remove generated files" + +all: slime.info slime.pdf html/index.html + +slime.dvi: $(TEXI) + texi2dvi slime.texi + +slime.ps: slime.dvi + dvips -o $@ $< + +slime.info: $(TEXI) + makeinfo $< + +slime.html: $(TEXI) + texi2html --css-include=slime.css $< + +html/index.html: $(TEXI) + makeinfo -o html --css-include=slime.css --html $< + +html.tgz: html/index.html + tar -czf $@ html + +DOCDIR=/project/slime/public_html/doc +# invoke this like: make CLUSER=heller publish +publish: slime.pdf html.tgz + scp slime.pdf html.tgz $(CLUSER)@common-lisp.net:$(DOCDIR) + ssh $(CLUSER)@common-lisp.net "cd $(DOCDIR); tar -zxf html.tgz" + +slime.pdf: $(TEXI) + texi2pdf $< + +slime-refcard.pdf: slime-refcard.tex + texi2pdf $< + +install: install-info + +uninstall: uninstall-info + +# Create contributors.texi, a texinfo table listing all known +# contributors of code. +# +# The gist of this horror show is that the contributor list is piped +# into texinfo-tabulate.awk with one name per line, sorted +# by number of contributions. +LAST_CHANGELOG_COMMIT=ab6d1bd5c9d3c5b4a6299b8c864ce4acfd25cbcc +contributors.texi: ../slime.el Makefile texinfo-tabulate.awk + git show $(LAST_CHANGELOG_COMMIT):ChangeLog \ + $(LAST_CHANGELOG_COMMIT):contrib/ChangeLog | \ + sed -ne '/^[0-9]/{s/^[^ ]* *//; s/ *<.*//; p;}' | \ + (cat; git log $(LAST_CHANGELOG_COMMIT).. --format='%aN') | \ + sort | \ + uniq -c | \ + LC_ALL=C sort -nr | \ + sed -e 's/^[^A-Z]*//; /^$$/d' | \ + LC_ALL=C awk -f texinfo-tabulate.awk \ + > $@ + +#.INTERMEDIATE: contributors.texi + +# Debian's install-info wants a --section argument. +install-info: section=$(shell grep INFO-DIR-SECTION $(infofiles) | sed 's/INFO-DIR-SECTION //') +install-info: slime.info + mkdir -p $(infodir) + $(INSTALL_CMD) $(infofiles) $(infodir)/$(infofiles) + @if (install-info --version && \ + install-info --version 2>&1 | sed 1q | grep -i -v debian) >/dev/null 2>&1; then \ + echo "install-info --info-dir=$(infodir) $(infodir)/$(infofiles)";\ + install-info --info-dir="$(infodir)" "$(infodir)/$(infofiles)" || :;\ + else \ + echo "install-info --infodir=$(infodir) --section $(section) $(section) $(infodir)/$(infofiles)" && \ + install-info --infodir="$(infodir)" --section $(section) ${section} "$(infodir)/$(infofiles)" || :; fi + +uninstall-info: + @if (install-info --version && \ + install-info --version 2>&1 | sed 1q | grep -i -v debian) >/dev/null 2>&1; then \ + echo "install-info --info-dir=$(infodir) --remove $(infodir)/$(infofiles)";\ + install-info --info-dir="$(infodir)" --remove "$(infodir)/$(infofiles)" || :;\ + else \ + echo "install-info --infodir=$(infodir) --remove $(infodir)/$(infofiles)";\ + install-info --infodir="$(infodir)" --remove "$(infodir)/$(infofiles)" || :; fi + rm -f $(infodir)/$(infofiles) + +clean: + rm -f contributors.texi + rm -f slime.aux slime.cp slime.cps slime.fn slime.fns slime.ky + rm -f slime.kys slime.log slime.pg slime.tmp slime.toc slime.tp + rm -f slime.vr slime.vrs + rm -f slime.info slime.pdf slime.dvi slime.ps slime.html + rm -f slime-refcard.pdf slime-refcard.log slime-refcard.aux + rm -rf html html.tgz diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/doc/contributors.texi b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/doc/contributors.texi new file mode 100644 index 0000000..13d7504 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/doc/contributors.texi @@ -0,0 +1,67 @@ +@multitable @columnfractions 0.333333 0.333333 0.333333 + +@item Helmut Eller @tab Tobias C. Rittweiler @tab Stas Boukarev +@item Luke Gorrie @tab Matthias Koeppe @tab Luís Oliveira +@item Nikodemus Siivola @tab Marco Baringer @tab João Távora +@item Alan Ruttenberg @tab Henry Harrington @tab Mark Evenson +@item Christophe Rhodes @tab Edi Weitz @tab Martin Simmons +@item Juho Snellman @tab Attila Lendvai @tab Peter Seibel +@item Geo Carncross @tab Douglas Crosher @tab Daniel Kochmanski +@item Gábor Melis @tab Daniel Barlow @tab Wolfgang Jenkner +@item Stelian Ionescu @tab Michael Weber @tab Didier Verna +@item Lawrence Mitchell @tab Anton Kovalenko @tab Terje Norderhaug +@item Jan Moringen @tab Brian Downing @tab Bill Clementson +@item Andras Simon @tab Adlai Chandrasekhar @tab Zach Beane +@item Ivan Shvedunov @tab Francois-Rene Rideau @tab Espen Wiborg +@item António Menezes Leitão @tab Utz-Uwe Haus @tab Thomas Schilling +@item Thomas F. Burdick @tab Takehiko Abe @tab Sébastien Villemot +@item Richard M Kreuter @tab Raymond Toy @tab Matthew Danish +@item Mark Harig @tab James Bielman @tab Harald Hanche-Olsen +@item Ariel Badichi @tab Andreas Fuchs @tab Willem Broekema +@item Taylor R. Campbell @tab Phil Hargett @tab Paulo Madeira +@item Lars Magne Ingebrigtsen @tab John Paul Wallington @tab Joerg Hoehle +@item David Reitter @tab Bryan O'Connor @tab Alexander Artemenko +@item Alan Shutko @tab Ursa americanus kermodei @tab Travis Cross +@item Tobias Rittweiler @tab Tiago Maduro-Dias @tab Stefan Kamphausen +@item Sean O'Rourke @tab Robert Lehr @tab Robert E. Brown +@item Philipp Marek @tab Peter S. Housel @tab Nathan Trapuzzano +@item Nathan Bird @tab Luís Borges de Oliveira @tab Jouni K Seppanen +@item Jon Oddie @tab Ivan Toshkov @tab Ian Eslick +@item Geoff Wozniak @tab Gary King @tab Fice T +@item Eric Blood @tab Eduardo Muñoz @tab Douglas Katzman +@item Christophe Junke @tab Christian Schafmeister @tab Christian Lynbech +@item Chris Capel @tab Charles Zhang @tab Bjørn Nordbø +@item Bart Botta @tab Anton Vodonosov @tab Alexey Dejneka +@item Alan Caulkins @tab Yu-Chiang Hsu @tab Yaroslav Kavenchuk +@item YOKOTA Yuki @tab Wolfgang Mederle @tab Wojciech Kaczmarek +@item William Bland @tab Vitaly Mayatskikh @tab Tomas Zellerin +@item Tom Pierce @tab Tim Daly Jr. @tab Syohei YOSHIDA +@item Sven Van Caekenberghe @tab Svein Ove Aas @tab Steve Smith +@item StanisBaw Halik @tab Sergey Kostyaev @tab Samuel Freilich +@item Russell McManus @tab Russ Tyndall @tab Rui Patrocínio +@item Robert P. Goldman @tab Robert Macomber @tab Robert Brown +@item Reini Urban @tab R. Matthew Emerson @tab Peter Feigl +@item Peter @tab Pawel Ostrowski @tab Paul Donnelly +@item Paul Collins @tab Olof-Joachim Frahm @tab Neil Van Dyke +@item NIIMI Satoshi @tab Mészáros Levente @tab Mikel Bancroft +@item MichaÅ‚ Herda @tab Michael White @tab Matthew Kennedy +@item Matthew D. Swank @tab Matt Pillsbury @tab Masayuki Onjo +@item Mark Wooding @tab Mark Karpov @tab Mark H. David +@item Marco Monteiro @tab Lynn Quam @tab Levente Mészáros +@item Leo Liu @tab Lasse Rasinen @tab Knut Olav Bøhmer +@item Kai Kaminski @tab Julian Stecklina @tab Juergen Gmeiner +@item Jon Allen Boone @tab John Stracke @tab John Smith +@item Johan BockgÃ¥rd @tab Joe Robertson @tab Jim Newton +@item Javier Olaechea @tab Jan Rychter @tab James McIlree +@item Jack Pugmire @tab Ivan Sokolov @tab Ivan Boldyrev +@item Ignas Mikalajunas @tab Hannu Koivisto @tab Graham Dobbins +@item Gerd Flaig @tab Gail Zacharias @tab Frederic Brunel +@item Eric Timmons @tab Dustin Long @tab Dmitry Igrishin +@item Deokhwan Kim @tab Denis Budyak @tab Daniel Koning +@item Daniel KochmaÅ„ski @tab Dan Weinreb @tab Dan Pierson +@item Cyrus Harmon @tab Chris Schafmeister @tab Cecil Westerhof +@item Brian Mastenbrook @tab Brandon Bergren @tab Bozhidar Batsov +@item Bob Halley @tab Barry Fishman @tab B.Scott Michel +@item Angelo Rossi @tab Andrew Myers @tab Aleksandar Bakic +@item Alain Picard @tab Adam Bozanich +@end multitable diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/doc/slime-refcard.pdf b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/doc/slime-refcard.pdf new file mode 100644 index 0000000000000000000000000000000000000000..66e41849598c6f036abad7f3abc9fb46876b2209 GIT binary patch literal 41845 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 qW@KPsY3ych +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcDnQp&=1TJ,~> +JcDnQp&=1TJ,~> +JcDnQp&=1TJ,~> +JcE=]rVd0(rr2loqtg-`p\+IV#PRoeq>:*grpKf:~> +JcE=]rVd0(rr2loqtg-`p\+IV#PRoeq>:*grpKf:~> +JcE=]rVd0(rr2loqtg-`p\+IV#PRoeq>:*grpKf:~> +^&S*2K`;\ar;-0]p@n@Wp@RnBl/gp^gtM_[%,0ImiT04hnFZMQrVl?eJ,~> +^&S*2K`;\ar;-0]p@n@Wp@RnBl/gp^gtM_[%,0ImiT04hnFZMQrVl?eJ,~> +^&S*2K`;\ar;-0]p@n@Wp@RnBl/gp^gtM_[%,0ImiT04hnFZMQrVl?eJ,~> +_#FK8r;$?d!r;cn\,QX2rVZTlrpKdkrquWgqYU6joD]L&q=RRajSr)m.C/Qo)F4~> +_#FK8r;$?d!r;cn\,QX2rVZTlrpKdkrquWgqYU6joD]L&q=RRajSr)m.C/Qo)F4~> +_#FK8r;$?d!r;cn\,QX2rVZTlrpKdkrquWgqYU6joD]L&q=RRajSr)m.C/Qo)F4~> +_>al?q!dM,hr['q!?_R[B6U<\@8]>TW+a/a2[rL%+WD>YGn1p]$&prp\j^`J,~> +_>al?q!dM,hr['q!?_R[B6U<\@8]>SYMdk^:j@0%*ZE"VkT`^]$&prp\j^`J,~> +_>al?q!dM,hr['q!?_R[B6U<\@8]>V6mGObffhD%+WSI]!S?7]$&prp\j^`J,~> +h>[WWrVZQgrV-NkqY^ +h>[WWrVZQgrV-NkqY^ +h>[WWrVZQgrV-NkqY^ +i;XMjrVH<]nEfB#j5]4`lgOH>q>C3jq>Us'pZTo*]]&><]WTQDp\jIY$N0Yek2"S6bK.`Erl4rX +&]r8De_&U3i8`tbmIBiCqYgEerser%mFoFYYH=n8d,t$!pAYX%qXE=XWP-?nW4LRHq>U0h%/ohS +[aX +i;XMjrVH<]nEfB#j5]4`lgOH>q>C3jq>Us'pZTo'Ze=ZtZ`DC8p\jIY$N0Yek2"S6bK.`Erl4rX +&]r8De_&U3i8`tbmIBiCqYgEerser%mFoFYWMcZ'd,t$!pAYX%qXE=XVR4(PUUo%Cq>U0h%/ohS +[`n%#kND*rlfmd!#jCO?bH'(YqYp0fJ,~> +i;XMjrVH<]nEfB#j5]4`lgOH>q>C3jq>UWspZTo0_>_X^_6_GNp\jIY$N0Yek2"S6bK.`Erl4rX +&]r8De_&U3i8`tbmIBiCqYgEerser%mFoFY\[SrTd,t$!pAYX%qXE=XXhr)uZ+ANQq>U0h%/ohS +[`cFp[C*Zc_S#6C#e.Ieb-TO`qYp0fJ,~> +ir9kpr:omMj4hu'_7R1c\\?)/fAPl]p%eObqu70'nC=YujOr):jPR)inGDVQ#lOAYeA&,YUT+6j +rMKRl&ZM@nU8Fur\%T]%dFmOFo_SR^rt#,*mFJYMn*93*d]1LSp\jjd&,YqR];b5Zi8F"CZIeRB +rqZR'qsDY1lH-<4XLlTm]<(D##dM"dh:&pnpAO[aJ,~> +ir9kpr:omMj4hu'_7R1c\\?)/fAPl]p%eObqu70'nC=SolKIEplJ&AinGDVQ#lOAYeA&,YT;)+R +&tu(iSt`*_Z+%Eab0eo%lh(&Qq#:m(qX)k@WpB$ +ir9kpr:omMj4hu'_7R1c\\?)/fAPl]p%eObqu70'nC=kd^ULV[^W +jSp5!r:odDfu^e(TW#$4`5KX*VPBrn_U.-&nbE%]rr3Q/q<,T+jM8%%Z,#G4_<:Xnn,E[lpZKc$ +a7&Kap$)PFrpLj&hlI!DZ]?TEJ +]]&S_qYq$(q<,Q6i4G)-M3+3lOR.f0N0'^WmB"n/r:U)?~> +jSoYfr:odDfu^e(SYE!prk&ZETV&$d_U.-&nbE%]rr3Q/q<,T#lJgaZi8X%._<:Xnn,E[lpZKc" +^?b+Po^)SC%GA>*Yb%S[Vmjk,nG<.[rt#%ugU4c]kN(^cl.W)cn,)n[&H2=`_5$AZio/kXlE\(] +pAOjf%K?1d^qT'lg=Os1gtUQLf*L$_h<"%&f(&\2s*t~> +jSoYfr:odDfu^e(V6RMKrko5ZYH4P+_U.-&nbE%]rr3Q/q<,T1^SmiuTr>`A_<:Xnn,E[lpZKc* +`luZIou$jQrQG\e`4`=ZUo1]FhsgLAq>V!'o%URl_R6MJYe%o[eF3;0rt,/&jMA1@ZDaXtYeRud +iV*6Hrso&(kJ5*MVO*gCQ^ +jo5bfq=3Rs^o=!Gi9omnrSSgZlL"&YYFr&9f&uZ$rr<#tp><.DeZ=^dN2tLtZ/>9Sn,E[jn'nDq +i76B&ouR3]rm_J2i8E\]lL+,hXhEQ]r;-F*rqPZpWTqU,S"$+djLMq`p\t!g&GtqFVs_s0PE:m' +dI*aUmeck\%0$%_\AdC +jo5bfq=3Rs^o<.@kMOqDf\blXZ/>9Sn,E[jn'n>j +l0%6kp#H,8roXCIl07L4liue!VnLpWr;-F*rqPZpU?psugt^`FlE\(_p\t!g#5dlKeD0-OVpY#3p&BO~> +jo5bfq=3Rs^o=9Obf[l@rOa8f`5g*>\>6:Ff&uZ$rr<#tp><.![@`qYS"@%3Z/>9Sn,E[jn'nV` +]X>/OorS5"rj<3E]Y)"t`6-^V@GAp\t!g&GtqFXNIi=QC!r. +ZH9&lmeck\%0$%_\AZ%WQ`IKoUS[sjs.fUb!1WhPrgj(a$EL>7UR/+$\'a^Cp&BO~> +kPl%kr:]F/_5=EomGQ[Fai+.i+Mc+De_oWYdBTXhhspRBs8DWFVsi0;M04ZUeaKEjp&4C[$3'b_ +^rPBFXK8,gRfK>bX:DMI]>2P1dFI(<^;T1/rql^-r:8L?i7YAoK7f#]eaK +kPl%kr:]F/_5=0amHNisjQ$3t+QDJDkNV=!af25XhspRBs8DWFVsEO'f?`(+kNf&#p&4C[$3'b_ +^q]-mhr!8_g]641h[\T'iSrqZk3)!q[`%>'rql^-r:8L?g$%AHeC<+-kNeqonbi7`')q^i^p<7b +g=+Kug>_D&]]Akequ7B0pYrWol/C@Eb0%rPeCWF0gu%#IqVhG2s4dt8g"4j2jQrnrnbi([J,~> +kPl%kr:]F/_5=`da1SmeXfMDt+K2EH[CjB!agn@hhspRBs8DWFVp)Q@S@"iY[EPQ'p&4C[$3'b_ +^rO*bT:_SFQN3QTT+7QlVPpW!ZF.9^_o1^4rql^-r:8L?bdX:8USFBO[EPGsnbi7`')q^i^qd^` +QDgj_QDhR4]]Akequ7B0pYrX!]V_$raiV93URdd=Q_'eBqPO7`s-F([R@Tn8Xi.d"nbi([J,~> +kl21mqXW[jYG^=Ag!..6VONkLO74rsA]! +iNr"'XGMdfon*7"reV,DOH>ZqS#39qeaKToo_n^f'E7jn`i87FRtGWtJssdGVoS*!rql^.rUo!M +dG;6kH>.S]Z.\'7g%51>rtPJ-j0lna]9%DS>]54_X1HBne^`@Li;V:,a9oMeX/ii!jIG&urUp2@~> +kl21mqXW[jYFsS7kiLd]hV?l`g)o,+hr3VXl0I$"^Ynb^s8DTCU[.+#f?`(+kNenro_n:Z$3'\X +Zg6f3f@SRGe,\)!f)XJ&gAfq6hV[;Tl`Ak5rVZ[/rqbp"U?psreBH.dguRgqa6NO#qu7<-p"cgo +l/C=Cb0\f!kh2rgoDSRd'`Rmf[_1k`g="-?bgbG*iT0(_kNMd,roa=Bs5F"8#3"t'QJM33p&BO~> +kl21mqXW[jYHcQQVT\R\-IXZF[os[D1Ylr;Z`ffqZd!T:E9ZT!ce;g%>74rsA]! +iNpb9T:DFFoqMMYrgXIfQ^=#)Q^j\C[EP`,o_n^f'E7jn`j3ObQ_V:/UR/+$YfH&*rql^.rUo!M +ah"78Y0!rrtPJ-j0ln=VO+@*`4r(6Su/Wl[C*L?]`,>=XU:r#St;h"fsBN,rUp2@~> +l2M=oqXE=XUVuHN`3H"tN/*%9rHo`:K8#/DQ);".g$5``lh^VZo[oo,eZ=UMM6#1qU=f,:nG`am +pY`=FeZ=W(K)0BuF*2bUG^OmfK7er9R`Octe+*A6rtGA)i3^G\]9%DSBRGoQi5E+ap\t'i')_:K +TC:=3M03 +l2M=oqXE=XTtKaUj5AbIf[eR$rR)h;eCE1)gYUoLkj57klh^VZo[oo(kMOn;fAGcWU=f,:nG`am +pY`=BkMOnfeG@B%cHjndd*g@keC<($guRh$e+*A6rtGA)i3^/]iS)`&ajSo%l+FLbp\t'i')_:K +TBk[tf?_"Pe_T?ST?Zg$qu7W7puJuul/C@Eb08AjjQGdom-Euj]!f)[]=,0Ili6;Yl0. +l2M=oqXE=XWPl`aX.buKS"?COrMq'>US43EQ(4VM\&>c!lh^VZo[on^[@`trSY!75U=f,:nG`am +pY`=#[@`ucU\_\;\$W<=Z)aq(USFENQ`\3:e+*A6rtGA)i3^G8VO+@*b,^o,]Yh5KTpi4+XNg21qu79-puK!(]V_$rahOU;XgPg[`;[sb_8jX6_T0^rbl>Tg]XkMY]Z7S& +lM:GPs*t~> +lMhLrq^+GGDrH$k-tNg6m"n%.TTrr)KAU@6X6M04ZUeaK6bo_n:Z +#QFM[][>QDT_b)XJoCQl!b$#!r/(B(#,]f9YL;q7?rtG7p +aJ\=FRtGWaCk.ehkH;Ybq>U +lMhLrq5n-eBIif!jg,#r7Cns#2\M/WRC;6r;RH.n^X?!kMOn;\\?GCi98jmg%>7?rtG7p +aJ%t]gsjQFbL>5+l__M^q>UZt61LRbiolg)'+ +DS#K +lMhLrqW[@`tra2kNTTsr7Eg%>7?rtG7p +aK`[cQ_V:6_PWU!_RIAFq>U +li.XtqecA:l@c2,KfRt>Q`91rN.JsuVRB+iSf03H[9p[_/X@p +DfU)Zc27M4s*t~> +li.Xtq_:p\t-`fV7]phq-3+hrj="f_#.2 +rs&>ec?\g@jne$EgsjQEBP=6deD0uZrS.V6k3SPhoDSUe'Dh%9U?psreBFepcIUk7m$uGkr;?R/ +rqPQcYNk-$e'"0$db<[E]X?bnrqudGrqblrOmM/aeC<:7m!_j6@:Wt`G2I%MiSeNdBkV*h_-^HL +?!q8ia8>l.s*t~> +li.XtqZ$jQ'\$?SfjJgQC4;9USF9T][XCLp\t-`fV6TtT:E9ZT!ce:f_#.2 +rs&>ecF_-+YkkI.Q_V:5]tMA!UR1nMrKd_YZH9E)oDSUe'Dh%9Z,Ec2UV=^e\=]:saeR5Or;?R/ +rqPQc]t^M3W5ZZsX-fcs_mSLurqudGrqblr[)B)5USF0X`3cMF\@]Gh_r&;IiShVh^q[Rp_7$_Q +[(!`gjSSrKs*t~> +m/Ie!qXE4IViB2rJdMm:snWnd:Gqu7Q1lG]=Zad[p7R`OcVDUX#aJV&sWK7ipmKDpH1JUls4 +I,97"J<87ZoDa=~> +m/Ie!qXE4ITBt[rg=4Kndam%,hrEe[roYEcjPo.UhV?oBiU".jk5##To[oo(kMOn;fAGcWU=f,: +n,EUjp#9GgmJ+DfC7$EH1aIEH,r:Df4cS +C>N]ADLg"2oDa=~> +m/Ie!qXE4IYJdZ8Q_Uh#W1TWNSu]!!rjfXQ`\3:ZdZe1`lH?uaN4,MaN2EB`l7/Y +_;<#G`Qd]IoDa=~> +m/IdtoA@0XlH,`THuEqGM5I?$e`Z5crpLuslK$dOdE'DRea@b2med"^o[oo,eZ=UMM6#1qU=f,: +n,F7(qso,XGH%U-Pbt7>Q)D`nK5Y[[R`NR_rU9^M"n&Y&\FBCnrtYM*hQG8^[Z5ZH +m/IdtoA@0Qm,[!Rd`fq]fA>EIkNhL$rp(]om- +m/IdtoA@0a`3#K"X1l?USXc:W[DKl(rlcM*`4rmkZE:75[E5l)med"^o[on^[@`trSY!75U=f,: +n,F7(qsqV9['?sN]W\HKT!b\eUV=LfXQ`\3<\E(]Pai`!0b0'__rQ>/^ +#l;W`p;k=sd-^E(J,~> +mJf3GpufYlmEM>YF(oQ8M6#%Sma%ntS"+2]Kp9'nn*]K+mGF7PjS&QPrUea:n("LrFc!0Ln"SJ, +rU0\3rqh:sLXXIiFiM79Q&Y(NRtH<]aQe[mBPM7MQBd`$HZRi\q>U +mJe4+pufYhmH*0ScH=AWfAG`Rm)YrVR@I?IG(m-?li-5fmFmD,jS&QPrUea:lf[0Wce%(;l_<&( +rU0\3rqgYOGLOcGA&c>kQ%//]gsjj/jQq=l<`iImLkgbBC15c3q>UllF"bZhrF8u:; +Es)G`F8l/[!JAbis*t~> +mJf3GpufYta0;#+\&lClSY!-paiCa#Tq&9S\@]DsbfRfAa3)0.jS&QPrUea:bdF(5[%3erbbEb^ +rU0\3rqjaS`7)rA]#MRoQ*nQ4Q_U=BXi.TFXfnps^:h4p\%()Kq>UO_9&jJ +UUnOLhY-sIrtP=qa0ERbQ_V:6]u@UWR]si4cL:Z-rt"tl`jWgfQ_U=BXi.l`lH0%J"jm:lb5_M= +aoh[db5VC_!RU6)s*t~> +mJf3DnC=Jqfs-K\AT)sQX4?XAG&4^3cI7'eG'(<5CNukFWNp\qoDARfrUea:n("LrFc!0Ln"SJ, +rU'V0re,obna:pXlK*8mYiNT`IY+$0lB,q,H$Rh^G'8(UIdkeaqu7E.m`hKnc(Ti2?VO@+Fc!0L +n"\M+rVlg3rqGKa\E(GhIVW(Z>]54_aQfYBlh^MY&,PV3Sa+=dK7]Q5lBHGWK`6Z/PQ->js8VtM +"94(/s8I]QPLf=)J,~> +mJf3DnC=Jjkht+?^Wb-Xhrj@&AQlWScI6FSAR`5U=_FOdV6XWIoDARfrUea:lf[0Wce%(;l_<&( +rU'V0rc<(0na::4lK)Z\V<['oe(!16m"8PRB4oY(A7T7bD",[Iqu7E.m`h?jjk\J3XDiQsce%(; +l_E)'rVlg3rqGKaYNk-$e'".kV9IHEjQrPZlh^MY&,PV3PO.AceC<:7m"T$9ErL+`KE$"6s8Vt; +"93F`s8I'?K@'2hJ,~> +mJf3DnC=J]\"T:raM4dHT!c\TZ*LpOcI9MU]XbV[YdCdOZ*M!YoDARfrUea:bdF(5[%3erbbEb^ +rU'V0rlW=,na=B8lK,a^`4r7:W2#]]`4<4d^:r%.]=Y_j_slphqu7E.m`hfQYaV8s`P0+-[%3er +bbNe]rVlg3rqGKa]t^M3W5ZZe`4r(6Xi.E_lh^MY&,PV3[`#;7USF0X`4W\Iao9Edd/V82s8Vu= +"96Nds8L.Ad-^E(J,~> +mf,?IpZ9/nkJWX9D/Xf`X4=@sDfpBeJ+)r[nUQ,NI!U%_GLYK!K)>QIs8DTBU@6X6M04ZUeaK6b +o_n.Vs+M8Pr;2/#q=B!@_;MqeI"e6iB2qN,Ck.ehkH)G]q>Ujs8VtM +"94(/s8I]QPLf=)J,~> +mf,?IpZ9/glf6aKbfnMhhrgeI?"@X0D=@%7nSW4*C1q5)A^oRRE;TY7s8DTBU?h""f?`(+kNekp +o_n.Vs)T97r;1MTq=A@.\*;l*dad18m=o(cDf>/aDJjB3EVn)ZrtbV1l,0+ZjP88/VJ(+WcIUk7 +m$c8hr;Q^3rUegDam%d;dD_&OT$,U;j6NPVkP>,Trt"tl`focMgsjj/jQqV2lZ2uG"bZhrF8u:; +Es)G`F8u5\!JAbis*t~> +mf,?IpZ90"_Q/ru_S<.=T!c;<[(F*6`:*9;n\rH._8!\/][YfVa8>l9s8DTBUfs`P'"*\=]:s +aeI,Mr;Q^3rUegDah"78Y0"Mm_nr:9X2;9ZkP>,Trt"tl`jWgfQ_U=BXi.l`lcK.K"jm:lb5_M= +aoh[db5_I`!RU6)s*t~> +mf+X3o%0etfs-K\Dg[YXeW=TiH[gYBK`(e%r.KauJqARBJFW;bK`:uN&H27RU@6X6M04ZUeaK6b +o_n.Vs+M8Qs8Re,rqCiK_;MqeI"e6s+Q1,s8.KP +s+Q1,re1B:f(/ik~> +mf+X3o%0emkht+?bgP5(kCZrJBl.haEr>lWr,QiQEH#jbDt3L?F8l1=&H27RU?h""f?`(+kNekp +o_n.Vs)T!/s8R.]rqC39\*;l*dad18m<<,ZEcV*VErU1]s3UZC(B4*i\\.1cg="-,;J)cLeD0-O +T>p3nrr3c2n'@Njk2+\7ZZf6.ajSo%l+FLcq#:3k&,PS1PO.AceC<:7m"T$9ErL+`KE$"6s8Vt; +"93F`s8I'?K@'2hJ,~> +mf+X3o%0e`\"T:r^T3a![C* +mf+U0lc?'jad[p$I#tqtNbs#iJqSgVL&_1,s+Q1,KnP-WK`(h'L&M#_rUea:n("LrFc!0Ln"SJ, +rTsRaKbosQs+Q1+pO'9_i4G(uM6#1qBR#)]L&_%(!WUaJs"OHGhQOiT]9%DS=%5\^C4;>\jLDnc +q>UEnq<,SskJWX9D-KS# +mf+U0lc>gejP88/db<[EJQl`&E,p%!F8u8]s)W8]F)uC"Er>oXF8c+MrUea:lf[0Wce%(;l_<&( +rTsRaEu0K/s)W8\pM7(Cl/C@EfAGcWkF8u,Y!WUODs"OHGhQONTiS)`&P#>DLbL5,(lEIta +q>UEnq<,Sllf6aKbb& +F*%B\Ergp?o)F4~> +mf+U0lc?BMXd>fsX-fcsZa.9^a2uL'b5_Las2rLab0%j(ao).\b5M>OrUea:bdF(5[%3erbbEb^ +rTsRaaqrG)s2rL`pVO5W]V_$rSY!75Y.hotb5_@]!WVQas"OHGhQOf/VO+@*_Rd@s`i,3%^V.>C +q>UEnq<,T'_Q/ru_Sj*u_TJpHVS'aKhtI'Jrt,2+l,0pIXd>fXQ`\3=]'IK;ap$/lb0'baqoT$@ +b0'b`aoTlVo)F4~> +n,FF-puK!)i4G(uI#tqtcXh3IJqSf2s+ULQL&Zj\s8I]Us+ULQKn]L*&H27RU$pO5M04ZUeaK6b +o_n.Vs+M8Qs8Re,rq:`C^u2hdI#4oSmqI'!KSBI'K`V5)qu8AKo@Tl-eZ=UM@o5Z`re6()rV_EL +K*_7)KDU=UKp1*Ys*t~> +n,FF-puJuul/C@Edb<[E`Dg;_E,p#@s)\5?F8p<&s8I'Cs)\5?F*%<[&H27RU$Ln!f?`(+kNekp +o_n.Vs)T!/s8R.]rq:*1[cuc)db!C>lW@e=F*%BYErl +n,FF-puK!(]V_$rX-fcsbH&1ka2uKHs2tBAb5]W,s8L.Es2tBAb0'\_&H27RU!0p:S@"iY[EPAt +o_n.Vs2l/)s8U6arq=13aLnC:X.>iibceb$b0'b]aoVP0qu8AKo@Tk_[@`tra1o*p_TJpHVS'dP +i:m6NrUo'Q_n;k5X3&5i]"c:mSY!75VqUeArVmH.q<,N!`3#B$UR/+$]XmFNrlPDkrlWC^rVak< +a924YaSYtZ!RU6)s*t~> +n,FF-p>2t1fs-K\I#tqt^1MM:JqJ`0qh4nGK`6[Zs8I]Us+ULQKn]L*&H24OTC:=3M04ZUeaK9d +o_n.Vs+M8Qs8Re,rq1Wo)F4~> +n,FF-p>2t*kht+?db<[EZrCOOE,fo=qf;W5F8g6%s8I'Cs)\5?F*%<[&H24OTBk[tf?`(+kNenr +o_n.Vs)T!/s8R.]rq1!*f]_8Gd+@1F*%BYErl,^bi98jm +g@Y@Dr:/7.lf[0WcaeL::jfe!fAGcWT%*?/rVn;FpuT-$l/C@EeD0-OL19=cEH6&MpMk0Eo5AMa +D/=%KCM`BWEH?cZo)F4~> +n,FF-p>2sr\"T:rX-fcs`N6Yga2lBEqoSd7b5TQ+s8L.Es2tBAb0'\_&H24OT?O^8S@"iY[EPE! +o_n.Vs2l/)s8U6arq4(,bdX:8Z(7Jobcee%b0'b]aoVP0qu8AJn'@cOZCIMq`kJmm^rWdMTsr7E +g@Y@Dr:/7.bdF(5[)]qo]"c:mSY!75T%*?/rVn;FpuT-,]V_$rUR/+$]Xd4HaN;NKpW1DIo>\bg +`5BLQ_Sbc]aNDlso)F4~> +n,FF,p"QG6eZ=UMF,-X?h/I4SH[^Hom""TrK(X_Jq>Q$Nre:CPKn]L*&H)(IS+"n/M04`]g$klm +p&47Ws+M8Qs8Re,rUkK6n("LrFc!0LmqR0#KSBI'K`V5)qu8AHlc,jfad[p$>Y@sb:h"R(X4?[/ +ddd87qWc%tlH,NJDd5q3787*.KqQ]XU!<$&rVn;FpuAj%i4G(uJssdGPB#B,It)p(iSJq6eTc7[ +FE2B2EHB?NItIULo)F4~> +n,Fa5p"QG2kMOn;cIUk7fO.rqBl%X'lu)=`E:n3jq/ULsrcA,>F*%<[&H)(IS*T7pf?`+-kj,," +p&47Ws)T!/s8R.]rUjm%lf[0Wce%(;lW@h>F*%BYErlYe_T?SS^$U"rVmE-puAirl/C@EeD0-OKj`^8D&$l4iSJ;$eRi?% +@UWWR?X_/mD/oL#o)F4~> +n,Fa5p"QFh[@`tr\=]:s`iQMZ^r++/m)AJba7[Npq8pb$rlY9@b0'\_&H)(IS'8:4S@"cZ\'Lr* +p&47Ws2l/)s8U6arUmt'bdF(5[%3erbcnk&b0'b]aoVP0qu8AHlc-0IXd>fs`P&[k^W3^PT!ce4 +ddd87qWc&(`3#B$^;[e#]"Q(pTpi4+Wm0u/rVmE-puAj%]V_$rUR/+$]=6Sp`"g20iSMB&e\/T+ +\[])X[^aPs`5qlDo)F4~> +n,Fa5p"QG6eZ=UMA93O'dG9@fDK9iAaEGnYHJ*XmjaVi5q1S_HKn]L*&H)"BU[?="Km\uni8L]k +p&=:W(kn1Rs+Q1*oQm;$eZ=UMM6#1qC3kJbL&_%(!WUaKs"XNJk.J4b^ls4_=[u+a93cCeR`Ocm +amAm&p>NEti4G(uBiePK<_H\9JssdGUr;QprVn;FpYrU!i4G(uJssdGOD;JJFE;K4Z`\,>Sp-Kc +Pc_pC_T/`rGCK;:o)F4~> +n,Fa5p"QG2kMOn;^[V#NaCNWGB\@*7j_\pTq/ZH6F*%<[&H)"BTC(are^E11l.N)l +p&=:W(it?0s)W8[oOt#ckMOn;fAGcW=D2YpF8u,Y!WUOEs"XNJk.Iq`inDl)R9F2aAu3`$guRgr +amAm&p>NEll/C@Eb*&U2O_1H6eD0-OT#BpjrVn;FpYrTml/C@EeD0-OJQTV)@prcTZ`[K,SnEk6 +L8DPq\%\_FASq1fo)F4~> +n,Fa5p"QFh[@`traL@e3ZH';S[(!TWaLfdI^Y-E=ji#0Zq8rU8b0'\_&H)"BX2hH5TrXQX][3\6 +p&=:W(s:5*s2rL_oY70F[@`trSY!75YeS6$b5_@]!WVQbs"XNJk.JCBW0XC$_n3Rh]YqR[Q`\33 +amAm&p>NEt]V_$rahl!:_S!h%UR/+$Y/KW%rVn;FpYrTu]V_$rUR/+$\$3Qb]"#5ZZ`^U/T!Z5F +]X>\rai:`q]YsR2o)F4~> +n,Fa6p>2t@eZ=UM@pjA5VU=eg_3:+KVj4$IC8Gcc]6/@Fk(*1&Kn]L*&Gtk;WTqTpK7&cli5)VS +pAXCX(kn1Rs+Q1*oQm8#eZ=UMM6#1qC3kJbL&_%(!WUaKs"aTIi3L8Y]9%DS=%c@_8Qoq\Q,Mje +^ZYCho%'Vpfs-K\AR&nkBNA5MIZhJ,\%Lhtrr2p5rqGBY`8J7hI"Ig.lAAo;Vj*CN`5KOlmf;eT +l2^#Gi!/K*H[+r+rq$/?~> +n,Fa6p>2t +n,Fa6p>2sr[@`tra2YT\S?g2ZaLf*uZ+d9/YGJP3]=P\kk/R,lb0'\_&Gtk;Zc&u4UT9cZ]Z%)3 +pAXCX(s:5*s2rL_oY7-E[@`trSY!75YeS6$b5_@]!WVQbs"aTIi3L85VO+@*_S!Xr]YhU`Q)hd0 +^ZYCho%'V[\"T:raMc6.b/2'9W0XBs]tEJ%rr2p5rqGBY_n;k5X.u#``3Q/5Z+[ch`5BIkbQ,fb +_uR[Q]EZ=!\@q:orq$/?~> +n,F"!puK'(i4G(uBjP1gLSi>Li;Dj?mJZJ]_8V[aD81>TmXp2lrr3Q+m)Z*iad[p1OLjAdZJbKV +lMhZas8Re,rUbE1n("LrFc!0LmqR0#KSBI'K`V5)r;SPNo@Tqufs-K\AQW2H>YA+2I#tqt_mA:p +q!6%omEM>YEF3C,M0ru;BRGoQi5;n[p\t0l&,u=]ZGYV4OF1tuS&ssamJcANjSn*:eH""raT09X +]*?C5d;e*jrU^&>~> +n,F"!puK&rl/C@Eb,_hnf&#NPl29lJmJZ>Y[_7E.>ean1mW!:Hrr3Q+m)YjdjP885g>V;+ZJbKV +lMhZQs8R.]rUactlf[0Wce%(;lW@h>F*%BYErl~> +n,F"!puK'/]V_$rai29/T:E-p]_o\Ja8O3iaMkj"ZbO35m`f`R&7O8ZJbKV +lMh[Is8U6arUdk!bdF(5[%3erbcnk&b0'b]aoVP0r;SPNo@Tq`\"T:raMYs:`4Wt0X-fcs_R&1o +q!6&#a0;#+]#DgmSZBoMb,^o,]Y_#6p\t0l&,u=]ZGX>PQ`IiqQ`\3Ma8X!W^](nF[/dN3XT5F# +V?X06bdQHlrU^&>~> +mf*jpm*(7Pc(Ti:EGB$*LS:ubr5er`rRLr+*U<(NY'IS+IY.Irs8Vr]`i&+DRtH*M]&:E3iV3?6 +rtC+bo[oo,eZ=UMM6#1qC3kJbL&_()s8N)Mr;SPLn'@TndAD\?@9dDeDd61NGDi`Zi25/to]!Ek +jM6t.CN"T^X,q^BA9Ws:g#/jap&4mi&,u:[YJ];1OF1b\Jt'm4c2Pfb_#CtFX8o-sRfJ`PO9VB& +m>BH;r:Br=~> +mf*jpm*'_Ajk\J7c-*iHf%o9Cr8[k>rTF4Fs6L]XVJ3ThCiK:Ns8Vr]`h;\Zgsjd+iT[kZiV3?6 +rtBJPo[oo(kMOn;fAGcW=D2YpF8u/Zs8N)Gr;SPLn'@Kik2+\7Z_bUdbb]s+d+I:?fr!Emo]!Eb +lJgOHbKSDghqHN$^ +mf*jpm**&]YaV8g]>hq$Ssl@Mr2ft'rO)[<*Q6+E[^EZo_oMZRs8Vr]`j!C`Q_UUKVS'pUiV3?6 +rtEQRo[on^[@`trSY!75YeS6$b5_C^s8N)dr;SPLn'@cOZCIMq`l-!+^Vmq/Z(%GrbGNq_o]!Ep +^SmHs`P8I@SsZS$aK_5.\'1i+p&4mi&,u:[YJRrLQ`J6BUR/*jYl:a)W;`[nT)bD\QN3 +mf*jso\XW*i4kqFKmn5cF+oR7r0m\[rN-%2*Qc^^kO,mVFFV)rqYfrV[VW.VU=h'cg:)O +VVp.4N-K8gOLhF&OF1bbM6#1qT@EH0rr3N.p"ZS*fs-K\AR'/*S#i=_RfJZOOT((:L]2o+JGsp$ +JssdGQdEnQoDa=~> +mf*jso\X#cl/LOPe^DghcILS$r7h;.rSRY6*TZAHlg1mP@qtN0rr2c[`h;\Zgsjd+iT[kZiV3?6 +rtKPQo[oo(kMOn;fAGcW=D2YpF8u:=F8u7?d/Eu#rqYfrT'YOneBFf.dFZmlV6S=shWF0ocg:)O +VV11kf[.jjg>T*kg="-ifAGcWT@EH0rr3N.p"ZS#kht+?^ST0(gu$reh#5t+f)XD$e,[tsdKe:W +jQq`M`;K6,J,~> +mf*gro\[+"]Vq9eTr>6.\"T;gQN3KQTDtc/Xg5FQb.ja`_=7=#rqbs#Yf*Z1UT9cZ]Z.>;p\s=T +'[$CHfV6TtT:E9ZT!ceH^W4L>s8W&?s8N)drVn\Qq<>f"`3#B$^;\3sSYNp;`jhY2ZH8iem-`K& +bdX:8Z+m?,VQH__X3.f?T!ce7eFNP:rt#,%goAT-Tpr=.`4i"5T:5bG!1*VNrgWt[rhBIiri6:! +Q`\3@d,Foos*t~> +mf*aqqX/WG_W8tMTTY4eK)U/qK)gW(M>rYXS#3I/dH'5?Eng'ZrVGj"Vs;BnK7&cli5)eZp\s=T +'SZMXfV7ibXGM(VX4?ZRH@gg(s8W%Os8N)MrVn\Qp>NEti4G(uC2\BXUmcmR>]54_aQfSYEIhXGM(0;-\$lM1tq]!.Oops)n +mf*aqqX/!#\*E)6h:gN3eGdnoe,\%tfDjPFgtpuLk3CWD@,(/HrVGj"T^:apeC*(0l+"+Zp\s=T +'Qa6FfV7]phq-3+hrj<-BQ/$6s8W%=s8N)GrVn\Qp>NEll/C@EbKSAebhU^lV9IHEjQrJTjQ=OQ +mH*0Sc-k>)l$'>ig="6rh<"$pbjPB-rt#)$g8=3!hq-2bI\k9 +mf*aqqX2)'ahP'TR[0G:U].=lUB%"dSGnipS>!!h^Wa6tg[G";qWl/*`3#B$X-fcs`jF_!roX4p +b5LtbUO`4i":U&LeeW;`jt[/R*+VZ*@iSHbFb +`4sd\r:Br=~> +mJd^qpj[O*\aA4t^TjH#OH>CuM#`>1K)U-iS:Q2[6OWs60& +oPWI0rU^&>~> +mJd^qphaVJZ0gc:io&YJg=k3Wf)XD$eGdl:eCN:,hW!bdLUu=4qYBHsT^:apeC*(0l+"+[p\s=T +'Qa6FfV7]phq-3+hrj<-BQ/$6s8W%=s8N)GrVo=bo%0_kkht+?bgG,&R&f#lbfS;eiT\"^g"Np= +lJgOHdb<[El9quCiS)`0guRgm_Wgprs8W&ifq[lrhq-2bI\k97dJhSne,\%ufDaJ(g]$"-hZi', +lWi5drU^&>~> +mJd^qpr'kP^;mghW1fZHR$aB@SH,;]U].;7URms?S>`p;]t3%jqYBHsYJdQ0UT9cZ]Z.>s8W&?s8N)drVo=bo%0_]\"T:r^TO!"V5]fV^<3LDVS'gRg"NpK +^SmHsX-fcse=4FiVO+?YQ`\3._Wgprs8W&ifqZd!T:E:/^VmmoY5YL$UB%"eSc4uVQ2[-LSd)(4 +gp>etrU^&>~> +m/IRoK7A0UL=#>Kg!.UL]!;16!2faa+HVV=HujO_LQf!flD_V\p%[glVWu9mK7&cli5)e[p\s=T +'SZMXfV7ibXGM(VX4?ZRH@gg(s8W%Os8N)MrVo=`mE;6kc(Ti2H&f>hKr2t]Jo>jkZ.\'2bfcd> +fs-K\JssdG_-N&cad[p1OLjAg\E!A`s8W&ifV7ibXGM(0>]54NNrG.>RK0#[X8][1`;[jWeHXt! +QZ_N>rq$/?~> +m/IRoEG]?tGK9+9kiLmaiSaXk!8d_1+PPN"da$4gf%T'Dm%_DXp%[glT^:apeC*(0l+"+[p\s=T +'Qa6FfV7]phq-3+hrj<-BQ/$6s8W%=s8N)GrVo=`mE;'fjk\J3dFmLBHCj3QeBH:li98jibfcd7 +kht+?eD0-O\4hD=jP885g>V;/\E!A`s8W&ifV7]phq-2bV9IH@g&B_)g]610hu;R7j8S-=k6C2< +M.>bmrq$/?~> +m/IRoaMbg%\]`%.\$3!3VP3pZ!1a%T+IJRhX1,@1SsH(S`3R5?p%[glYJdQ0UT9cZ]Z.>s8W&?s8N)drVo=`mE;NMYaV8sY*l&rV6m@kUV="&Tsr7Abfcd* +\"T:rUR/+$_kXWXXd>f`R&7O6\E!A`s8W&ifV6TtT:E:/`4r( +li.EIK7Mg$DMG[ZmHWWfg&0A#dJh30]!eJtHt[AE%jhRtGd;VU=h"]==F! +c(Ti2JssdGS7RiJad[p.NjdcjXPNRJs8W&ifV.caXGM(0Dh=FY[f3l;a8jKaec+J,kPjcGmfg[e +F+!T/o)F4~> +li.E8EGjWC>^*F*mHj*%kksTDk5OHAi?$k0d`TeZe(EO>g8!$]p$'Gfm,ZsOdb<[E\@(>jroX4p +F8ba`U?h""f?`(+kNc5`E-$+#s8@$=rrCFFs$cq^jh7MVj4i&1g#;/[97H6ggsjX#hWF0k]==6q +jk\J3eD0-OQ;`J'jP884g#;/:XPNRJs8W&ifV.Wohq-2bbgbG*rSdb:!9O4CrojFKrp9XM"hf1j +C@faAs*t~> +li.F:aMm#I[(3loa2GX'\,fcRA7@7XPNRJs8W&ifV-NsT:E:/^S@-eU]..iXT5U)[Jmf=_Z%LQbQYtt +\\[n'o)F4~> +li7!=$\\/%HZm!"Um/^2i;E$Dmf)Joi8)elOF1bNCOVG]jLD\VnE7]clH,NJI#tqt_RAM"roX4p +L&LYrU@6X6M04ZUeaI7!JqSjXs8@ZOrrCXLs$ltZgo\u[[Z5ZaQ,Mk5ARFoVXGM(OR`OceV4b6W +^ls4rP/$)KPAFh!eZ=UMM6#1qT[iW2s8W&heXl6[XGM(Z@3l2^5Nmgm:N_4m0YQCDZ, +]Q\dTqpk9;J,~> +li7!+$ZblVBk=lTT8'h`g&117llbQVk2G%Bb-T:>g>_D%\)6]<_k-5Ugsjd+iT[k\j7rW9rtKPQ +o[oo(kMOn;fAGcW=D2YpF8u:=F8u7?d/O&7rUemIb3@m +li7"-$H_qY^q@7XXh;`qqof&^rkoql]!A3#X3/H$W0XBs]slngkJOI@Xd>f`R&7O9[c@/^k5Q.< +rUea:bdF(5[%3erbcnk&b0'barQ>0?!:Bdc7fDu7Xi\/LRBEEPX2<2WV9H?>S@#&XXi.38TY%t; +QDgaJW5$rJZ)Z$UT:E9ZT!ce8eaiYT$4U7S@$&+Q`[[,rk/6K!6>)_&&H?.^q7:oS$963 +]Y_\cmIL:-~> +li6s<2#W&YJE5FsFE)5@ChmdZBqD8fTu#(Ci4G(uBjc";VU=h+cfjE(U?]jiK7K6*kJXplq#9FU +'SZMXfV7ibXGM(VX4?ZRH@gg(s8W%Os8N)Mrr6C(n'RfrdAD\?KqQ]XTl+Jgh6r>iI#tqt_23g5 +eZ=UMKqQ]X\#XO`i7YAoG_Mg8m@_Yiqu?]on^ +li6s*2#VE5DWKN]@UNJQ>$4t$=.>q=S%$E(l/C@Eb-B7ChWF0tcfjE(SF#=leC314laaReq#9FU +'Qa6FfV7]phq-3+hrj<-BQ/$6s8W%=s8N)Grr6C(n'R]mk2+\7e_T?SP[7>0l/C=Cdb<[E\VYt) +kMOn;e_T?SYH)&5g$%AHd+-t6m@2;dqu?]on^ +li6t,2#YM9`T5ar\[SrOZ*:I+Y+i57WlW?)]V_$rai:i_S?g88cfjE(X2M-,USas8W&?s8N)drr6C(n'RuSZCIMqTpi4+^oONY\tb[rX-fcs^km]f +[@`trTpi4+^8n`HbI=17Z([Vja/I2Kqu?]on^ +li6s<2#i8_K_Y2kIsud#H[:"iH-j`V^2IeN^Yl_cHtd>EP/$(g^YmtZ`Se@iI"Ig.lD;5Xq>TOV +'SZMXfV7ibXGM(VX4?ZRH@gg(s8W%Os8QW\s8W)ol,0@_ad[p&KqQ]XKQ_1:jM6t.GDi`ZheJ;= +ad[p&KqQ]XT"oMd_r/.gI"7L#kH2M^q>UEkm`hftad[p7R`OcP@;2l`EH?5FcZsikhL'a#It3(> +JqEcNKSBHWo)F4~> +li6s*2#hW_D'^YmtZ^$4M0da[(5m$YTNq>TOV +'Qa6FfV7]phq-3+hrj<-BQ/$6s8W%=s8QWVs8W)ol,0+ZjP880e_T?SFCn^QlJgOHd+I:?fP6?2 +jP880e_T?SR_WK>]BS;.daQt2l_VAZq>UEkm`hQojP887guRgM:fsl,?t!PUcY$qGhJ6nCD/O:^ +E,kYnF*%B.o)F4~> +li6t,+TKU,anYMj`5BI1^q[Y9^TOV +'[$CHfV6TtT:E9ZT!ceH^W4L>s8W&?s8QWss8W)ol,0^CXd>fpTpi4+[^36X^SmHsZ(%Grb%dEa +Xd>fpTpi4+VnfsO_n;k5X/;/__R@5Bq>UEkm`i,WXd>fXQ`\34Vm!82\%'#]cb@0KhSR.I`5Tad +a2n%tb0'bOo)F4~> +li6s +li6s*!<<%>#6+SXEcH)Lrbs4VDt*13kA"YEV;]=)D_DNVU9'aYj16%e'ct/l+=7YpAP!fm)c!gjP887guRgR>@lQ)Ci+$,n8E:=pAT(2EWc5\ +F8l/[!WUO;s*t~> +li6t,!<<&@#6+SkaiMQJrl6AX`piE7kJ=mIY/e2PQ`J62RA7@8YLhI8`4Vt6X.u#``4s8W&?s8Q*ds8W)li3U>6VO+?aR&7OGY.D'T`3#B$]:k[ta*G"q +R\@fXQ`\39ZFnr/_o0L4nA`NApAW/4aTMI` +b5VC_!WVQXs*t~> +li6s,dBKS9@(qh51QKn]P\ +rr2uLo)F4~> +li6s*!<<%>s8N)Wrc8'lrc9CaF8YoUq/L?3@T;"Di7QE&fAGcWU!D2o]BS;.da[(5m#&dIqW7_k +F8ba`U?h""f?`(+kNc5`E-$+#s8@$=s&IGGs8;H=U[.+#f?_q#j6O-YEb&8;kMOn;c.1Y3RH<8T +c-Fnsk3T+ZhJ6Snm,ZsOce%(;l_E&%r;QQYa.Ve[gsjj/jQqS/C[uK?q>,.0F*%?[qf;o?F*%A& +rr2uFo)F4~> +li6t,!<<&@s8N)jrlP5frlQPcb5D.Yq8gS7\Z/52b0'__qoT'Ab0'b, +rr2uco)F4~> +n,ELhr;-6gKE2#NL&_/QjSji5PQ$7^s+ULQL&Zj[nTo&VjM6t.EJ:(1mA%_LYf,J3OF2YKaQf/4 +lh]`C'SZMXfV7ibXGM(VX4?ZRH@gg(s8W%Or;T@cm)ksfc(Ti2KqQ]XUN2*7D9q%HNd>>XKqZbb +KlLLALSiJeHctZ'GFn6MVMB5HTZuktbjG<,qWl/!lH,NJJssdGPf8.JL&V)UL&Zj\s8VtM!rmt. +r;QcJo)F4~> +n,EXlr;-50Ec_6ZF8u7?i;RctKDop +n,EXlr;-62aiaV^b5_JAoDZl4d/M06s2tBAb5]W+n\;BI^SmHs]:k[ta/m>/Yf",NQ`HmJXi.fj +lh]`C'[$CHfV6TtT:E9ZT!ceH^W4L>s8W&?r;T@cm)l9IYaV8sTpi4+_RIFsZHKhSRBFZDTpi3S +Tt87RT:E4/Z-2CM]VEWTS=[3`R]si3bjG<,qWl/*`3#B$UR/+$]Z%hbb5VDEb5]W,s8Vu=!rpEc +r;Qcao)F4~> +nc'.!r:faIk^J&6q1OHUs8V0ZK`I>9KdHbQs8RfQKn]8LEKTP.RtGX2R`Ocm_U#F'i4G(uJssdG +R)nXjjo6$KrUea:n("LrFc!0LmqR0#KSBI+rIt4M9)eVI]Xd+=PC@M*TZukXG)CZeZK/fbIVW80 +KqX3??Yk7X`95Tkg@9`?VXN':M04?6`948;kP>)Qlc,jfad[p7R`OcY`ddi=rr3.Us+Q1,s8.KO +s+Q1)rrCX@s*t~> +nc&ppr:faIk\Y3Vq>PI8rrD!VEr^jlF!^j-s8R0?F*%(k?\Ie,gsjQtguRgr_U#Etl/C@EeD0-O +Mob8]jo6$9rUea:lf[0Wce%(;lW@h>F*%B]rH%r;9)eVI]Wg\\g=+)Qlc,UajP887guRgV`bkQnrr3.Cs)W8]s8-j= +s)W8ZrrCF:s*t~> +nc&ppr:faIketH\q>SP:rrDZiaoKffasI)1s8U7Ab0'Iq[^sDZQ_V9iQ`\32_U#F']V_$rUR/+$ +]#a77jo6%;rUea:bdF(5[%3erbcnk&b0'barQ>*=9)eVI]Y;.ZQDhEhR]siB]>qdt`kSI)Qlc-0IXd>fXQ`\3=`l._rrr3/Es2rLas80q? +s2rL^rrDHWs*t~> +nc'-soB+WF^iO[Fl@O\Cs8V0ZK`I>9KdHbQs8RfQKnT/JE09G-RtGX2R`Ock^s/sui4G(uKqQ]X +R*+gnjSonlo[oo,eZ=UMM6#1qU=b'NL&_2OL&M$DrUo!KdG;6kH@1gci:1T.N.5u(mEM>YEF3$l +KlLI-F,-X?m]V!!p@Wg>`8J7hI!h$ei5;eUp&+[P`hr%CRtH<]aQf#0J,4lurrn,VKn]R,qh5+O +Kn]I)!7p`@J,~> +nc'-soB+WF^gUbfl>^ics8V$VEr^jlF!^j-s8R0?F*%%j?\@_+gsjQtguRgp^s/sll/C@Ee_T?S +N6:PbjSonlo[oo(kMOn;fAGcWU=aF+F8u:=F8c,2rUo!Kb3@mJ>QrrmKDF*%B]qf;i= +F*%9Z!7:<:J,~> +nc'-soB+WF^pq"llH%)is8V]iaoKffasI)1s8U7Ab0'Fp[^j>YQ_V9iQ`\31^s/st]V_$rTpi4+ +]ZTX=jSonlo[on^[@`trSY!75U=dN/b5_M?b5M?4rUo!Kah"78Y,dqe][X1"b/Cp%a0;#+]#DY" +Tt84_\=]:sagnqCp@Z8._n;k5X/hVb]Y^o0p&+[P`im=_Q_U=BXi.ll`;7XUrrpRFb0'baqoT!? +b0'Y^!:B@WJ,~> +nc'-kiPqq)a2=clc$k7ts8V0ZK`I>9KdHbQs8RfQL&18gCp +nc'-kiPqjt^:9S9c"q??s8V$VEr^jlF!^j-s8R0?F8G@U>,:HCg=+9qguRgq^rr^gl/C@Ee_T?S +IEq!WR6>s%<4Ze"5mghq-3'gZ.V.?#"k-B3FQ`hq-2b +I]UeqFg96ChWF0pEUN\uCquq6j4i&/fAGcWT[`N/qWl.om,ZsOeD0-OL;n*,F8l1CF8p<&s8Vt; +!rm=_r;QcDo)F4~> +nc'-kiPr.7`lc6+c,7TEs8V]iaoKffasI)1s8U7Ab51SWZ,=>TQDhQnQ`\31^rr^o]V_$rTpi4+ +\'FI?jSoeio[on^[@`trSY!75U=dNbrr<#@!WU=@s%<4Ze"4dkT:E9cQ)hdF[)'u+^9GhhT:E:/ +^W!e'^;d[TS?g83^@(jm_n`auX-KNgSY!75T[`N/qWl/*`3#B$UR/+$]Z.ndb5VDEb5]W,s8Vu= +!rpEcr;Qcao)F4~> +nc'-^a04poi8EeVW-3ZCrVtsXK`I>9KdHbQs8RfNKC@U-F5>6@LN@BcR`Oco`65"GeZ=UMM6#1q +DU\.Rp&>V90o[oo,eZ=UMM6#1qU"4elrVc_LL&Qf)s%<.Ra/A4ERtGX5TZul! +F+3lVHuHjZ]9%DS=&!$r>&8_S`95UOL@kE@JBOYRc(Ti2JssdGW6"<#q +nc'-^a/J@jl07NeV.FL`rVtgTEr^jlF!^j-s8R0V90o[oo(kMOn;fAGcWU"4/ZrVc_:F8g7Zs%<.Ra._k\gsjQuh<"$i +@;P]2C0e=5iS)`&P&IF@T$,U;j6OjiG4b_0DTeR;jk\J3eD0-OU<)Zrq +nc'-^a10:/]Y),+XLuKmrVuKgaoKffasI)1s8U7>aR@orYfV90o[on^[@`trSY!75U"76\rVc` +nc'9SXPhXI]=Z#7iGIaturhU/3UF(T]X[b^G5bKQ^LeZ=UMM6#1q +E7a^[q>V!)rVQEao'PZ(l0e6@rVuorrb)3,n^X9#eZ=UMM6#1qS'QTTo^qg.K(aiorVlfkjh&%` +^ls4eKqQ]XKm&"Cq0mFMlH,NJDd5q0:1/-uVU=h8^P_gcr.3Fnn("LrFafLgjL;_]p\F-qVs;Bn +K7]Q5lBK; +nc'9SWnHRqiSih\fii$+qYoDoF8pmlF!^j-rqpd,Ct6(]g#h/BcG\,`iTTQ_bKQ^HkMOn;fAGcW +@+Y#Kq>V!)rVQEao'PZ(l0e6@rVuorrb)3,n^X8tkMOn;fAGcWS'PsBo^qfqE;";KrVlfkjh%_] +inDl+e_T?SG%>Leq/'Sqm,ZsObbf&mFg96ChWF1&^O#\Sr,:/\lf[0WcdLP,lE@e[p\F-qT^:ap +eC<:7m"WMsqK)Z9"`s]bF8u:;EruA_F8Z% +nc'9SZH9MTVP^E'bd+t%qYp*/b5]ifasI)1rqsk._pu;gaKh>-\&ke@UUnmMbKQ^)[@`trSY!75 +Xk31Cq>V!)rVQEao'PZ(l0e6@rVuorrb)3,n^X8U[@`trSY!75S'T%Do^qgsa7dUOrVlfkjh&4@ +W0XBoTpi4+\@]`Vq8BhV`3#B$^;[e"^;d[TS?g8I^W6-Kr5R<^bdF(5[&B:h^V%/=p\F-qZ,Ec2 +USF0X`4X+.qTAg;"j6kfb5_M=ao_Ucb5D8>mIL:-~> +nc*OK[-uPGOH>aGkFupAn+bmrL&R9iKnT>Up@*O`FJtS`dAD\?@;LIZ`95R;eBafVeZ=UMM6#1q +ES:!_s8W)trVZNep@@V6hpffb^;J=Un+chXq=jUUo^V+fQg`J+M04ZUeaJ@(GLtL"fm7s@hL4ea +qu$0FYL217Nd?)7]&<*nH%GnjJ9ZA-dAD\?@8BKj?uq+#dI*XPNVi_RK&3]Ii4G(uH&f>hd&Ypm +q!?,$lH,NJJssdGPf/(JL&V)UL&Zj\s8VtM!rmt.r;QcJo)F4~> +nc'9DXR#',g=k +nc'9D^Wa*WQ^[p@,uP\Yu4BZCIMq`knUVYab5VDEb5]W,s8Vu=!rpEcr;Qcao)F4~> +nc'9;b4!l]M0t)UdGB"cfBCk=p@j[JJoL1-hpQSFL!f;8VMB5$?uLXcaQfS"h9hk`eZ=UMOLjB? +F4p-[qYBp[oC)#,hUTfaYbA&-`lG$ifB`%tki(=Mf[S$HJa_-jM04ZUeaI.-BVD/pUMFYIER*V8 +q"!(5n("LrFaT:^i4s2VK)PX-JpVC^h6r>iB2q?'Ck.ehkL-KfO8]+XKB9bOjM6t.F,-X?m\%qq +p[6;,lH,NJJssdGP.uJ@K`:rSL&Qd[rr)_I"T*k*rVlfr!7p`@J,~> +nc*F?_!C1@f@&7,k1O9PfBC_'p@j)WE,b8_hpPr4Fis+6hU]uYZ-:_QjQr5-h9hk\kMOn;g>V;] +A(gGKqYBp[oC)#,hUTfaYb@es]t^>SfB`%tki(=Mf[S$HJa;LVf?`(+kNcc;5+lc?3`J,TEHETOj1lJgOHcIUk7m%)Ml +p[6;%m,ZsOeD0-OKthI!F8l.BF8g6%rr)e:s)J8>EcV-Xrr2uFo)F4~> +nc*F?cciegSZABQZH'5YfBDDaVS'sU^rQEPa2#%)\tb[rahbO*_PWU!_U,F?bl.S@aQ:(S^SmHs\=]:sae[;P +p[6;5`3#B$UR/+$]>)8Yb5VADb5TQ+rr)f +nc*47am[c\M03lpVU=7AX2DYthr*F?He$BWZ(@3,mG6$aLN?m+F+Tk%lJl]gjO'LdeZ=UTOLjAd +Ems7=lK@0_f?_FIY+_Mj_scmOi8F"D[FF'`_m?>F,-X?m\IV[OT,:[K^6^ElH,NJDh=G!lD2;\p@-Ohn("Lr +IZhJ,YdAcGK(o!4K(X_Io^r*6$A!`qJ:[ChrVliJo)F4~> +nc*47_!C1@f?_anhWEL#X2DM_hr*F-C":JEZ(?]lmHN`hf$:UhcICY1m+PXHjO'L`kMOn>g>V;, +@ajQ-lK@0_f?_FIY+_>^]BehKl07TM[FF'`_m?>EKJc>]LEpLf%m,ZsObgbG/m%2)Xp@-Oblf[0W +db<^GV6jt*E;0)"E:n0ho^r*$s)/22DK#4DrVliDo)F4~> +nc*47cciegS[>kuS?g5>X2E2thr*G/^t$]GZ(AVMa1ALFT!u_W\>,Cm`7D3;jO'LA[@`tiR&7O3 +YLD_%lK@0_f?_FIY+_f&_p$'6]Y);*[FF'`_m?>fsUR/+$Xhs;qnC+,U[@`tf +QDhR:[(u.Np\+=$ouG,Fo_li1`X)"O`qB0+rr;BVs*t~> +nc)Y-^$jLPM039KLSiJe[@<=qYHkHOCnR8m`:*!Ic*j=$F(&HcF+Tk%lBlY.kg#aedAD\HOLjAb +CqIj4`P/a]U7J-idI6Jci75rb]=Z>NZ*V*B]]&eWs69m3RtGWa@WdO/pXLeMmB4Okk/aLdad[p$ +JssdGPB25+rr7Y%GB`K&VMB5$:LJ7!VU=gVcgHtqs!`WjdV81#XGM(IOLjAf[,CTIfTP^RXGM=d +]&:>mFOtothVTGi%`Xqu51;s*t~> +nc)Y-[-Qo4f?^qOf&#QUXI"rNYHkH=>+h:S]BehJjl,%HcEjdccICY1m#,>akg#[ak2+\;g>V;* +>eA/$`P/a]U77dYb3SH\l0%-eiSinaWjB@;[+YBCs6L$PgsjQF\BidapZF'kmAS+ek/a:`jP88/ +eD0-OKjnn=rr7"VAS1;khU]uYGHoHEhWF0;cgHDas!`!XdT>bthq-3&g>V;.[,CTIfSo.Zhq-<1 +iT[b>@b5APhV;huBP?&Nrb)[PAnB.sBAVqGqu4t5s*t~> +nc)V,`lti^S[?GHT:E40\tl%*YHkI?ZCmnn_p$'1YbRYY\&QG.\>,Cm`4NS3kg#pFZCIMeR&7O2 +WOpDIV`!EK3UV=^f[%3f_[4Ai/\&dXmaK`[cQ_V9i +Q`\3<\\uSgs2i6mZc]SDT!u_R`jhY2ZH9H!ma(n4.EV)-Y0=;GS@#>aVS'gRi:QTmWQ_cBS?&$S +]Z-GOf>6A$gq_UX^Y%3<^C.ch]Z[t%hWjb1rpB:VJ,~> +nc'0HRIA\,M0398F,-X?jR)E^rkh(MNmZ&Ep=<,[AWaQh5lh=Qm0s!`WngMGg$Z&EpMM6#1qUt5&,hO2^G[Z5Zl +Z.\#UAuBONY,Q33CMTZ=rb;gTBU>]aLpG1^o)&FWs*t~> +nc)8.O6budf?^q3cIUk7lL!oX]">S_f^%njl0%-dh:^?(^<=gJf%8gB]k;&rlH>shjP885g>V;& +:Q(I3T;B3Blg4!'l0%0giSWGig'?U#acM\=lKJ0/s5XI@eBFe;MR_!apYRL[kh32lh7oNIjP88/ +eD0-OLLb:Cs8R.ZBj03Ri7QDkMTjT*jQsunh=Q@!s!`$]gKN:oi7QE&fAGcWUt5&,hNQ%FiRuW2 +i98d6<2X!*Y,PR!=]qJnrE'D-LnfcOZHD.squ60dJ,~> +nc)Y9[*5qLS[?GW\"B1r^W4R@_Sa:4bfn5J]X=l:R[KkYaMt`sT:MR]^pLo8lH?NPXd>f`R&7O. +S;WWfs +UR/+$]t;8*s8U6^^p;1nTpr=._7ub3Xi/Yoh=T(ns#A0ngTo&4Tpr +nc'0VN6pChNd>MP?uq+#^s1EcrSSpRe^;LNXIG6(H?!kGIYWcWX4>"cJq))3aJeCGRtGX,OLsHM +n,MYikMY1HdE024XJ(o@M1^8)MlYCsFL1&DZ2C^'RfS.[raGtABP;P_M(>%9lEJOb\AdC +nc'-UK#m38g!S!WZHh%XioTA$kp,ETk2bLYgtC6*c-4M^f%8d9kI7I4D92%aU?psreBH@piT^@- +s6LTgl07BnjPo.Uh:pZ8eC2juhrj +nc'0VZcp"URBFEJ`j_P0W3E\@rOaAa[Bcp3T9kt>Y.DBTW1TWNT!cJ9^r5@#aK`[cQ_V9qR&7Oq +bl>Tu_S!IfZE:(#T:2%3S>3$`S"@%3FLf/bU&:P_QN[E#qWQ`I`lR]si4bO"i\\B2C\Q`IB\ +Tsr7iaN268p!!ER#04rt_rC@fo)F4~> +nc'0cRtpCUVMftKDeO3IPG,(drOX;ZXJVJKM1^+oFaSdtP,>;-e\H%JMh9@BaJeCGRtGWmI#tu> +ec3`.`4NIZVONd0M1pJ-Fa&4bMne?DB^aKQN;SP4K)foiFT?^[Hn9lHdI+0[e?m0P]9%DfOLjB? +CjL\ds8RfLJ9?_9c(Ti2A:Tr`kMg9&nbeUMruZskl#`9Wad[p$J +nc'-bOa-9ThUp<(bfS/]g>1Zai?R:W%o +s5Y$WiSi\NgtLH5e^Msmd*gFrip,fBlf[0Xr7Ctu!6tJg!7CJf/C`P=m&8(V[(PY^g="F'iT]W2 +BlJ.ns)\$SA:3e+h:9cae(`pKfii%Yr.G"K*cq2B@Z'O5gsjQsgZ.Us^ut@SV2"?tgsjQpf\krU +rTX"1kmJ?DRJ,~> +nc'0c_RddlS=?C\^WO$WQC=G@rMCg5T:D77S>36u[&]smQCOPP[D]AsaN3T2aK`[cQ_V:;X-]^_ +[K!?GX/;YaSfsVNn4![_V(ul,(-PXd>fsZ(%Gp +[CZ@MosOe$#-bSWZ-Mb5o)F4~> +nc'0mWH+9hdBSspJp_c`IYEW=rK&7_M2-_2FaSXiM3+1,^X:TgUi1MBOG)'LbGsjLRtGW]Bmc$A +XT+b,Q&q#_LP(&%Fa8@dLP_+]X2!`#EpqP[M>_f(J:`B,rJ:N7oT1T#dI*ONf!WHS]9%DhP/$(r +Dg[1ks8RfNJU2A*eZ=UMFb#q%lD8QNp\pBUruZslmWXTVc(Ti2I#tqt_m\Rsn$RH/dAD\?A9a'7 +XLA,?orS.^#GJT^e%=]9rq$/?~> +nc'0mT4!H@k2>"HeC)^he(*('rRrLKf@JI"cdL7kf@o$;io]FXT3Z'nJ9&m$bG=LcgsjQ8b0o#C +huDIKgY1?4f$r0rcdC1jf%8X2hr_D0 +?>FP%s8R0 +nc'0mcaUU+ZD!PQUT:Z/W1f`LrKeauS=ZLV[&^.#SX>b8W3WhNX0fS)c,o5;bHo-hQ_V:4b,^m. +TDt5pQ'[o/Sti6e['$I)T:M@9SuBEEEm1q`SGfJjVPBo[rLEqVoU%/!ZH9;rf!WH/VO+?^QDhR: +[DL#-s8U7>`kS_$[@`tr[&01l`4rh"p\rP=ru]D\m_$$LYaV8sX-fcs_m\Rsn'&2^ZCIMqaK_5, +T;2C_oq25M#F_F!b.Ha0rq$/?~> +nc'*rZ?pShmb,O`RZNG_Jq3]F,(P8sLP_+UR]F$@e`?/&Uq_5+pQC6[nC"9&c(Ti0C1q:.re^Z- +(k@![H$k-oLP_%QR\m-saOTA/FcG>4Z','I"-o=DT`(nk[e.-]aOSk7gYKK]i4G(uI\tN\]5rFR +L&_1,re#WFZK/fbM2@86lJlo1Jc#J2rr4'orUY>Wi7YAoG_1dQeaKa"o^on;_Vi%fIWojXM2@8l +OS+J0K*R76eaKa"pAX[`J,~> +nc'*rW+fV4m-*KfgtLE3eC49B,1G&kf%8X0gu%)OkN_E1U;(AZpOdP4nC"*!jk\J2bK7lSrn%2" +(Xpg[dF-Lnf%8U/gtprIjQGg]A<#:+i;D:2gYCT?rSR5*/*,m +nc'*rftb&#ag\=EQ^F87USdmg,,V-1T:M@8Q_((V[D0huWP?3epX%(KnC"P]YaV9#`lcH)rga"` +(o=:9Y,eFpT:MC;Q^jYEXgPpcZ&Qu:TpGYE"-o4>Rf/fXU\(E6XgQ]ggYKK\]V_$rW1:08`4 +nc'*u\:Aq>T&AebaL\XRR[*`2+-i:`VQ7;CaOT56hQihocf9S/rKDrco\?(sfs-KfIf+R4J:`B, +M2@7SQ("SN[^sQ-e_o`LZZC,kVru=>rON*LaN2X)eH"Fti%+*MXL%-P`i\FBQ&q*)dI*cSmt?Dp +s+UK+J:`(7dC-*V[`Ia4I=?hJs-*H^+GKgiIXAK`^lsA%TXs(OZJbHOaEMptdAE(bLOsu&I!>7+ +!."Qk#_8APh=.W*pAX[`J,~> +nc'*uY&A$fS([,kjPf%RgtV\Z*o#K*hV[;OjQGdofqt?Jcf8q`rI]1;o\>qhkht+CqpHG4eC<%# +f@em4gtprIiT0.al0R*$@pcL1lfI.)i/*tuiXm"ldU[-spg=kEGm%J%[Ec_9\ +F8p8uEbXn&iSWPOjQrUXCiTISKDtljF8krNCT?[Zg=4X.iT]X5i:cr_ASLMnhV-W5eGdkrd.P]b +dJhQ"e(ipGlEB+=rq$/?~> +nc'*uho]#2Vgs3UcF+Nj]Y_mm\#W0X3RR\maIZJbHOhn6A>ZCI5MT;/?cX0M?) +!3Z=%#cpAX[`J,~> +nG`s0KRr(&CnoqRi7ZN!`;7%e`5p$Ie_oNRn&(E2ER0%"p4S/"PD.Q^kH_PW^oNoer/_k_R[TnM +X1#UXaO/Poi9Kaf`2@ZsK6u$j_sQO`hui0-lL"Q=!7:PW0Z1`C`58R!cc#GDeW'"E`4EP$e]#+I +p4S/"s+UK+Jr+Q8mG6=Ch +nG`s&Ec9mW>*dk.l0.9jj8.^Uj5f:`kNV9ulb&!^@*`TTp2Y6SK6,B6kH:lNinrPgg)Jf%gtglF +iSihXk3(smm-NEPaL8PS[kPG'\%K5IB@"<`n(!$Vk2YFZjQF7g +C\Dgjs8R0?F)cJ7M!aEhkNM9I[WZS0s8R`Lru1cQF)p!si8!,DiU".jk4nkrCLN%ck2P=Uh#?"- +f_*hrg&B\2gYCcSah$R.rq$/?~> +nG`sVai<8[ZGFc']XP2KX88\8X0&M0[Cj8mbeq,t\'MnXp;tJWd)tbNkJ>0QW1K?Ar0SFgQ^=/4 +Sti0`Xg5@G]Yqq6`3HPV^qeC+b/_9q]E?$h`5hi#!m&F&qoCJ.aN28S!1EhR#aLaO`7) +nG`s0KnT*^H#n&*_;ObHkPF*YkN_@#n%cGuC:&,:II;^`rIot*PD0&7n\fXgjOM>dr44>qaN2WV +e_T0HlL+,e_53cF\As8ONIgDKEJV6G_84'kPc0=NC29cLDYe9*[;^)AF0C>achd@tO-f:ti8EnI +Y18(!Kn]R,L&Zj[NdPo(dI6POQFPP*K8'@*PPkG%rI]rTRd/SIaN`Q/HID9ZrmQFFEL#tQg!RmU +]"50>WrTU-\d-0pe`rLFm/$;QJ,~> +nG`s&F)pp:B45;E\(L'6lh]iGli-5ilaF$Q=L;R[C[Q0[@550XY4nI:9*ulcK"sk(JTXlfm[# +afa04qK$`Xs)\3]Edhb3Gf]4:aG@@XI;s?.s+C7L*rU))D2moGjQ,FdltXu;qu4iYBjZ\_lKIBk +io/kSp##`,#NOn.m"rsQqXXZ:~> +nG`sWb/s;>^::DQaNVcE_YUne_SjC7bf@E1YdD!X_X>J@rQ<:_d)uCdn^Fke^U:2Br2(sEXf\h8 +[CX#f`6$6HaKD;B\AuJ(b/Wba\%BGoaN2<-]2ss*t~> +nGa!1Kn]L#JUW9nEGTluXi^IV+/5QrTVZS?Fa;npNe@4^s8Re,s-*K_rqY&rDmSotjS[pakN_@" +n*eT=U6Kk;DK3VAL#_KZK9Co_NI5ug]5V`#^N@SAG^=\jh>)FPidH6JI`RTGec,I;SooCU`knis +e*;SaKn]R,L&Zj\Ob%q)EGi"#G2;SJKSBI+PPbA#qi6GYXPrI0mEp6&k4eiSeV&L#F*Y(Lmcrlk +i7[eR!8[Y4#NtC@V/kMdrUTu=~> +nGa!'F*%7+s8R.]s+C@OrqXo^?)[)UlMTlqlg4!* +lg)U#Q%ipS>[PFrG2qn;EIr6+I;3B3]3epV^LG;rB4tu5h.le%0]Hk`P\e3dq9T';o9*TuR(g). +?IS1ZrH!&[s)\3]F+J7FARJcI?Y&!\JTGo4s+C4K*W(;0CSoeOm-Vl.AENXbs3G_(Bjk_Rg$J(j +l07F)k5a`Fkm-P@l^2,=o_n@\J,~> +nGa!Xb0'\X`l#[7[^*9F[_DX[+2G%mV5:Q4]>!4AbK0S's8U6as3UfGrqYTi[)U>.^\k_n_SjC5 +bfn8O^qI(YZaRg!_rL(+aNr!'b/(d/]=,/Z^U_J!^;%G;h8/s)0]KsdcGSSaq<\+Xo?=eT_o9a+ +[F=E^rQ<:_s2tAab0J#D]XP8P[_(A`cH=<0s3UZC*W+$u\@0W"`5g*1]B8kds6[qJ^pphlbfRf< +]Y(`H[/df;]Ec +nGa!1Kn]R+KS, +nGa$(F*%B\EcHQoCM@D&_5:T=?N4@H@Dud*fkTYeDt\4'F8p=]s)W8]KDtm.rRuX4@Afp!\%KA_ +]Tn2+GFhuC?=@>UBPM>Jmsk*.JocQcrdf$,l/c\rjl^LJDf9T6p%J3$/GO4)SoN#-rm:]Eqj_J8 +A&2X"C$kY9s)W8]s)\3]F+\LPDJX(FCMre@K6.%l!/(1K*WCV=GK=BRM5O]lD"RZ*s3Ph-Deirn +AS?gq\%:5blO1bA\%S)`X(,o6qYp'cJ,~> +nGa$Yb0'b`aiMZk_SEk,_7@#R[K!ZL\Ac).ftlgi`qIO#b5]Was2rLad/O&&rU%_A\>Q[PaMYp: +`5'!u\Xp(4[CEf]^VRePn'(P&ccXVWrm&R(l/fe!jlaSL`l?'>p%J4&/GR<-fZ<@)rpBabqpr[! +]"tr&_!Um=s2rLas2tAab0\8N`P]OL_Su0Dd)u@f!7:WC*<+7,`5o:#^U1G^_t~> +nGa!1Kn]R,KnY]dK7\[@kg'*Ss*bXHJFW8`q1OG#Kp.5jL&_1,L&[A8s"<;nJUZ7pF)eXrE4U+4 +Fa)>]I!pHoJV&K+qYZNUs-&/#L&[?iK_kIrKD>7qqu26ML&V)IKc'iDKs$-\PQ056s8K*PJUcm5 +mXk<6L&Zl+rt'naKnY_EKS4u1pOe.trf`'8rrA8ZruI;cO6MFEGh%1lK)GWJs42mXKS+f(L3Ri] +E3X7rrbE.@C20K +nGa!'F*%B]F)us0EH#j_kfWg=s(iA6DXm@=q/UQUF+\Q6F8u8]F8pmks"E8\Df"(L@:-IN?b0ZT +A7a8(C27X'DfB]9qYZ!Fs+>BFF8pl6Er,QNEVT?Mqf;[Ws8Mh8)#nYuU3"\6s3UfGrh+7LD&9IkmF+\OTEcH*nEH;$WK6.%l!/(.J*J8oml$$cPeS8uAr;Q`rcuX8KEGoZ:An,7V +Z!1E2=V@H2=JDQn=^#$8?FjUifkbX(rpg#=~> +nGa!Xb0'bab0&',aN)s3Sp8b5]i2ankeRaS>SQqoSi[s8Mi:)#qb$grf$2s6]jdrn>H5`9>/- +a85bWs2t?@&Bb$qb0\;RaiMQtaN=D[d)u@f!7:TB*RN*Ul,: +nGa!1Kn]R,KnY`jKnP-Vq=so@(ANN7qLneFL&_1,s+QYjs+ULQKn]PjrVmSmPD"S[m='KDidKp; +It3+@JqAW-re1<*s8N^qs8S::PD0%#Kn]R,Kn]R,L&_+*s8VnK#lfU4Y(bGjs472L%'G;;K_^;u +K`;"*s+UIP"GQl0Kp2Fg#6'=1s8S::rr2t^qZ$SZ#a5"EJV!BDKS9=(!7q+&$&!qlJUi2ti8&bZ +HN2V.HJ$nsH@(!dIH>tHo7M_qnGe"~> +nGa!'F*%B]F*!!6F)uC!q=so.(AMlhqJuN4F8u8]s)Wg6s)\5?F*%A6rVmJfK5tu'm;6Y!ibRXl +D/O:_E;jkWErL.[rt9tas+>BFF8pl6F8u8]F8u8]s8@$=s7p^As)W7UF3oR>d/O%RU2t?qq/Z@R +rr7'>F8l1BF8p<&KD]cprcClrr@]Js8R]WK)'q8Dt7mgF8c+=d/A"lEcHVJDJX+Hh.ck% +s4@Eef\'s;BaAHhj_aGWEH;'Js*t~> +nGa!Xb0'bab0&*2b0%j'q=sp0(APtlqT8[6b5_Las2r^2s2tBAb0'b2rVmK$d)jB#mDQm%ikjfp +`5Taea8X0[ao9H_rt<]Ys3Sp8b5]i2b5_Lab5_Las8C+?s7seCs2rL>b3dRUmJd+ogrda\q8rNV +rr:.@b5VDDb5]W,d/;#jrlWC`s3SpfrrCFBs8UFOchYi*`q%3mb5M>?mJY06aiM`H`P]RNh8'$) +s4@Fgf\+%=^^.cnji$TYaN=GNs*t~> +nG`d+Kn]R,KnY`jre:@OrIl$eKn]P\s8RfQs+UK,PD0$js8Re,s-*E]%-3V+L&Ln$KD>4opk/R! +!<)\Hs8N^qs8S::PD0%#Kn]R,Kn]R,L&_+*s8VnK#lfU4Y(bGjs472L!3Z +nG`d!F*%B]F*!!6rcA)=rGrbSF*%A&s8R0?s)\3]K6.'6s8R.]s+C:M%,cbZF8buUEVT +"EXTaF+aC3"oiXbs8R`Mrr@]Js8IWRre#63rVgm:rrCFCEs@8;EcH*npAJt1oE'")p&8q0E +nG`dRb0'bab0&*2rlY6?rQ5oUb0'b,s8U7As2tAad)uC2s8U6as3U`E%.higb5M4YaS>POprNHV +!<)]8s8N_Ys8UHgd)uC8b0'bab0'bab5_F_s8Vo;#li&igrf$2s6]gc!8RRr#li'Ib5_Las2t?@ +"Npbeb0^(/"ol`fs8UIErrCFBs8L@Jrm8d/rVjt +nG`d+Kn]R,KnY`jre:@OrIl$eKn]P\s8RfQs+UK,PD0$js8Re,s-*E]$fmM*L&_1,L&_1,s8@WO +s7h +nG`d!F*%B]F*!!6rcA)=rGrbSF*%A&s8R0?s)\3]K6.'6s8R.]s+C:M$fHYYF8u8]F8u8]s8@!= +s7g[8rt9tas+>BFF8pl6F8u8]F8u8]s8@$=s7p^As)W7UF3oR>d/O%FUAf3>s)\3]s8R0?F8l1B +F8p<&s86pAs)W8]s+C:M!/(.Jrdt@RK6),6rcA& +nG`dRb0'bab0&*2rlY6?rQ5oUb0'b,s8U7As2tAad)uC2s8U6as3U`E$hM`fb5_Lab5_Las8C(? +s7jb:rt<]Ys3Sp8b5]i2b5_Lab5_Las8C+?s7seCs2rL>b3dRUmJd+ch#>G%s2tAas8U7Ab5VDD +b5]W,s8:"Cs2rLas3U`E!7:TBrm1fJd)sN2rlY3>!:B[+!7:\es8Mu>s8<#Arr2f;"olaFs2rLQ +s*t~> +nG`d+Kn]R,KnY`jre:@OrIl$eKn]P\s8RfQs+UK,PD0$js8Re,s-*E]$fmM*L&_1,L&_1,s8@WO +s7hL&_.+rVllKqh5$6rIt:OrIt:O!ep[Sqh54RL&_1,L%#%l~> +nG`d!F*%B]F*!!6rcA)=rGrbSF*%A&s8R0?s)\3]K6.'6s8R.]s+C:M$fHYYF8u8]F8u8]s8@!= +s7g[8rt9tas+>BFF8pl6F8u8]F8u8]s8@$=s7p^As)W7UF3oR>d/O%FUAf3 +nG`dRb0'bab0&*2rlY6?rQ5oUb0'b,s8U7As2tAad)uC2s8U6as3U`E$hM`fb5_Lab5_Las8C(? +s7jb:rt<]Ys3Sp8b5]i2b5_Lab5_Las8C+?s7seCs2rL>b3dRUmJd+ch#>G#s2tAas8U7>rrgLE +b0'b^ap%gfb5_LgrVllEqZ$QA"TQikb5_I`rVllbqoSocrQ>0?rQ>0?!m:QCqoT*Bb5_Lab4#@\~> +nG`O$L&V,PK`RD;re:@OrIl$eKn]P\s8RfQs+UK,PD0$js8Re,s-*E]$fmM*L&_1,L&_1,s8@WO +s7h +nG`NoF8l4>ErgpnrcA)=rGrbSF*%A&s8R0?s)\3]K6.'6s8R.]s+C:M$fHYYF8u8]F8u8]s8@!= +s7g[8rt9tas+>BFF8pl6F8u8]F8u8]s8@$=s7p^?s)W7UF3oR;rrAemEsDYcs)\5?F8Z%@F8p<& +s86pAs)W8]s+C:M!/(.Jrdt@RK6),6rcA&#leses)\5?F*$gM +J,~> +nG`OKb5VG@aoTlhrlY6?rQ5oUb0'b,s8U7As2tAad)uC2s8U6as3U`E$hM`fb5_Lab5_Las8C(? +s7jb:rt<]Ys3Sp8b5]i2b5_Lab5_Las8C+?s7seAs2rL>b3dRRrrCjRap.mgs2tBAb5D8Bb5]W, +s8:"Cs2rLas3U`E!7:TBrm1fJd)sN2rlY3>!:B[+!7:_frr;r>s8N/Cs8W)@#li&is2tBAb0'2Q +J,~> +nG`O$L&V,PK`RD;re:@OrIka]Kn]P\s8RfQs+UK,PD/u8s+LLRPPtLhjHG:Os8Re,s8RfQrIk7O +pkAbJ&sN@qPD,3Ss-&.js8Re,s8RfQrIt:Oq1T%QKnZ[`es$%3!3Z +nG`NoF8l4>ErgpnrcA)=rGrJKF*%A&s8R0?s)\3]K6."ks)S5@KDkfXi.H)ls8R.]s8R0?rGqu= +piHK8&qg5aK6)Zds+>B6s8R.]s8R0?rH&#=q/Zc?F*"'sd"D8r!2BI6#6/cEF8u8]r;QqAs)W8] +s8@!Bs)W8]s+C:M!/(.Jrdt@RK6),6rcA&#leses)\5?F*$gM +J,~> +nG`OKb5VG@aoTlhrlY6?rQ5WMb0'b,s8U7As2tAad)u=es2kBBd/EtPo?bY&s8U6as8U7ArQ5-? +pr`X:'%$[Yd)s_Xs3Sp2s8U6as8U7ArQ>0?q8rpAb0&M^mEke2!8RRr#62jGb5_Lar;QrCs2rLa +s8C(Ds2rLas3U`E!7:TBrm1fJd)sN2rlY3>!:B[+!7:_frr;r>s8N/Cs8W)@#li&is2tBAb0'2Q +J,~> +nG`O$L&V,PK`RD;re:@OrIka]Kn]P\s8RfQs+UK,PD/u8s+LLRPPkFfPD+_js+Q1,s+ULOK`M/J +L&_/cPQ1ZHKp.5js+Q1,s+Q1,s+ULOL&_2KKa.R2Ks$-\PPkF\Y5X+Zs+UK,s8RfNrrn,VKn]R, +rIkFTKn]R,PPtL]PPY:aPQ-jHPD+_jre:=N!7q%$!0dD9rr;qNs8N.Ss8W(P#lfU4s+ULQKn]!q +J,~> +nG`NoF8l4>ErgpnrcA)=rGrJKF*%A&s8R0?s)\3]K6."ks)S5@KDb`VK6),6s)W8]s)\5=Erc78 +F8u7QKE(t(F+\Q6s)W8]s)W8]s)\5=F8u:9EsDYcF/!a&KDb`LUAf3#leses)\5?F*$gM +J,~> +nG`OKb5VG@aoTlhrlY6?rQ5WMb0'b,s8U7As2tAad)u=es2kBBd/G#s2tAas8U7>rrpRFb0'ba +rQ5!:B[+!7:_frr;r>s8N/Cs8W)@#li&is2tBAb0'2Q +J,~> +nG`O$L&V,PK`RD;re:@OrIka]Kn]P\s8RfQs+UK,PD/u8s+LLRPPkFfPD+_js+Q1,s+ULOK`M/J +L&_/QPQ(R`Kp.5irs4>Ys+Q1,s+ULOL&V,KKa.R2Ks(I,PPkF\Y5X+Zs+UK,s8RfNrrn,VKn]R, +rIkFTKn]R,PPtL]PPY:cPQ-jHPD+_jKn]I)!7q%$!0dD9rr;qNs8N.Ss8W(P#QKL3s+ULQL$ntk~> +nG`NoF8l4>ErgpnrcA)=rGrJKF*%A&s8R0?s)\3]K6."ks)S5@KDb`VK6),6s)W8]s)\5=Erc78 +F8u7?KDtlPF+\Q5rs3]Gs)W8]s)\5=F8l49EsDYcF/&]]KDb`LUAf3#QJjds)\5?F70'Y~> +nG`OKb5VG@aoTlhrlY6?rQ5WMb0'b,s8U7As2tAad)u=es2kBBd/G#s2tAas8U7>rrpRFb0'ba +rQ5s8N/Cs8W)@#QMrhs2tBAb3o:[~> +nG`O$L&V,PK`RD;re:@OrIkLVKn]P\s8RfOrrRn +nG`NoF8l4>ErgpnrcA)=rGr5DF*%A&s8R0=rrR7oF8c.=Erl;nr;R+Vs)\5?F*%B]F8u2[!<;h8 +qu6_=K6-qis)\5?!-A/>s)\2>rGr,AF*%A&rr3#GKDb`QUAo:Us)\/=!-A)<%s.blF8u8]s)W8] +F*%B]KDkfMKDPTSKE$T(K6),6F*%9Z!7:Ua!/(8lrr;q#QJjds)\5?F70'Y~> +nG`OKb5VG@aoTlhrlY6?rQ5BFb0'b,s8U7?rrU?ib5MA?aoVOhr;R,Ns2tBAb0'bab5_F_!<;i: +qu6`?d)u7cs2tBA!6Y<@s2t?@rQ59Cb0'b,rr3#dd/s2t&'Fppb5_Las2rLa +b0'bad/EtEd/*bKd/VJmd)sN2b0'Y^!:B[+!7:_frr;r>s8N/Cs8W)@#QMrhs2tBAb3o:[~> +nG`O$L&V,PK`RD;re:@Os+LUUL&Zj\rVlkOrVlqQPD/u8s+LLRPPkFfPQ-@:s+Q1,s+ULOK`h@/ +s+UFOs+U@M!elhlqu?\Ms8N(Qrr<"Prr;qN"TO10s+UIP!S3J4rr]G(Kn]F(!/:@N%u(%;L&_1, +s+Q1,Kn]R,PPtL]PPY:bPQ-jHPD+_jL&:lMf)::(s+Q[9L&V,NL&_/SL&_2PKa7X3L&Zl,s+Tn@ +J,~> +nG`NoF8l4>ErgpnrcA)=s)S>CF8p<&rVlk=rVlq?K6."ks)S5@KDb`VKE$#ms)W8]s)\5=Es)G` +s)\/=s)\);!cs!8qu?\;s8N(?rr<">rr;q<"TNOas)\2>!RQJsrr]"qF*%6Y!-A)<%s.blF8u8] +s)W8]F*%B]KDkfMKDPTRKE$T(K6),6F8Pt;d/A"es)WhlF8l4EsM_dF8p=]s)[W. +J,~> +nG`OKb5VG@aoTlhrlY6?s2kKEb5]W,rVll?rVlrAd)u=es2kBBd/"TQWes2t?@!U\83rr_'Vb0'V]!6Y6>&'Fppb5_La +s2rLab0'bad/EtEd/*bJd/VJmd)sN2b5;2=mJY0/s2r^fb5VG>b5_JCb5_M@ap7shb5]Was2sd0 +J,~> +nG`O$L&V,PK`mV>L&Zl+s8RcUs+UK,L&M#OL&M#QKp.5hs8RcRs-*B\!gEY +nG`NoF8l4>Es.-qF8p=\s8R-Cs)\3]F8c+=F8c+?F+\Q4s8R-@s+C7L!e^Morr3CJs8R0?s)\3] +s)\3]rVun=qu6_=K6-qis)\5?!-A/>s)\2>rGr,AF*%A&rr3#GKDb`OUAo:Uqu6Y;r;R:Ks)W8] +s)\3]F8p<&s8R`Mrr@]Jrs48WKE$RFF8p=YrrCFEEruA_KDorks8@$=rrR9As8I'Es)W8]F8u8] +mf.e~> +nG`OKb5VG@aop)kb5]W`s8U4Es2tAab5M>?b5M>Ab0\<0s8U4Bs3U]D!mptirr3DLs8U7As2tAa +s2tAarVuo?qu6`?d)u7cs2tBA!6Y<@s2t?@rQ59Cb0'b,rr3#dd/qu6Z=r;R;Ms2rLa +s2tAab5]W,s8UIErrCFBrs7!Od/VJ8b5]W]rrDHbao_Ucd/M2es8C+?rrU@Cs8L.Gs2rLab5_La +mf.e~> +nG`O$L&V,PK`[J +nG`NoF8l4>Erq!oF8Z(%!2IKF8u8]s)\3] +s)\/=s)\);!cs!8qu?\;s8N(?rr<">rr;q<"TNOas)\2>!RQJsrr]"qF*%$S%s.blF8u8]s)W8] +F*%B]KDkfMKDPTRKE$T(K6),6F8Pt;d/A"es)WhlF8l4>EsDYcs8R0?s8I'Es)W8]F8u8]mf.e~> +nG`OKb5VG@ao]rib5D;>aoqaes2rL_rrC4?rrU?ib5MA?aoVOhr;QiFs2t?@%*JVMb5_Las2tAa +s2t"TQWes2t?@!U\83rr_'Vb0'DW&'Fppb5_Las2rLa +b0'bad/EtEd/*bJd/VJmd)sN2b5;2=mJY0/s2r^fb5VG@ap.mgs8U7As8L.Gs2rLab5_Lamf.e~> +nG`O$L&V,PK`[J +nG`NoF8l4>Erq!oF8Pt@F8p=]F*%<[!-A,=!cs!8rVun=!WRfMrrRiQF8l1JF8u8]s8R0?F8p=] +F8c.=F8Pt=F+\Q2s8R0?rr@->s8R0>s8@!As)W8]F8l1?d"D8r"/>g:F7oPDF8p<&s8R0?F*%A& +F8u8mrVlkMqYphRs+C?(F*%A&qu6ZCrGr&?F+aI5rr<">#6/cEs)\5?rcA,>"`s]bs8R0.s*t~> +nG`OKb5VG@ao]rib5;2Bb5]Wab0'\_!6Y9?!m8m4rVuo?!WUOErrURIb5VDLb5_Las8U7Ab5]Wa +b5MA?b5;2?b0\<.s8U7ArrC4@s8U7@s8C(Cs2rLab5VDAmEke2"5Nq!b4YcFb5]W,s8U7Ab0'b, +b5_LgrVllEqYpiJs3Uemb0'b,qu6Z`rQ53Ab0^.1rr<#@#62jGs2tBArlY9@"j6kfs8U70s*t~> +p]#dES,i?aJ,~> +p]#dES,i?aJ,~> +p]#dES,i?aJ,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +o`#!5WoMY0s5WDE!6>&<_uB_Wrr2u=p&G&loD\l4 +o`#!5WoMY0s5WDE!6>&<_uB_Wrr2u=p&G&loD\l4 +o`#!5WoMY0s5WDE!6>&<_uB_Wrr2u=p&G&loD\l4 +pAY0R +pAY0R +pAY0R +pAY:r3TL.>j6?REj)XYhs&K$t!TS4grrE,"q#C@okPkR_!<3#uWpfrl`rK->EWF/Rs8Q*krrE+[ +n,EEg!8%7$~> +pAY:r3TL.>j6?REj)XYhs&K$t!TS4grrE,"q#C@okPkR_!<3#uWpfrl`rK->EWF/Rs8Q*krrE+[ +n,EEg!8%7$~> +pAY:r3TL.>j6?REj)XYhs&K$t!TS4grrE,"q#C@okPkR_!<3#uWpfrl`rK->EWF/Rs8Q*krrE+[ +n,EEg!8%7$~> +pAY-nEr>qDEo[2[ElS0?WrN+! +*KF."q>WDSWrN+ZElV1?j&I*?j)R-[j8]."!36%u%rt[Ms8V+Zrr3MLs2S,[a8b1? +pAY-nEr>qDEo[2[ElS0?WrN+! +*KF."q>WDSWrN+ZElV1?j&I*?j)R-[j8]."!36%u%rt[Ms8V+Zrr3MLs2S,[a8b1? +pAY-nEr>qDEo[2[ElS0?WrN+! +*KF."q>WDSWrN+ZElV1?j&I*?j)R-[j8]."!36%u%rt[Ms8V+Zrr3MLs2S,[a8b1? +pAY+mrW";dWrE(!s/H(!!!$">ErT,[EiK*>3<6)Ws8Q*ts8Q(,s)K,[ +3E9&Z*E<*[qYrPUWrN+!!!#"ZW`:&[ +<<1(>!!#"Za8>lS<<*%!!$-+[s&C(>!6=+"3E6&Zs&C(>*HM)X&B@cN3E>,"*B?,#rr<$>*EE%; +!NH.u<>smt!$)%>*<<,>WW4&"!<;'Z3B8,[*B@+?WqQIC~> +pAY+mrW";dWrE(!s/H(!!!$">ErT,[EiK*>3<6)Ws8Q*ts8Q(,s)K,[ +3E9&Z*E<*[qYrPUWrN+!!!#"ZW`:&[ +<<1(>!!#"Za8>lS<<*%!!$-+[s&C(>!6=+"3E6&Zs&C(>*HM)X&B@cN3E>,"*B?,#rr<$>*EE%; +!NH.u<>smt!$)%>*<<,>WW4&"!<;'Z3B8,[*B@+?WqQIC~> +pAY+mrW";dWrE(!s/H(!!!$">ErT,[EiK*>3<6)Ws8Q*ts8Q(,s)K,[ +3E9&Z*E<*[qYrPUWrN+!!!#"ZW`:&[ +<<1(>!!#"Za8>lS<<*%!!$-+[s&C(>!6=+"3E6&Zs&C(>*HM)X&B@cN3E>,"*B?,#rr<$>*EE%; +!NH.u<>smt!$)%>*<<,>WW4&"!<;'Z3B8,[*B@+?WqQIC~> +p&?N%WiB&!irH+ZWW<&!NrQ*Z`rM,[!33%!WrF*[ErV."WW9(!*QS*Xs&K$ts&BI,EZL2? +s/H(Zs&E(qruqHCs8T)!+" +a8\/"EZP2[N]@*>qYq$*WrN*>*WP."WW6'!EcV*X!NH.u +<>"7k*TI-[rrB)!*EE->!<5&>rVlp>3QLdlJ,~> +p&?N%WiB&!irH+ZWW<&!NrQ*Z`rM,[!33%!WrF*[ErV."WW9(!*QS*Xs&K$ts&BI,EZL2? +s/H(Zs&E(qruqHCs8T)!+" +a8\/"EZP2[N]@*>qYq$*WrN*>*WP."WW6'!EcV*X!NH.u +<>"7k*TI-[rrB)!*EE->!<5&>rVlp>3QLdlJ,~> +p&?N%WiB&!irH+ZWW<&!NrQ*Z`rM,[!33%!WrF*[ErV."WW9(!*QS*Xs&K$ts&BI,EZL2? +s/H(Zs&E(qruqHCs8T)!+" +a8\/"EZP2[N]@*>qYq$*WrN*>*WP."WW6'!EcV*X!NH.u +<>"7k*TI-[rrB)!*EE->!<5&>rVlp>3QLdlJ,~> +nc':'WW9(!WW<&!WrK(!WW3$!a8`.>rVumt#QFe(s/H(!!;QTosts8Q(%WW3$!a8,`C!36)!UJq!;uls<=]$/WrE'>rrB)! +WW<&!Wr;r"j)P-"p&BO~> +nc':'WW9(!WW<&!WrK(!WW3$!a8`.>rVumt#QFe(s/H(!!;QTosts8Q(%WW3$!a8,`C!36)!UJq!;uls<=]$/WrE'>rrB)! +WW<&!Wr;r"j)P-"p&BO~> +nc':'WW9(!WW<&!WrK(!WW3$!a8`.>rVumt#QFe(s/H(!!;QTosts8Q(%WW3$!a8,`C!36)!UJq!;uls<=]$/WrE'>rrB)! +WW<&!Wr;r"j)P-"p&BO~> +p\u.P3<8([WrK(!rrB)!WW<"ts&B=(*EE,>3N<)Ss8Q(2s/L+>!<<'!WrH(!s8R*[j8Y." +iuO/[!<<'!Wr2l8EZP0[!07'ZWlG+>iuO/#*TQ0?*>s2S.9rsJh,s8R*[j/N+>!35kp!NH.t +s8Q(8rrB)!3E?)"ErV."ruG,>a)^4?s2P,>pA]X~> +p\u.P3<8([WrK(!rrB)!WW<"ts&B=(*EE,>3N<)Ss8Q(2s/L+>!<<'!WrH(!s8R*[j8Y." +iuO/[!<<'!Wr2l8EZP0[!07'ZWlG+>iuO/#*TQ0?*>s2S.9rsJh,s8R*[j/N+>!35kp!NH.t +s8Q(8rrB)!3E?)"ErV."ruG,>a)^4?s2P,>pA]X~> +p\u.P3<8([WrK(!rrB)!WW<"ts&B=(*EE,>3N<)Ss8Q(2s/L+>!<<'!WrH(!s8R*[j8Y." +iuO/[!<<'!Wr2l8EZP0[!07'ZWlG+>iuO/#*TQ0?*>s2S.9rsJh,s8R*[j/N+>!35kp!NH.t +s8Q(8rrB)!3E?)"ErV."ruG,>a)^4?s2P,>pA]X~> +p\t5nr;Zp?WrI,WW<)! +!35tss&BR/WW;)Z!!"&>iuS+!!`f8#rVupuqYpp'WrN+Z*<6([rrB(prrM-[rDa3bEcV0[ +WrH(!s,R$Xs/Q%u!EI2>!!+,#pA]X~> +p\t5nr;Zp?WrI,WW<)! +!35tss&BR/WW;)Z!!"&>iuS+!!`f8#rVupuqYpp'WrN+Z*<6([rrB(prrM-[rDa3bEcV0[ +WrH(!s,R$Xs/Q%u!EI2>!!+,#pA]X~> +p\t5nr;Zp?WrI,WW<)! +!35tss&BR/WW;)Z!!"&>iuS+!!`f8#rVupuqYpp'WrN+Z*<6([rrB(prrM-[rDa3bEcV0[ +WrH(!s,R$Xs/Q%u!EI2>!!+,#pA]X~> +pAY6TWiF,s8V->s8T+!j8Z+Z +WiG[j#KQlEa8c2"j8K#XWWV;]j5^(;s/H;'a8c1[WoO*Y!6>*=!6>*=!QV5>rr^=As2Y$:s5X.Z +#fluFWiH+!a/]+s2V/"a8c2" +WlP/>j/T-Os*t~> +pAY6TWiF,s8V->s8T+!j8Z+Z +WiG[j#KQlEa8c2"j8K#XWWV;]j5^(;s/H;'a8c1[WoO*Y!6>*=!6>*=!QV5>rr^=As2Y$:s5X.Z +#fluFWiH+!a/]+s2V/"a8c2" +WlP/>j/T-Os*t~> +pAY6TWiF,s8V->s8T+!j8Z+Z +WiG[j#KQlEa8c2"j8K#XWWV;]j5^(;s/H;'a8c1[WoO*Y!6>*=!6>*=!QV5>rr^=As2Y$:s5X.Z +#fluFWiH+!a/]+s2V/"a8c2" +WlP/>j/T-Os*t~> +l2LbaWmUhIWW7VMec1.~> +l2LbaWmUhIWW7VMec1.~> +l2LbaWmUhIWW7VMec1.~> +l2Lc)a3jnf`uTa2ec1.~> +l2Lc)a3jnf`uTa2ec1.~> +l2Lc)a3jnf`uTa2ec1.~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +JcCT,J,~> +%%EndData +showpage +%%Trailer +end +%%EOF diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/doc/slime-small.pdf b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/doc/slime-small.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4fd6557889e650edbbdf23ea97834b6c2cc16d16 GIT binary patch literal 7407 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, describe-key, ``What does this key do?''} +Describes current function bound to @kbd{} for focus buffer. + +@kbdanchorc{C-h b, describe-bindings, ``Exactly what bindings are available?''} +Lists the current key-bindings for the focus buffer. + +@kbdanchorc{C-h m, describe-mode, ``Tell me all about this mode''} +Shows all the available major mode keys, then the minor mode keys, for +the modes of the focus buffer. + +@kbdanchorc{C-h l, view-lossage, ``Woah@comma{} what key chord did I just do?''} +Shows you the literal sequence of keys you've pressed in order. + +@c is breaks links PDF, despite that it's not l it's C-h +@c @kbdanchorc{ l, , ``What starts with?''} +@c Lists all keybindings that begin with @code{} for the focus buffer mode. + + +@end table + +@emph{Note:} In this documentation the designation @kbd{C-h} is a +@dfn{canonical key} which might actually mean Ctrl-h, or F1, or +whatever you have @code{help-command} bound to in your +@code{.emacs}. Here is a common situation: + +@example +(global-set-key [f1] 'help-command) +(global-set-key "\C-h" 'delete-backward-char) +@end example + +@noindent In this situation everywhere you see @kbd{C-h} in the +documentation you would substitute @kbd{F1}. + +You can assign or change default key bindings globally using the +@code{global-set-key} function in your @file{~/.emacs} file like this: +@example +(global-set-key "\C-c s" 'slime-selector) +@end example +@noindent +which binds @kbd{C-c s} to the function @code{slime-selector}. + +Alternatively, if you want to assign or change a key binding in just a +particular slime mode, you can use the @code{define-key} function +in your @file{~/.emacs} file like this: +@example +(define-key slime-repl-mode-map (kbd "C-c ;") + 'slime-insert-balanced-comments) +@end example +@noindent +which binds @kbd{C-c ;} to the function +@code{slime-insert-balanced-comments} in the REPL buffer. + +@c ----------------------- +@node Evaluation +@section Evaluation commands + +These commands each evaluate a Common Lisp expression in a different +way. Usually they mimic commands for evaluating Emacs Lisp code. By +default they show their results in the echo area, but a prefix +argument causes the results to be inserted in the current buffer. + +@table @kbd + +@kbditem{C-x C-e, slime-eval-last-expression} + +Evaluate the expression before point and show the result in the echo +area. + +@kbditem{C-M-x, slime-eval-defun} +Evaluate the current toplevel form and show the result in the echo +area. `C-M-x' treats `defvar' expressions specially. Normally, +evaluating a `defvar' expression does nothing if the variable it +defines already has a value. But `C-M-x' unconditionally resets the +variable to the initial value specified in the `defvar' expression. +This special feature is convenient for debugging Lisp programs. + +@end table + +If @kbd{C-M-x} or @kbd{C-x C-e} is given a numeric argument, it +inserts the value into the current buffer, rather than displaying it +in the echo area. + +@table @kbd +@kbditem{C-c :, slime-interactive-eval} +Evaluate an expression read from the minibuffer. + +@kbditem{C-c C-r, slime-eval-region} +Evaluate the region. + +@kbditem{C-c C-p, slime-pprint-eval-last-expression} +Evaluate the expression before point and pretty-print the result in a +fresh buffer. + +@kbditem{C-c E, slime-edit-value} +Edit the value of a setf-able form in a new buffer @file{*Edit
*}. +The value is inserted into a temporary buffer for editing and then set +in Lisp when committed with @kbd{C-c C-c}. + +@kbditem{C-c C-u, slime-undefine-function} +Undefine the function, with @code{fmakunbound}, for the symbol at +point. + +@end table + +@c ----------------------- +@node Compilation +@section Compilation commands + +@cindex Compilation + +@SLIME{} has fancy commands for compiling functions, files, and +packages. The fancy part is that notes and warnings offered by the +Lisp compiler are intercepted and annotated directly onto the +corresponding expressions in the Lisp source buffer. (Give it a try to +see what this means.) + +@table @kbd +@cindex Compiling Functions +@kbditem{C-c C-c, slime-compile-defun} +Compile the top-level form at point. The region blinks shortly to +give some feedback which part was chosen. + +With (positive) prefix argument the form is compiled with maximal +debug settings (@kbd{C-u C-c C-c}). With negative prefix argument it is compiled for +speed (@kbd{M-- C-c C-c}). If a numeric argument is passed set debug or speed settings +to it depending on its sign. + +The code for the region is executed after compilation. In principle, +the command writes the region to a file, compiles that file, and loads +the resulting code. + +@kbditem{C-c C-k, slime-compile-and-load-file} +Compile and load the current buffer's source file. If the compilation +step fails, the file is not loaded. It's not always easy to tell +whether the compilation failed: occasionally you may end up in the +debugger during the load step. + +With (positive) prefix argument the file is compiled with maximal +debug settings (@kbd{C-u C-c C-k}). With negative prefix argument it is compiled for +speed (@kbd{M-- C-c C-k}). If a numeric argument is passed set debug or speed settings +to it depending on its sign. + +@kbditem{C-c M-k, slime-compile-file} +Compile (but don't load) the current buffer's source file. + +@kbditem{C-c C-l, slime-load-file} +Load a Lisp file. This command uses the Common Lisp LOAD function. + +@cmditem{slime-compile-region} +Compile the selected region. + +@end table + +The annotations are indicated as underlining on source forms. The +compiler message associated with an annotation can be read either by +placing the mouse over the text or with the selection commands below. + +@table @kbd +@kbditem{M-n, slime-next-note} +Move the point to the next compiler note and displays the note. + +@kbditem{M-p, slime-previous-note} +Move the point to the previous compiler note and displays the note. + +@kbditem{C-c M-c, slime-remove-notes} +Remove all annotations from the buffer. + +@kbditem{C-x `, next-error} +Visit the next-error message. This is not actually a @SLIME{} command +but @SLIME{} creates a hidden buffer so that most of the Compilation +mode commands (@inforef{Compilation Mode,, emacs}) work similarly for +Lisp as for batch compilers. + +@end table + +@node Completion +@section Completion commands + +@cindex Completion +@cindex Symbol Completion + +Completion commands are used to complete a symbol or form based on +what is already present at point. Classical completion assumes an +exact prefix and gives choices only where branches may occur. Fuzzy +completion tries harder. + +@table @kbd +@kbditem{M-TAB,slime-complete-symbol} +@c @itemx ESC TAB +@c @itemx C-M-i +Complete the symbol at point. Note that three styles of completion are +available in @SLIME{}; the default is similar to normal Emacs +completion (@pxref{slime-completion-at-point-functions}). + +@end table + +@c ----------------------- +@node Finding definitions +@section Finding definitions (``Meta-Point'' commands). + +@cindex Meta-dot +@cindex TAGS + +The familiar @kbd{M-.} command is provided. For generic functions this +command finds all methods, and with some systems it does other fancy +things (like tracing structure accessors to their @code{DEFSTRUCT} +definition). + +@table @kbd + +@kbditem{M-., slime-edit-definition} +Go to the definition of the symbol at point. + +@item M-, +@itemx M-* +@itemx M-x slime-pop-find-definition-stack +@kindex M-, +@findex slime-pop-find-definition-stack +Go back to the point where @kbd{M-.} was invoked. This gives multi-level +backtracking when @kbd{M-.} has been used several times. + +@kbditem{C-x 4 ., slime-edit-definition-other-window} +Like @code{slime-edit-definition} but switches to the other window to +edit the definition in. + +@kbditem{C-x 5 ., slime-edit-definition-other-frame} +Like @code{slime-edit-definition} but opens another frame to edit the +definition in. + +@cmditem{slime-edit-definition-with-etags} +Use an ETAGS table to find definition at point. + +@end table + +@c ----------------------- +@node Documentation +@section Documentation commands + +@SLIME{}'s online documentation commands follow the example of Emacs +Lisp. The commands all share the common prefix @kbd{C-c C-d} and allow +the final key to be modified or unmodified (@pxref{Key bindings}.) + +@table @kbd + +@kbditem{SPC, slime-space} +The space key inserts a space, but also looks up and displays the +argument list for the function at point, if there is one. + +@kbditem{C-c C-d d, slime-describe-symbol} +Describe the symbol at point. + +@kbditem{C-c C-d f, slime-describe-function} +Describe the function at point. + +@kbditem{C-c C-d A, slime-apropos} +Perform an apropos search on Lisp symbol names for a regular expression +match and display their documentation strings. By default the external +symbols of all packages are searched. With a prefix argument you can choose a +specific package and whether to include unexported symbols. + +@kbditem{C-c C-d z, slime-apropos-all} +Like @code{slime-apropos} but also includes internal symbols by default. + +@kbditem{C-c C-d p, slime-apropos-package} +Show apropos results of all symbols in a package. This command is for +browsing a package at a high-level. With package-name completion it +also serves as a rudimentary Smalltalk-ish image-browser. + +@kbditem{C-c C-d h, slime-hyperspec-lookup} +Lookup the symbol at point in the @cite{Common Lisp Hyperspec}. This +uses the familiar @file{hyperspec.el} to show the appropriate section +in a web browser. The Hyperspec is found either on the Web or in +@code{common-lisp-hyperspec-root}, and the browser is selected by +@code{browse-url-browser-function}. + +Note: this is one case where @kbd{C-c C-d h} is @emph{not} the same as +@kbd{C-c C-d C-h}. + +@kbditem{C-c C-d ~, hyperspec-lookup-format} +Lookup a @emph{format character} in the @cite{Common Lisp Hyperspec}. + +@kbditem{C-c C-d #, hyperspec-lookup-reader-macro} +Lookup a @emph{reader macro} in the @cite{Common Lisp Hyperspec}. +@end table + +@c ----------------------- +@node Cross-reference +@section Cross-reference commands + +@cindex xref +@cindex Cross-referencing + +@SLIME{}'s cross-reference commands are based on the support provided +by the Lisp system, which varies widely between Lisps. For systems +with no built-in @acronym{XREF} support @SLIME{} queries a portable +@acronym{XREF} package, which is taken from the @cite{CMU AI +Repository} and bundled with @SLIME{}. + +Each command operates on the symbol at point, or prompts if there is +none. With a prefix argument they always prompt. You can either enter +the key bindings as shown here or with the control modified on the +last key, @xref{Key bindings}. + +@menu +* Xref buffer commands:: +@end menu + +@table @kbd +@kbditem{C-c C-w c, slime-who-calls} +Show function callers. + +@kbditem{C-c C-w w, slime-calls-who} +Show all known callees. + +@kbditem{C-c C-w r, slime-who-references} +Show references to global variable. + +@kbditem{C-c C-w b, slime-who-binds} +Show bindings of a global variable. + +@kbditem{C-c C-w s, slime-who-sets} +Show assignments to a global variable. + +@kbditem{C-c C-w m, slime-who-macroexpands} +Show expansions of a macro. + +@cmditem{slime-who-specializes} +Show all known methods specialized on a class. + +@end table + +There are also ``List callers/callees'' commands. These operate by +rummaging through function objects on the heap at a low-level to +discover the call graph. They are only available with some Lisp +systems, and are most useful as a fallback when precise @acronym{XREF} +information is unavailable. + +@table @kbd +@kbditem{C-c <, slime-list-callers} +List callers of a function. + +@kbditem{C-c >, slime-list-callees} +List callees of a function. + +@end table + +@node Xref buffer commands +@subsection Xref buffer commands +Commands available in Xref buffers +@table @kbd + +@kbditem{RET, slime-show-xref} +Show definition at point in the other window. Do not leave Xref buffer. + +@kbditem{Space, slime-goto-xref} +Show definition at point in the other window and close Xref buffer. + +@kbditem{C-c C-c, slime-recompile-xref} +Recompile definition at point. + +@kbditem{C-c C-k, slime-recompile-all-xrefs} +Recompile all definitions. + +@end table + +@c ----------------------- +@node Macro-expansion +@section Macro-expansion commands + +@cindex Macros + +@table @kbd +@kbditem{C-c C-m, slime-expand-1} +Macroexpand (or compiler-macroexpand) the expression starting at point +once. If invoked with a prefix argument use macroexpand instead or +macroexpand-1 (or compiler-macroexpand instead of +compiler-macroexpand-1). + +@cmditem{slime-macroexpand-1} +Macroexpand the expression starting at point once. If invoked with a +prefix argument, use macroexpand instead of macroexpand-1. + +@kbditem{C-c M-m, slime-macroexpand-all} +Fully macroexpand the expression starting at point. + +@cmditem{slime-compiler-macroexpand-1} +Display the compiler-macro expansion of sexp starting at point. + +@cmditem{slime-compiler-macroexpand} +Repeatedy expand compiler macros of sexp starting at point. + +@end table + +For additional minor-mode commands and discussion, +@pxref{slime-macroexpansion-minor-mode}. + + +@c ----------------------- +@node Disassembly +@section Disassembly commands + +@table @kbd + +@kbditem{C-c M-d, slime-disassemble-symbol} +Disassemble the function definition of the symbol at point. + +@kbditem{C-c C-t, slime-toggle-trace-fdefinition} +Toggle tracing of the function at point. If invoked with a prefix +argument, read additional information, like which particular method +should be traced. + +@cmditem{slime-untrace-all} +Untrace all functions. + +@end table + +@c ----------------------- +@node Recovery +@section Abort/Recovery commands + +@table @kbd +@kbditem{C-c C-b, slime-interrupt} +Interrupt Lisp (send @code{SIGINT}). + +@cmditem{slime-restart-inferior-lisp} +Restart the @code{inferior-lisp} process. + +@kbditem{C-c ~, slime-sync-package-and-default-directory} +Synchronize the current package and working directory from Emacs to +Lisp. + +@kbditem{C-c M-p, slime-repl-set-package} +Set the current package of the @acronym{REPL}. + +@cmditem{slime-cd} +Set the current directory of the Lisp process. This also +changes the current directory of the REPL buffer. + +@cmditem{slime-pwd} +Print the current directory of the Lisp process. + +@end table + +@c ----------------------- +@node Inspector +@section Inspector commands + +The @SLIME{} inspector is a Emacs-based alternative to the +standard @code{INSPECT} function. The inspector presents objects in +Emacs buffers using a combination of plain text, hyperlinks to related +objects. + +The inspector can easily be specialized for the objects in your own +programs. For details see the @code{inspect-for-emacs} generic +function in @file{swank/backend.lisp}. + +@table @kbd + +@kbditem{C-c I, slime-inspect} +Inspect the value of an expression entered in the minibuffer. + +@end table + +The standard commands available in the inspector are: + +@table @kbd + +@kbditem{RET, slime-inspector-operate-on-point} +If point is on a value then recursively call the inspector on that +value. If point is on an action then call that action. + +@kbditem{d, slime-inspector-describe} +Describe the slot at point. + +@kbditem{e, slime-inspector-eval} +Evaluate an expression in the context of the inspected object. The +variable @code{*} will be bound to the inspected object. + +@kbditem{v, slime-inspector-toggle-verbose} +Toggle between verbose and terse mode. Default is determined by +`swank:*inspector-verbose*'. + +@kbditem{l, slime-inspector-pop} +Go back to the previous object (return from @kbd{RET}). + +@kbditem{n, slime-inspector-next} +The inverse of @kbd{l}. Also bound to @kbd{SPC}. + +@kbditem{g, slime-inspector-reinspect} +Reinspect. + +@kbditem{q, slime-inspector-quit} +Dismiss the inspector buffer. + +@kbditem{p, slime-inspector-pprint} +Pretty print in another buffer object at point. + +@kbditem{., slime-inspector-show-source} +Find source of object at point. + +@kbditem{>, slime-inspector-fetch-all} +Fetch all inspector contents and go to the end. + +@kbditem{M-RET, slime-inspector-copy-down} +Store the value under point in the variable `*'. This can +then be used to access the object in the REPL. + +@kbditempair{TAB, S-TAB, slime-inspector-next-inspectable-object, slime-inspector-previous-inspectable-object} + +Jump to the next and previous inspectable object respectively. + +@end table + +@c ----------------------- +@node Profiling +@section Profiling commands + +The profiling commands are based on CMUCL's profiler. These are +simple wrappers around functions which usually print something to the +output buffer. + +@table @kbd +@cmditem{slime-toggle-profile-fdefinition} +Toggle profiling of a function. +@cmditem{slime-profile-package} +Profile all functions in a package. +@cmditem{slime-profile-by-substring} +Profile all functions which names contain a substring. +@cmditem{slime-unprofile-all} +Unprofile all functions. +@cmditem{slime-profile-report} +Report profiler data. +@cmditem{slime-profile-reset} +Reset profiler data. +@cmditem{slime-profiled-functions} +Show list of currently profiled functions. +@end table + +@c ----------------------- +@node Other +@section Shadowed Commands + +@table @kbd + +@kbditempair{C-c C-a, C-c C-v, slime-nop, slime-nop} +This key-binding is shadowed from inf-lisp. + +@end table + +@c ----------------------- +@node Semantic indentation +@section Semantic indentation + +@SLIME{} automatically discovers how to indent the macros in your Lisp +system. To do this the Lisp side scans all the macros in the system and +reports to Emacs all the ones with @code{&body} arguments. Emacs then +indents these specially, putting the first arguments four spaces in and +the ``body'' arguments just two spaces, as usual. + +This should ``just work.'' If you are a lucky sort of person you needn't +read the rest of this section. + +To simplify the implementation, @SLIME{} doesn't distinguish between +macros with the same symbol-name but different packages. This makes it +fit nicely with Emacs's indentation code. However, if you do have +several macros with the same symbol-name then they will all be indented +the same way, arbitrarily using the style from one of their +arglists. You can find out which symbols are involved in collisions +with: + +@example +(swank:print-indentation-lossage) +@end example + +If a collision causes you irritation, don't have a nervous breakdown, +just override the Elisp symbol's @code{common-lisp-indent-function} +property to your taste. @SLIME{} won't override your custom settings, it +just tries to give you good defaults. + +A more subtle issue is that imperfect caching is used for the sake of +performance. @footnote{@emph{Of course} we made sure it was actually too +slow before making the ugly optimization.} + +In an ideal world, Lisp would automatically scan every symbol for +indentation changes after each command from Emacs. However, this is too +expensive to do every time. Instead Lisp usually just scans the symbols +whose home package matches the one used by the Emacs buffer where the +request comes from. That is sufficient to pick up the indentation of +most interactively-defined macros. To catch the rest we make a full scan +of every symbol each time a new Lisp package is created between commands +-- that takes care of things like new systems being loaded. + +You can use @kbd{M-x slime-update-indentation} to force all symbols to +be scanned for indentation information. + +@c ----------------------- +@node Reader conditionals +@section Reader conditional fontification + +@SLIME{} automatically evaluates reader-conditional expressions, like +@code{#+linux}, in source buffers and ``grays out'' code that will be +skipped for the current Lisp connection. + +@c ----------------------- +@node Debugger +@chapter SLDB: the SLIME debugger + +@cindex Debugger + +@SLIME{} has a custom Emacs-based debugger called @SLDB{}. Conditions +signalled in the Lisp system invoke @SLDB{} in Emacs by way of the +Lisp @code{*DEBUGGER-HOOK*}. + +@SLDB{} pops up a buffer when a condition is signalled. The buffer +displays a description of the condition, a list of restarts, and a +backtrace. Commands are offered for invoking restarts, examining the +backtrace, and poking around in stack frames. + +@menu +* Examining frames:: +* Restarts:: +* Frame Navigation:: +* Stepping:: +* Miscellaneous:: +@end menu + +@c ----------------------- +@node Examining frames +@section Examining frames + +Commands for examining the stack frame at point. + +@table @kbd +@kbditem{t, sldb-toggle-details} +Toggle display of local variables and @code{CATCH} tags. + +@kbditem{v, sldb-show-source} +View the frame's current source expression. The expression is +presented in the Lisp source file's buffer. + +@kbditem{e, sldb-eval-in-frame} +Evaluate an expression in the frame. The expression can refer to the +available local variables in the frame. + +@kbditem{d, sldb-pprint-eval-in-frame} +Evaluate an expression in the frame and pretty-print the result in a +temporary buffer. + +@kbditem{D, sldb-disassemble} +Disassemble the frame's function. Includes information such as the +instruction pointer within the frame. + +@kbditem{i, sldb-inspect-in-frame} +Inspect the result of evaluating an expression in the frame. + +@kbditem{C-c C-c, sldb-recompile-frame-source} +Recompile frame. @kbd{C-u C-c C-c} for recompiling with maximum debug settings. + +@end table + +@c ----------------------- +@node Restarts +@section Invoking restarts + +@table @kbd +@kbditem{a, sldb-abort} +Invoke the @code{ABORT} restart. + +@anchor{sldb-quit} +@kbditem{q, sldb-quit} +``Quit'' -- For @SLIME{} evaluation requests, invoke a restart which +restores to a known program state. For errors in other threads, see +@ref{*SLDB-QUIT-RESTART*}. + +@kbditem{c, sldb-continue} +Invoke the @code{CONTINUE} restart. + +@item 0 ... 9 +Invoke a restart by number. +@end table + +Restarts can also be invoked by pressing @kbd{RET} or @kbd{Mouse-2} on +them in the buffer. + +@c ----------------------- +@node Frame Navigation +@section Navigating between frames + +@table @kbd +@kbditempair{n,p,sldb-down,sldb-up} +Move between frames. + +@kbditempair{M-n, M-p, sldb-details-down, sldb-details-up} +Move between frames ``with sugar'': hide the details of the original +frame and display the details and source code of the next. Sugared +motion makes you see the details and source code for the current frame +only. + +@kbditem{>, sldb-end-of-backtrace} +Fetch the entire backtrace and go to the last frame. + +@kbditem{<, sldb-beginning-of-backtrace} +Goto the first frame. + +@end table + +@node Stepping +@section Stepping + +@cindex Stepping + +Stepping is not available in all implementations and works very +differently in those in which it is available. + +@table @kbd +@kbditem{s, sldb-step} +Step to the next expression in the frame. For CMUCL that means, set a +breakpoint at all those code locations in the current code block which +are reachable from the current code location. + +@kbditem{x, sldb-next} +Step to the next form in the current function. + +@kbditem{o, sldb-out} +Stop single-stepping temporarily, but resume it once the current +function returns. + +@end table + +@node Miscellaneous +@section Miscellaneous Commands + +@table @kbd +@kbditem{r, sldb-restart-frame} +Restart execution of the frame with the same arguments it was +originally called with. (This command is not available in all +implementations.) + +@kbditem{R, sldb-return-from-frame} +Return from the frame with a value entered in the minibuffer. (This +command is not available in all implementations.) + + +@kbditem{B, sldb-break-with-default-debugger} +Exit @SLDB{} and debug the condition using the Lisp system's default +debugger. + +@kbditem{C, sldb-inspect-condition} +Inspect the condition currently being debugged. + +@kbditem{:, slime-interactive-eval} +Evaluate an expression entered in the minibuffer. +@kbditem{A, sldb-break-with-system-debugger} +Attach debugger (e.g. gdb) to the current lisp process. + +@end table + + +@c ----------------------- +@node Misc +@chapter Misc + +@menu +* slime-selector:: +* slime-macroexpansion-minor-mode:: +* Multiple connections:: +@end menu + +@c ----------------------- +@node slime-selector +@section @code{slime-selector} + +The @code{slime-selector} command is for quickly switching to +important buffers: the @REPL{}, @SLDB{}, the Lisp source you were just +hacking, etc. Once invoked the command prompts for a single letter to +specify which buffer it should display. Here are some of the options: + +@table @kbd +@item ? +A help buffer listing all @code{slime-selectors}'s available buffers. +@item r +The @REPL{} buffer for the current @SLIME{} connection. +@item d +The most recently activated @SLDB{} buffer for the current connection. +@item l +The most recently visited @code{lisp-mode} source buffer. +@item s +The @code{*slime-scratch*} buffer (@pxref{slime-scratch}). +@item c +SLIME connections buffer (@pxref{Multiple connections}). +@item n +Cycle to the next Lisp connection (@pxref{Multiple connections}). +@item t +SLIME threads buffer (@pxref{Multiple connections}). +@end table + +@code{slime-selector} doesn't have a key binding by default but we +suggest that you assign it a global one. You can bind it to @kbd{C-c s} +like this: + +@example +(global-set-key "\C-cs" 'slime-selector) +@end example + +@noindent +And then you can switch to the @REPL{} from anywhere with @kbd{C-c s +r}. + +The macro @code{def-slime-selector-method} can be used to define new +buffers for @code{slime-selector} to find. + +@c ----------------------- +@node slime-macroexpansion-minor-mode +@section slime-macroexpansion-minor-mode + +Within a slime macroexpansion buffer some extra commands are provided +(these commands are always available but are only bound to keys in a +macroexpansion buffer). + +@table @kbd +@kbditem{C-c C-m, slime-macroexpand-1-inplace} +Just like slime-macroexpand-1 but the original form is replaced with +the expansion. + +@c @anchor{slime-macroexpand-1-inplace} +@kbditem{g, slime-macroexpand-1-inplace} +The last macroexpansion is performed again, the current contents of +the macroexpansion buffer are replaced with the new expansion. + +@kbditem{q, slime-temp-buffer-quit} +Close the expansion buffer. + +@kbditem{C-_, slime-macroexpand-undo} +Undo last macroexpansion operation. + +@end table + +@c ----------------------- +@node Multiple connections +@section Multiple connections + +@SLIME{} is able to connect to multiple Lisp processes at the same +time. The @kbd{M-x slime} command, when invoked with a prefix +argument, will offer to create an additional Lisp process if one is +already running. This is often convenient, but it requires some +understanding to make sure that your @SLIME{} commands execute in the +Lisp that you expect them to. + +Some buffers are tied to specific Lisp processes. Each Lisp connection +has its own @acronym{REPL} buffer, and all expressions entered or +@SLIME{} commands invoked in that buffer are sent to the associated +connection. Other buffers created by @SLIME{} are similarly tied to +the connections they originate from, including @SLDB{} buffers, +apropos result listings, and so on. These buffers are the result of +some interaction with a Lisp process, so commands in them always go +back to that same process. + +Commands executed in other places, such as @code{slime-mode} source +buffers, always use the ``default'' connection. Usually this is the +most recently established connection, but this can be reassigned via +the ``connection list'' buffer: + +@table @kbd +@kbditem{C-c C-x c, slime-list-connections} +Pop up a buffer listing the established connections. It is also +available by the typing @kbd{c} from the @SLIME{} selector +(@ref{slime-selector}). + +@kbditem{C-c C-x n, slime-cycle-connections} +Change current Lisp connection by cycling through all connections. It +is also available by the typing @kbd{n} from the SLIME selector +(@ref{slime-selector}). + +@kbditem{C-c C-x t, slime-list-threads} +Pop up a buffer listing the current threads. It is also available by +the typing @kbd{t} from the @SLIME{} selector (@ref{slime-selector}). +@end table + +The buffer displayed by @code{slime-list-connections} gives a one-line +summary of each connection. The summary shows the connection's serial +number, the name of the Lisp implementation, and other details of the +Lisp process. The current ``default'' connection is indicated with an +asterisk. + +The commands available in the connection-list buffer are: + +@table @kbd +@kbditem{RET, slime-goto-connection} +Pop to the @acronym{REPL} buffer of the connection at point. + +@kbditem{d, slime-connection-list-make-default} +Make the connection at point the ``default'' connection. It will then +be used for commands in @code{slime-mode} source buffers. + +@kbditem{g, slime-update-connection-list} +Update the connection list in the buffer. + +@kbditem{q, slime-temp-buffer-quit} +Quit the connection list (kill buffer, restore window configuration). + +@kbditem{R, slime-restart-connection-at-point} +Restart the Lisp process for the connection at point. + +@cmditem{slime-connect} +Connect to a running Swank server. + +@cmditem{slime-disconnect} +Disconnect all connections. + +@cmditem{slime-abort-connection} +Abort the current attempt to connect. + +@end table + + +@c ----------------------- +@node Customization +@chapter Customization + +@menu +* Emacs-side customization:: +* Lisp-side:: +@end menu + +@c ----------------------- +@node Emacs-side customization +@section Emacs-side + +The Emacs part of @SLIME{} can be configured with the Emacs +@code{customize} system, just use @kbd{M-x customize-group slime +RET}. Because the customize system is self-describing, we only cover a +few important or obscure configuration options here in the manual. + +@table @code + +@item slime-truncate-lines +The value to use for @code{truncate-lines} in line-by-line summary +buffers popped up by @SLIME{}. This is @code{t} by default, which +ensures that lines do not wrap in backtraces, apropos listings, and so +on. It can however cause information to spill off the screen. + +@anchor{slime-completion-at-point-functions} +@vindex slime-completion-at-point-functions +@item slime-completion-at-point-functions +A list of functions used for completion of Lisp symbols. This works +as the standard +@code{completion-at-point-functions} +(@pxref{Completion in Buffers,,,elisp}). Three completion +styles are available: @code{slime-simple-completion-at-point}, +@code{slime-complete-symbol*} (@pxref{Compound Completion}), +and @code{slime-fuzzy-complete-symbol} (@pxref{Fuzzy Completion}). + +The default is @code{slime-simple-completion-at-point}, which +completes in the usual Emacs way. + +@vindex slime-filename-translations +@item slime-filename-translations +This variable controls filename translation between Emacs and the Lisp +system. It is useful if you run Emacs and Lisp on separate machines +which don't share a common file system or if they share the filesystem +but have different layouts, as is the case with @acronym{SMB}-based +file sharing. + +@anchor{slime-net-coding-system} +@vindex slime-net-coding-system +@cindex Unicode +@cindex UTF-8 +@cindex ASCII +@cindex LATIN-1 +@cindex Character Encoding +@item slime-net-coding-system +If you want to transmit Unicode characters between Emacs and the Lisp +system, you should customize this variable. E.g., if you use SBCL, you +can set: +@example +(setq slime-net-coding-system 'utf-8-unix) +@end example +To actually display Unicode characters you also need appropriate +fonts, otherwise the characters will be rendered as hollow boxes. If +you are using Allegro CL and GNU Emacs, you can also +use @code{emacs-mule-unix} as coding system. GNU Emacs has often +nicer fonts for the latter encoding. (Different encodings can be used +for different Lisps, see @ref{Multiple Lisps}.) + +@end table + +@menu +* Hooks:: +@end menu + +@c ----------------------- +@node Hooks +@subsection Hooks + +@table @code + +@vindex slime-mode-hook +@item slime-mode-hook +This hook is run each time a buffer enters @code{slime-mode}. It is +most useful for setting buffer-local configuration in your Lisp source +buffers. An example use is to enable @code{slime-autodoc-mode} +(@pxref{slime-autodoc-mode}). + +@anchor{slime-connected-hook} +@vindex slime-connected-hook +@item slime-connected-hook +This hook is run when @SLIME{} establishes a connection to a Lisp +server. An example use is to create a Typeout frame (@xref{Typeout frames}.) + +@vindex sldb-hook +@item sldb-hook +This hook is run after @SLDB{} is invoked. The hook functions are +called from the @SLDB{} buffer after it is initialized. An example use +is to add @code{sldb-print-condition} to this hook, which makes all +conditions debugged with @SLDB{} be recorded in the @REPL{} buffer. + +@end table + +@c ----------------------- +@node Lisp-side +@section Lisp-side (Swank) + +The Lisp server side of @SLIME{} (known as ``Swank'') offers several +variables to configure. The initialization file @file{~/.swank.lisp} +is automatically evaluated at startup and can be used to set these +variables. + +@menu +* Communication style:: +* Other configurables:: +@end menu + +@c ----------------------- +@node Communication style +@subsection Communication style +@vindex SWANK:*COMMUNICATION-STYLE* + +The most important configurable is @code{SWANK:*COMMUNICATION-STYLE*}, +which specifies the mechanism by which Lisp reads and processes +protocol messages from Emacs. The choice of communication style has a +global influence on @SLIME{}'s operation. + +The available communication styles are: + +@table @code +@item NIL +This style simply loops reading input from the communication socket +and serves @SLIME{} protocol events as they arise. The simplicity +means that the Lisp cannot do any other processing while under +@SLIME{}'s control. + +@item :FD-HANDLER +This style uses the classical Unix-style ``@code{select()}-loop.'' +Swank registers the communication socket with an event-dispatching +framework (such as @code{SERVE-EVENT} in @acronym{CMUCL} and +@acronym{SBCL}) and receives a callback when data is available. In +this style requests from Emacs are only detected and processed when +Lisp enters the event-loop. This style is simple and predictable. + +@item :SIGIO +This style uses @dfn{signal-driven I/O} with a @code{SIGIO} signal +handler. Lisp receives requests from Emacs along with a signal, +causing it to interrupt whatever it is doing to serve the +request. This style has the advantage of responsiveness, since Emacs +can perform operations in Lisp even while it is busy doing other +things. It also allows Emacs to issue requests concurrently, e.g. to +send one long-running request (like compilation) and then interrupt +that with several short requests before it completes. The +disadvantages are that it may conflict with other uses of @code{SIGIO} +by Lisp code, and it may cause untold havoc by interrupting Lisp at an +awkward moment. + +@item :SPAWN +This style uses multiprocessing support in the Lisp system to execute +each request in a separate thread. This style has similar properties +to @code{:SIGIO}, but it does not use signals and all requests issued +by Emacs can be executed in parallel. + +@end table + +The default request handling style is chosen according to the +capabilities of your Lisp system. The general order of preference is +@code{:SPAWN}, then @code{:SIGIO}, then @code{:FD-HANDLER}, with +@code{NIL} as a last resort. You can check the default style by +calling @code{SWANK-BACKEND::PREFERRED-COMMUNICATION-STYLE}. You can +also override the default by setting +@code{SWANK:*COMMUNICATION-STYLE*} in your Swank init file. + +@c ----------------------- +@node Other configurables +@subsection Other configurables + +These Lisp variables can be configured via your @file{~/.swank.lisp} +file: + +@table @code + +@vindex SWANK:*CONFIGURE-EMACS-INDENTATION* +@item SWANK:*CONFIGURE-EMACS-INDENTATION* +This variable controls whether indentation styles for +@code{&body}-arguments in macros are discovered and sent to Emacs. It +is enabled by default. + +@vindex SWANK:*GLOBALLY-REDIRECT-IO* +@item SWANK:*GLOBALLY-REDIRECT-IO* +When T this causes the standard streams (@code{*standard-output*}, +etc) to be globally redirected to the @REPL{} in Emacs. + +When @code{:STARTED-FROM-EMACS} (default) redirects the output when +the lisp is launched from emacs (i.e. @kbd{M-x slime}), but not +from @kbd{M-x slime-connect}. + +When @code{NIL} these streams are only temporarily redirected +to Emacs using dynamic bindings while handling requests. Note that +@code{*standard-input*} is currently never globally redirected into +Emacs, because it can interact badly with the Lisp's native @REPL{} by +having it try to read from the Emacs one. + +@vindex SWANK:*GLOBAL-DEBUGGER* +@item SWANK:*GLOBAL-DEBUGGER* +When true (the default) this causes @code{*DEBUGGER-HOOK*} to be +globally set to @code{SWANK:SWANK-DEBUGGER-HOOK} and thus for @SLIME{} +to handle all debugging in the Lisp image. This is for debugging +multithreaded and callback-driven applications. + +@anchor{*SLDB-QUIT-RESTART*} +@vindex SWANK:*SLDB-QUIT-RESTART* +@item SWANK:*SLDB-QUIT-RESTART* +This variable names the restart that is invoked when pressing @kbd{q} +(@pxref{sldb-quit}) in @SLDB{}. For @SLIME{} evaluation requests this +is @emph{unconditionally} bound to a restart that returns to a safe +point. This variable is supposed to customize what @kbd{q} does if an +application's thread lands into the debugger (see +@code{SWANK:*GLOBAL-DEBUGGER*}). +@example +(setf swank:*sldb-quit-restart* 'sb-thread:terminate-thread) +@end example + +@vindex SWANK:*BACKTRACE-PRINTER-BINDINGS* +@vindex SWANK:*MACROEXPAND-PRINTER-BINDINGS* +@vindex SWANK:*SLDB-PRINTER-BINDINGS* +@vindex SWANK:*SWANK-PPRINT-BINDINGS* +@item SWANK:*BACKTRACE-PRINTER-BINDINGS* +@itemx SWANK:*MACROEXPAND-PRINTER-BINDINGS* +@itemx SWANK:*SLDB-PRINTER-BINDINGS* +@itemx SWANK:*SWANK-PPRINT-BINDINGS* +These variables can be used to customize the printer in various +situations. The values of the variables are association lists of +printer variable names with the corresponding value. E.g., to enable +the pretty printer for formatting backtraces in @SLDB{}, you can use: +@example +(push '(*print-pretty* . t) swank:*sldb-printer-bindings*). +@end example + +@vindex SWANK:*USE-DEDICATED-OUTPUT-STREAM* +@item SWANK:*USE-DEDICATED-OUTPUT-STREAM* +This variable controls whether to use an unsafe efficiency hack for +sending printed output from Lisp to Emacs. The default is @code{nil}, +don't use it, and is strongly recommended to keep. + +When @code{t}, a separate socket is established solely for Lisp to send +printed output to Emacs through, which is faster than sending the output +in protocol-messages to Emacs. However, as nothing can be guaranteed +about the timing between the dedicated output stream and the stream of +protocol messages, the output of a Lisp command can arrive before or +after the corresponding REPL results. Thus output and REPL results can +end up in the wrong order, or even interleaved, in the REPL buffer. +Using a dedicated output stream also makes it more difficult to +communicate to a Lisp running on a remote host via SSH +(@pxref{Connecting to a remote lisp}). + +@vindex SWANK:*DEDICATED-OUTPUT-STREAM-PORT* +@item SWANK:*DEDICATED-OUTPUT-STREAM-PORT* +When @code{*USE-DEDICATED-OUTPUT-STREAM*} is @code{t} the stream will +be opened on this port. The default value, @code{0}, means that the +stream will be opened on some random port. + +@vindex SWANK:*LOG-EVENTS* +@item SWANK:*LOG-EVENTS* +Setting this variable to @code{t} causes all protocol messages +exchanged with Emacs to be printed to @code{*TERMINAL-IO*}. This is +useful for low-level debugging and for observing how @SLIME{} works +``on the wire.'' The output of @code{*TERMINAL-IO*} can be found in +your Lisp system's own listener, usually in the buffer +@code{*inferior-lisp*}. + +@end table + +@c ----------------------- +@node Tips and Tricks +@chapter Tips and Tricks + +@menu +* Connecting to a remote lisp:: +* Global IO Redirection:: +* Auto-SLIME:: +@end menu + +@c ----------------------- +@node Connecting to a remote lisp +@section Connecting to a remote lisp + +One of the advantages of the way @SLIME{} is implemented is that we can +easily run the Emacs side (slime.el) on one machine and the lisp backend +(swank) on another. The basic idea is to start up lisp on the remote +machine, load swank and wait for incoming @SLIME{} connections. On the +local machine we start up emacs and tell @SLIME{} to connect to the +remote machine. The details are a bit messier but the underlying idea is +that simple. + +@menu +* Setting up the lisp image:: +* Setting up Emacs:: +* Setting up pathname translations:: +@end menu + +@c ----------------------- +@node Setting up the lisp image +@subsection Setting up the lisp image + +When you want to load swank without going through the normal, Emacs +based, process just load the @file{swank-loader.lisp} file. Just +execute + +@example +(load "/path/to/swank-loader.lisp") +(swank-loader:init) +@end example + +inside a running lisp image@footnote{@SLIME{} also provides an +@acronym{ASDF} system definition which does the same thing}. Now all we +need to do is startup our swank server. The first example assumes we're +using the default settings. + +@example +(swank:create-server) +@end example + +Since we're going to be tunneling our connection via ssh@footnote{there +is a way to connect without an ssh tunnel, but it has the side-effect of +giving the entire world access to your lisp image, so we're not going to +talk about it} and we'll only have one port open we want to tell swank +to not use an extra connection for output (this is actually the default +in current @SLIME{}): + +@example +(setf swank:*use-dedicated-output-stream* nil) +@end example + +@c ----------------------- +If you need to do anything particular +(like be able to reconnect to swank after you're done), look into +@code{swank:create-server}'s other arguments. Some of these arguments +are +@table @code + +@item :PORT +Port number for the server to listen on (default: 4005). +@item :STYLE +See @xref{Communication style}. +@item :DONT-CLOSE +Boolean indicating if the server will continue to accept connections +after the first one (default: @code{NIL}). For ``long-running'' lisp processes +to which you want to be able to connect from time to time, +specify @code{:dont-close t} +@item :CODING-SYSTEM +String designating the encoding to be used to communicate between the +Emacs and Lisp. +@end table + +So the more complete example will be +@example +(swank:create-server :port 4005 :dont-close t :coding-system "utf-8-unix") +@end example +On the emacs side you will use something like +@example +(setq slime-net-coding-system 'utf-8-unix) +(slime-connect "localhost" 4005)) +@end example +to connect to this lisp image from the same machine. + + +@node Setting up Emacs +@subsection Setting up Emacs + +Now we need to create the tunnel between the local machine and the +remote machine. + +@example +ssh -L4005:localhost:4005 username@@remote.example.com +@end example + +That ssh invocation creates an ssh tunnel between the port 4005 on our +local machine and the port 4005 on the remote machine@footnote{By +default swank listens for incoming connections on port 4005, had we +passed a @code{:port} parameter to @code{swank:create-server} we'd be +using that port number instead}. + +Finally we can start @SLIME{}: + +@example +M-x slime-connect RET RET +@end example + +The @kbd{RET RET} sequence just means that we want to use the default +host (@code{localhost}) and the default port (@code{4005}). Even +though we're connecting to a remote machine the ssh tunnel fools Emacs +into thinking it's actually @code{localhost}. + +@c ----------------------- +@node Setting up pathname translations +@subsection Setting up pathname translations + +One of the main problems with running swank remotely is that Emacs +assumes the files can be found using normal filenames. if we want +things like @code{slime-compile-and-load-file} (@kbd{C-c C-k}) and +@code{slime-edit-definition} (@kbd{M-.}) to work correctly we need to +find a way to let our local Emacs refer to remote files. + +There are, mainly, two ways to do this. The first is to mount, using +NFS or similar, the remote machine's hard disk on the local machine's +file system in such a fashion that a filename like +@file{/opt/project/source.lisp} refers to the same file on both +machines. Unfortunately NFS is usually slow, often buggy, and not +always feasible, fortunately we have an ssh connection and Emacs' +@code{tramp-mode} can do the rest. +(See @inforef{Top, TRAMP User Manual,tramp}.) + +What we do is teach Emacs how to take a filename on the remote machine +and translate it into something that tramp can understand and access +(and vice versa). Assuming the remote machine's host name is +@code{remote.example.com}, @code{cl:machine-instance} returns +``remote'' and we login as the user ``user'' we can use @code{slime-tramp} +contrib to setup the proper translations by simply doing: + +@example +(add-to-list 'slime-filename-translations + (slime-create-filename-translator + :machine-instance "remote" + :remote-host "remote.example.com" + :username "user")) +@end example + +@c ----------------------- +@node Global IO Redirection +@section Globally redirecting all IO to the REPL + +When connecting via @kbd{M-x slime-connect} @SLIME{} does +not change @code{*standard-output*} and friends outside of the +@REPL{}. If you have any other threads which call @code{format}, +@code{write-string}, etc. that output will be seen only in +the @code{*inferior-lisp*} buffer or on the terminal, more often than +not this is inconvenient. So, if you want code such as this: + +@example +(run-in-new-thread + (lambda () + (write-line "In some random thread.~%" *standard-output*))) +@end example + +to send its output to @SLIME{}'s repl buffer, as opposed to +@code{*inferior-lisp*}, set @code{swank:*globally-redirect-io*} to T +in @file{~/.swank.lisp} + +But when started using @kbd{M-x slime} the streams are redirected by +default. + +@c ----------------------- +@node Auto-SLIME +@section Connecting to SLIME automatically + +To make @SLIME{} connect to your lisp whenever you open a lisp file +just add this to your @file{.emacs}: + +@example +(add-hook 'slime-mode-hook + (lambda () + (unless (slime-connected-p) + (save-excursion (slime))))) +@end example + +@node Contributed Packages +@chapter Contributed Packages + +In version 2.1 we moved some functionality to separate packages. This +chapter tells you how to load contrib modules and describes what the +particular packages do. + +@menu +* Loading Contribs:: +* REPL:: +* slime-mrepl:: +* inferior-slime-mode:: +* Compound Completion:: +* Fuzzy Completion:: +* slime-autodoc-mode:: +* ASDF:: +* Banner:: +* Editing Commands:: +* Fancy Inspector:: +* Presentations:: +* Typeout frames:: +* TRAMP:: +* Documentation Links:: +* Xref and Class Browser:: +* Highlight Edits:: +* Scratch Buffer:: +* SLIME Trace Dialog:: +* slime-sprof:: +* SLIME Enhanced M-.:: +* slime-fancy:: +* Quicklisp:: +@end menu + +@node Loading Contribs +@section Loading Contrib Packages + +@cindex Contribs +@cindex Contributions +@cindex Plugins + +Contrib packages aren't loaded by default. You have to modify your +setup a bit so that Emacs knows where to find them and which of them +to load. Generally, you set the variable @code{slime-contribs} with +the list of package-names that you want to use. For example, a setup +to load the @code{slime-scratch} and @code{slime-editing-commands} +packages looks like: + +@example +;; @emph{Setup load-path and autoloads} +(add-to-list 'load-path "~/dir/to/cloned/slime") +(require 'slime-autoloads) + +;; @emph{Set your lisp system and some contribs} +(setq inferior-lisp-program "/opt/sbcl/bin/sbcl") +(setq slime-contribs '(slime-scratch slime-editing-commands)) +@end example + +After starting @SLIME{}, the commands of both packages should be +available. + +The REPL and @code{slime-fancy} modules deserve special mention. Many +users consider the REPL (@pxref{REPL}) essential +while @code{slime-fancy} (@pxref{slime-fancy}) loads the REPL and +almost all of the popular contribs. So, if you aren't sure what to +choose start with: + +@example +(setq slime-contribs '(slime-repl)) ; repl only +@end example + +If you like what you see try this: + +@example +(setq slime-contribs '(slime-fancy)) ; almost everything +@end example + +@subsection Loading and unloading ``on the fly'' + +We recommend that you setup contribs @emph{before} starting @SLIME{} via +@kbd{M-x slime}, but if you want to enable more contribs @emph{after} +you do that, you can set the @code{slime-contribs} variable to another +value and call @code{M-x slime-setup}. Note this though: + +@itemize @bullet +@item +If you've removed contribs from the list they won't be unloaded +automatically. +@item +If you have more than one @SLIME{} connection currently active, you must +manually repeat the @code{slime-setup} step for each of them. +@end itemize + +Short of restarting Emacs, a reasonable way of unloading contribs is +by calling an Emacs Lisp function whose name is obtained by +adding @code{-unload} to the contrib's name, for every contrib you +wish to unload. So, to remove @code{slime-repl}, you must call +@code{slime-repl-unload}. Because the unload function will only, if +ever, unload the Emacs Lisp side of the contrib, you may also need to +restart your lisps. + +@c ----------------------- +@node REPL +@section REPL: the ``top level'' + +@cindex Listener + +@SLIME{} uses a custom Read-Eval-Print Loop (@REPL{}, also known as a +``top level'', or listener). The @REPL{} user-interface is written in +Emacs Lisp, which gives more Emacs-integration than the traditional +@code{comint}-based Lisp interaction: + +@itemize @bullet +@item +Conditions signalled in @REPL{} expressions are debugged with @SLDB{}. +@item +Return values are distinguished from printed output by separate Emacs +faces (colours). +@item +Emacs manages the @REPL{} prompt with markers. This ensures that Lisp +output is inserted in the right place, and doesn't get mixed up with +user input. +@end itemize + +To load the REPL use @code{(add-to-list 'slime-contribs 'slime-repl)} in your +@code{.emacs}. + +@table @kbd + +@kbditem{C-c C-z, slime-switch-to-output-buffer} +Select the output buffer, preferably in a different window. + +@kbditem{C-c C-y, slime-call-defun} +Insert a call to the function defined around point into the REPL. + +@kbditem{C-c C-j, slime-eval-last-expression-in-repl} +Inserts the last expression to the REPL and evaluates it there. +Switches to the current packae of the source buffer for the duration. +If used with a prefix argument, doesn't switch back afterwards. + +@end table + +@menu +* REPL commands:: +* Input Navigation:: +* Shortcuts:: +@end menu + +@c ----------------------- +@node REPL commands +@subsection REPL commands + +@table @kbd + +@kbditem{RET, slime-repl-return} +Evaluate the current input in Lisp if it is complete. If incomplete, +open a new line and indent. If a prefix argument is given then the +input is evaluated without checking for completeness. + +@kbditem{C-RET, slime-repl-closing-return} +Close any unmatched parenthesis and then evaluate the current input in +Lisp. Also bound to @kbd{M-RET}. + +@kbditem{TAB, slime-indent-and-complete-symbol} +Indent the current line and perform symbol completion. + +@kbditem{C-j, slime-repl-newline-and-indent} +Open and indent a new line. + +@kbditem{C-a, slime-repl-bol} +Go to the beginning of the line, but stop at the @REPL{} prompt. + +@c @anchor{slime-interrupt} +@kbditem{C-c C-c, slime-interrupt} +Interrupt the Lisp process with @code{SIGINT}. + +@c @kbditem{C-c M-g, slime-quit} +@c Quit @SLIME{}. + +@kbditem{C-c M-o, slime-repl-clear-buffer} +Clear the entire buffer, leaving only a prompt. + +@kbditem{C-c C-o, slime-repl-clear-output} +Remove the output and result of the previous expression from the +buffer. + +@end table + +@c ----------------------- +@node Input Navigation +@subsection Input navigation + +@cindex Input History + +The input navigation (a.k.a. history) commands are modelled after +@code{coming}-mode. Be careful if you are used to Bash-like +keybindings: @kbd{M-p} and @kbd{M-n} use the current input as search +pattern and only work Bash-like if the current line is +empty. @kbd{C-} and @kbd{C-} work like the up and down keys in +Bash. + +@table @kbd + +@kbditempair{C-, C-, slime-repl-forward-input, slime-repl-backward-input} +Go to the next/previous history item. + +@kbditempair{M-n, M-p, slime-repl-next-input, slime-repl-previous-input} +Search the next/previous item in the command history using the current +input as search pattern. If @kbd{M-n}/@kbd{M-n} is typed two times in +a row, the second invocation uses the same search pattern (even if the +current input has changed). + +@kbditempair{M-s, M-r, slime-repl-next-matching-input, slime-repl-previous-matching-input} +Search forward/reverse through command history with regex + +@c @code{slime-repl-@{next,previous@}-input}@* +@c @code{slime-repl-@{next,previous@}-matching-input}@* +@c @code{comint}-style input history commands. + +@kbditempair{C-c C-n, C-c C-p, slime-repl-next-prompt, slime-repl-previous-prompt} +Move between the current and previous prompts in the @REPL{} buffer. +Pressing RET on a line with old input copies that line to the newest +prompt. +@end table + +@vindex slime-repl-wrap-history +The variable @code{slime-repl-wrap-history} controls wrap around +behaviour, i.e. whether cycling should restart at the beginning of the +history if the end is reached. + +@c ----------------------- +@comment node-name, next, previous, up +@node Shortcuts +@subsection Shortcuts + +@cindex Shortcuts + +``Shortcuts'' are a special set of @REPL{} commands that are invoked +by name. To invoke a shortcut you first press @kbd{,} (comma) at the +@REPL{} prompt and then enter the shortcut's name when prompted. + +Shortcuts deal with things like switching between directories and +compiling and loading Lisp systems. The set of shortcuts is listed +below, and you can also use the @code{help} +shortcut to list them interactively. + +@table @kbd +@item change-directory (aka !d, cd) +Change the current directory. + +@item change-package (aka !p, in, in-package) +Change the current package. + +@item compile-and-load (aka cl) +Compile (if necessary) and load a lisp file. + +@item defparameter (aka !) +Define a new global, special, variable. + +@item disconnect +Disconnect all connections. + +@item help (aka ?) +Display the help. + +@item pop-directory (aka -d) +Pop the current directory. + +@item pop-package (aka -p) +Pop the top of the package stack. + +@item push-directory (aka +d, pushd) +Push a new directory onto the directory stack. + +@item push-package (aka +p) +Push a package onto the package stack. + +@item pwd +Show the current directory. + +@item quit +Quit the current Lisp. + +@item resend-form +Resend the last form. + +@item restart-inferior-lisp +Restart *inferior-lisp* and reconnect @SLIME{}. + +@item sayoonara +Quit all Lisps and close all @SLIME{} buffers. + +@end table + +@node slime-mrepl +@section Multiple REPLs + +The @code{slime-mrepl} package adds support for multiple listener +buffers. The command @kbd{M-x slime-new-mrepl} creates a new +buffer. In a multi-threaded Lisp, each listener is associated with a +separate thread. In a single-threaded Lisp it's also possible to +create multiple listener buffers but the commands are executed +sequentially by the same process. + +@node inferior-slime-mode +@section @code{inferior-slime-mode} + +The @code{inferior-slime-mode} is a minor mode is intended to use with +the @code{*inferior-lisp*} lisp buffer. It provides some of the +@SLIME{} commands, like symbol completion and documentation lookup. It +also tracks the current directory of the Lisp process. To install it, +add something like this to user @file{.emacs}: + +@example +(add-to-list 'slime-contribs 'inferior-slime) +@end example + +@table @kbd +@cmditem{inferior-slime-mode} +Turns inferior-slime-mode on or off. +@end table + +@vindex inferior-slime-mode-map +The variable @code{inferior-slime-mode-map} contains the extra +keybindings. + +@node Compound Completion +@section Compound Completion + +@anchor{slime-complete-symbol*} +The package @code{slime-c-p-c} provides a different symbol completion +algorithm, which performs completion ``in parallel'' over the +hyphen-delimited sub-words of a symbol name. +@footnote{This style of completion is modelled on @file{completer.el} +by Chris McConnell. That package is bundled with @acronym{ILISP}.} +Formally this means that ``@code{a-b-c}'' can complete to any symbol +matching the regular expression ``@code{^a.*-b.*-c.*}'' (where ``dot'' +matches anything but a hyphen). Examples give a more intuitive +feeling: +@itemize @bullet +@item +@code{m-v-b} completes to @code{multiple-value-bind}. +@item +@code{w-open} is ambiguous: it completes to either +@code{with-open-file} or @code{with-open-stream}. The symbol is +expanded to the longest common completion (@code{with-open-}) and the +point is placed at the first point of ambiguity, which in this case is +the end. +@item +@code{w--stream} completes to @code{with-open-stream}. +@end itemize + +The variable @code{slime-c-p-c-unambiguous-prefix-p} specifies where +point should be placed after completion. E.g. the possible +completions for @code{f-o} are @code{finish-output} and +@code{force-output}. By the default point is moved after the +@code{f}, because that is the unambiguous prefix. If +@code{slime-c-p-c-unambiguous-prefix-p} is nil, point moves to +the end of the inserted text, after the @code{o} in this case. + +In addition, @code{slime-c-p-c} provides completion for character names +(mostly useful for Unicode-aware implementations): + +@example +CL-USER> #\Sp +@end example + +Here @SLIME{} will usually complete the character to @code{#\Space}, but +in a Unicode-aware implementation, this might provide the following +completions: +@example +Space Space +Sparkle Spherical_Angle +Spherical_Angle_Opening_Left Spherical_Angle_Opening_Up +@end example + +The package @code{slime-c-p-c} also provides context-sensitive +completion for keywords. Example: + +@example +CL-USER> (find 1 '(1 2 3) :s +@end example + +Here @SLIME{} will complete @code{:start}, rather than suggesting all +ever-interned keywords starting with @code{:s}. + + +@table @kbd +@kbditem{C-c C-s, slime-complete-form} +Looks up and inserts into the current buffer the argument list for the +function at point, if there is one. More generally, the command +completes an incomplete form with a template for the missing arguments. +There is special code for discovering extra keywords of generic +functions and for handling @code{make-instance}, +@code{defmethod}, and many other functions. Examples: + +@example +(subseq "abc" + --inserts--> start [end]) +(find 17 + --inserts--> sequence :from-end from-end :test test + :test-not test-not :start start :end end + :key key) +(find 17 '(17 18 19) :test #'= + --inserts--> :from-end from-end + :test-not test-not :start start :end end + :key key) +(defclass foo () ((bar :initarg :bar))) +(defmethod print-object + --inserts--> (object stream) + body...) +(defmethod initialize-instance :after ((object foo) &key blub)) +(make-instance 'foo + --inserts--> :bar bar :blub blub initargs...) +@end example +@end table + +@node Fuzzy Completion +@section Fuzzy Completion + +The package @code{slime-fuzzy} implements yet another symbol +completion heuristic. + +@table @kbd +@anchor{slime-fuzzy-complete-symbol} +@kbditem{C-c M-i, slime-fuzzy-complete-symbol} +Presents a list of likely completions to choose from for an +abbreviation at point. If you set the +variable @code{slime-complete-symbol-function} to this command, fuzzy +completion will also be used for @kbd{M-TAB}. +@end table + +@subsection The Algorithm + +It attempts to complete a symbol all at once, instead of in pieces. +For example, ``mvb'' will find ``@code{multiple-value-bind}'' and +``norm-df'' will find +``@code{least-positive-normalized-double-float}''. + +The algorithm tries to expand every character in various ways and +rates the list of possible completions with the following heuristic. + +Letters are given scores based on their position in the string. +Letters at the beginning of a string or after a prefix letter at +the beginning of a string are scored highest. Letters after a +word separator such as #\- are scored next highest. Letters at +the end of a string or before a suffix letter at the end of a +string are scored medium, and letters anywhere else are scored +low. + +If a letter is directly after another matched letter, and its +intrinsic value in that position is less than a percentage of the +previous letter's value, it will use that percentage instead. + +Finally, a small scaling factor is applied to favor shorter +matches, all other things being equal. + +@subsection Duplicate Symbols + +In case a symbol is accessible via several packages, duplicate symbol +filter specified via @code{*fuzzy-duplicate-symbol-filter*} swank +variable is applied. @code{:nearest-package} value specifies that only +symbols in the package with highest score should be kept. +@code{:home-package} specifies that only the match that represents the home +package of the symbol is used, and @code{:all} value specifies that +duplicate symbol filter mode should be turned off. + +To specify a custom filter, set @code{*fuzzy-duplicate-symbol-filter*} +to a function accepting three arguments: the name of package being +examined, the list of names of all packages being examined with +packages with highest matching score listed first and an @code{equal} +hash-table that is shared between calls to the function and can be +used for deduplication purposes. The function should return a +deduplication filter function which accepts a symbol and returns true +if the symbol should be kept. + +For example, the effect of @code{:nearest-package} can be also achieved +by specifying the following custom filter in @file{~/.swank.lisp}: +@example +(setf *fuzzy-duplicate-symbol-filter* + (lambda (cur-package all-packages dedup-table) + (declare (ignore cur-package all-packages)) + (lambda (symbol) + (unless (gethash (symbol-name symbol) dedup-table) + (setf (gethash (symbol-name symbol) dedup-table) t))))) +@end example +And instead of @code{:home-package}, the following can be used: +@example +(setf *fuzzy-duplicate-symbol-filter* + (lambda (cur-package all-packages dedup-table) + (declare (ignore dedup-table)) + (let ((packages (mapcar #'find-package + (remove cur-package all-packages)))) + (lambda (symbol) + (not (member (symbol-package symbol) packages)))))) +@end example + +@node slime-autodoc-mode +@section @code{slime-autodoc-mode} + +Autodoc mode is an additional minor-mode for automatically showing +information about symbols near the point. For function names the +argument list is displayed, and for global variables, the value. +Autodoc is implemented by means of @code{eldoc-mode} of Emacs. + +The mode can be enabled by default in your @code{~/.emacs}: +@example +(add-to-list 'slime-contribs 'slime-autodoc) +@end example + +@table @kbd +@cmditem{slime-arglist NAME} +Show the argument list of the function NAME. + +@cmditem{slime-autodoc-mode} +Toggles autodoc-mode on or off according to the argument, and +toggles the mode when invoked without argument. +@kbditem{C-c C-d a, slime-autodoc-manually} +Like slime-autodoc, but when called twice, +or after slime-autodoc was already automatically called, +display multiline arglist. +@end table + +@vindex slime-use-autodoc-mode +If the variable @code{slime-use-autodoc-mode} is set (default), Emacs +starts a timer, otherwise the information is only displayed after +pressing SPC. + +@vindex slime-autodoc-use-multiline-p +If @code{slime-autodoc-use-multiline-p} is set to non-nil, +allow long autodoc messages to resize echo area display. + +@vindex slime-autodoc-mode-string +@code{slime-autodoc-mode-string} is a string that will be displayed in +the mode line when autodoc-mode is enabled, or nil, if you prefer no +indication. You can customize this variable. + +@node ASDF +@section ASDF + +@acronym{ASDF} is a popular ``system construction tool''. The package +@code{slime-asdf} provides some commands to load and compile such +systems from Emacs. @acronym{ASDF} itself is not included with +@SLIME{}; you have to load that yourself into your Lisp. In +particular, you must load @acronym{ASDF} before you connect, otherwise +you will get errors about missing symbols. + +@table @kbd +@cmditem{slime-load-system NAME} +Compile and load an ASDF system. The default system name is taken +from the first file matching *.asd in the current directory. +@cmditem{slime-reload-system NAME} +Recompile and load an ASDF system without recompiling its dependencies. +@cmditem{slime-open-system NAME &optional LOAD} +Open all files in a system, optionally load it if LOAD is non-nil. +@cmditem{slime-browse-system NAME} +Browse files in a system using Dired. +@cmditem{slime-delete-system-fasls NAME} +Delete FASLs produced by compiling a system. +@cmditem{slime-rgrep-system NAME REGEXP} +Run @code{rgrep} on the base directory of an ASDF system. +@cmditem{slime-isearch-system NAME} +Run @code{isearch-forward} on the files of an ASDF system. +@cmditem{slime-query-replace-system NAME FROM TO &OPTIONAL DELIMITED} +Run @code{query-replace} on an ASDF system. +@end table +The package also installs some new REPL shortcuts (@pxref{Shortcuts}): + +@table @kbd +@item load-system +Compile (as needed) and load an ASDF system. +@item reload-system +Recompile and load an ASDF system. +@item compile-system +Compile (but not load) an ASDF system. +@item force-compile-system +Recompile (but not load) an ASDF system. +@item force-load-system +Recompile and load an ASDF system. +@item open-system +Open all files in a system. +@item browse-system +Browse files in a system using Dired. +@item delete-system-fasls +Delete FASLs produced by compiling a system. +@end table + +@node Banner +@section Banner +The package @code{slime-banner} installs a window header line ( +@inforef{Header Lines, , elisp}.) in the REPL buffer. It also runs an +animation at startup. + +@vindex slime-startup-animation +@vindex slime-header-line-p +By setting the variable @code{slime-startup-animation} to nil you can +disable the animation respectively with the +variable @code{slime-header-line-p} the header line. + +@node Editing Commands +@section Editing Commands + +The package @code{slime-editing-commands} provides some commands to +edit Lisp expressions. + +@table @kbd +@kbditem{C-c M-q, slime-reindent-defun} +Re-indents the current defun, or refills the current paragraph. +If point is inside a comment block, the text around point will be +treated as a paragraph and will be filled with @code{fill-paragraph}. +Otherwise, it will be treated as Lisp code, and the current defun +will be reindented. If the current defun has unbalanced parens, +an attempt will be made to fix it before reindenting. + +@kbditem{C-c C-], slime-close-all-parens-in-sexp} +Balance parentheses of open s-expressions at point. +Insert enough right parentheses to balance unmatched left parentheses. +Delete extra left parentheses. Reformat trailing parentheses +Lisp-stylishly. + +If REGION is true, operate on the region. Otherwise operate on +the top-level sexp before point. + +@cmditem{slime-insert-balanced-comments} +Insert a set of balanced comments around the s-expression containing +the point. If this command is invoked repeatedly (without any other +command occurring between invocations), the comment progressively +moves outward over enclosing expressions. If invoked with a positive +prefix argument, the s-expression arg expressions out is enclosed in a +set of balanced comments. + +@kbditem{M-C-a, slime-beginning-of-defun} +@kbditem{M-C-e, slime-end-of-defun} +@end table + +@node Fancy Inspector +@section Fancy Inspector + +@cindex Methods + +An alternative to default inspector is provided by the package +`slime-fancy-inspector'. This inspector knows a lot about CLOS +objects and methods. It provides many ``actions'' that can be +selected to invoke Lisp code on the inspected object. For example, to +present a generic function the inspector shows the documentation in +plain text and presents each method with both a hyperlink to inspect +the method object and a ``remove method'' action that you can invoke +interactively. The key-bindings are the same as for the basic +inspector (@pxref{Inspector}). + +@node Presentations +@section Presentations + +@cindex Presentations + +A ``presentation''@footnote{Presentations are a feature originating +from the Lisp machines. It was possible to define @code{present} +methods specialized to various devices, e.g. to draw an object to +bitmapped screen or to write some text to a character stream.} in +@SLIME{} is a region of text associated with a Lisp object. +Right-clicking on the text brings up a menu with operations for the +particular object. Some operations, like inspecting, are available +for all objects, but the object may also have specialized operations. +For instance, pathnames have a dired operation. + +More importantly, it is possible to cut and paste presentations (i.e., +Lisp objects, not just their printed presentation), using all standard +Emacs commands. This way it is possible to cut and paste the results of +previous computations in the REPL. This is of particular importance for +unreadable objects. + +The package @code{slime-presentations} installs presentations in the +REPL, i.e. the results of evaluation commands become presentations. In +this way, presentations generalize the use of the standard Common Lisp +REPL history variables @code{*}, @code{**}, @code{***}. Example: + +@example +CL-USER> (find-class 'standard-class) +@emph{#} +CL-USER> +@end example + +Presentations appear in red color in the buffer. +(In this manual, we indicate the presentations @emph{like this}.) +Using standard Emacs +commands, the presentation can be copied to a new input in the REPL: + +@example +CL-USER> (eql '@emph{#} + '@emph{#}) +@emph{T} +@end example + +Note that standard evaluation and quoting rules still apply. So if a +presentation is a list, it needs to be quoted in an evaluated context to +avoid treating it as a function call: + +@example +CL-USER> (list (find-class 'standard-class) 2 3 4) +@emph{(# 2 3 4)} +CL-USER> @emph{(# 2 3 4)} +; Funcall of # which is a non-function. +; Evaluation aborted. +CL-USER> '@emph{(# 2 3 4)} +(# 2 3 4) +@end example + +When you copy an incomplete presentation or edit the text within a +presentation, the presentation changes to plain text, losing the +association with a Lisp object. In the buffer, this is indicated by +changing the color of the text from red to black. This can be undone. + +Presentations are also available in the inspector (all inspectable parts +are presentations) and the debugger (all local variables are +presentations). This makes it possible to evaluate expressions in the +REPL using objects that appear in local variables of some active +debugger frame; this can be more convenient than using @code{M-x +sldb-eval-in-frame}. @strong{Warning:} The presentations that stem from +the inspector and debugger are only valid as long as the corresponding +buffers are open. Using them later can cause errors or confusing +behavior. + +For some Lisp implementations you can also install the package +@code{slime-presentation-streams}, which enables presentations on the +Lisp @code{*standard-output*} stream and similar streams. This means +that not only results +of computations, but also some objects that are printed to the standard +output (as a side-effect of the computation) are associated with +presentations. Currently, all unreadable objects +and pathnames get printed as presentations. + +@example +CL-USER> (describe (find-class 'standard-object)) +@emph{#} is an instance of + @emph{#}: + The following slots have :INSTANCE allocation: + PLIST NIL + FLAGS 1 + DIRECT-METHODS ((@emph{#} + ... +@end example + +Again, this makes it possible to inspect and copy-paste these objects. + +In addition to the standard Emacs commands, there are several keyboard +commands, a menu-bar menu, and a context menu to operate on +presentations. We describe the keyboard commands below; they are also +shown in the menu-bar menu. + +@table @kbd +@kbditem{C-c C-v SPC, slime-mark-presentation} +If point is within a presentation, move point to the beginning of the +presentation and mark to the end of the presentation. +This makes it possible to copy the presentation. + +@kbditem{C-c C-v w, slime-copy-presentation-at-point-to-kill-ring} +If point is within a presentation, copy the surrounding presentation +to the kill ring. + +@kbditem{C-c C-v r, slime-copy-presentation-at-point-to-repl} +If point is within a presentation, copy the surrounding presentation +to the REPL. + +@kbditem{C-c C-v d, slime-describe-presentation-at-point} +If point is within a presentation, describe the associated object. + +@kbditem{C-c C-v i, slime-inspect-presentation-at-point} +If point is within a presentation, inspect the associated object with +the @SLIME{} inspector. + +@kbditem{C-c C-v n, slime-next-presentation} +Move point to the next presentation in the buffer. + +@kbditem{C-c C-v p, slime-previous-presentation} +Move point to the previous presentation in the buffer. + +@end table +Similar operations are also possible from the context menu of every +presentation. Using @kbd{mouse-3} on a presentation, the context menu +opens and offers various commands. For some objects, specialized +commands are also offered. Users can define additional specialized +commands by defining a method for +@code{swank::menu-choices-for-presentation}. + + +@strong{Warning:} On Lisp implementations without weak hash tables, +all objects associated with presentations are protected from garbage +collection. If your Lisp image grows too large because of that, +use @kbd{C-c C-v M-o} (@code{slime-clear-presentations}) to remove these +associations. You can also use the command @kbd{C-c M-o} +(@code{slime-repl-clear-buffer}), which both clears the REPL buffer and +removes all associations of objects with presentations. + +@strong{Warning:} Presentations can confuse new users. + +@example +CL-USER> (cons 1 2) +@emph{(1 . 2)} +CL-USER> (eq '@emph{(1 . 2)} '@emph{(1 . 2)}) +@emph{T} +@end example + +One could have expected @code{NIL} here, because it looks like two +fresh cons cells are compared regarding object identity. +However, in the example the presentation @code{@emph{(1 . 2)}} was copied twice +to the REPL. Thus @code{EQ} is really invoked with the same object, +namely the cons cell that was returned by the first form entered in the +REPL. + +@node Typeout frames +@section Typeout frames + +@cindex Typeout Frame + +A ``typeout frame'' is a special Emacs frame which is used instead of +the echo area (minibuffer) to display messages from @SLIME{} commands. +This is an optional feature. The advantage of a typeout frame over the +echo area is that it can hold more text, it can be scrolled, and its +contents don't disappear when you press a key. All potentially long +messages are sent to the typeout frame, such as argument lists, macro +expansions, and so on. + +@table @kbd +@cmditem{slime-ensure-typeout-frame} +Ensure that a typeout frame exists, creating one if necessary. +@end table + +If the typeout frame is closed then the echo area will be used again +as usual. + +To have a typeout frame created automatically at startup you should +load the @code{slime-typeout-frame} package. (@pxref{Loading Contribs}.) + +The variable @code{slime-typeout-frame-properties} specifies the +height and possibly other properties of the frame. Its value is +passed to @code{make-frame}. (@inforef{Creating Frames, ,elisp}.) + +@node TRAMP +@section TRAMP + +@cindex TRAMP + +The package @code{slime-tramp} provides some functions to set up +filename translations for TRAMP. (@pxref{Setting up pathname +translations}) + +@node Documentation Links +@section Documentation Links + +For certain error messages, SBCL includes references to the ANSI +Standard or the SBCL User Manual. The @code{slime-references} package +turns those references into clickable links. This makes finding the +referenced section of the HyperSpec much easier. + +@node Xref and Class Browser +@section Xref and Class Browser + +A rudimentary class browser is provided by +the @code{slime-xref-browser} package. + +@table @kbd +@cmditem{slime-browse-classes} +This command asks for a class name and displays inheritance tree of +for the class. + +@cmditem{slime-browse-xrefs} +This command prompts for a symbol and the kind of cross reference, +e.g. callers. The cross reference tree rooted at the symbol is then +then displayed. + +@end table + + +@node Highlight Edits +@section Highlight Edits + +@code{slime-highlight-edits} is a minor mode to highlight those +regions in a Lisp source file which are modified. This is useful to +quickly find those functions which need to be recompiled (with +@kbd{C-c C-c}) + +@table @kbd +@cmditem{slime-highlight-edits-mode} +Turns @code{slime-highlight-edits-mode} on or off. +@end table + +@node Scratch Buffer +@section Scratch Buffer + +@anchor{slime-scratch} +The @SLIME{} scratch buffer, in contrib package @code{slime-scratch}, +imitates Emacs' usual @code{*scratch*} buffer. +If @code{slime-scratch-file} is set, it is used to back the scratch +buffer, making it persistent. The buffer is like any other Lisp +buffer, except for the command bound to @kbd{C-j}. + +@table @kbd + +@kbditem{C-j, slime-eval-print-last-expression} +Evaluate the expression sexp before point and insert print value into +the current buffer. + +@cmditem{slime-scratch} +Create a @file{*slime-scratch*} buffer. In this +buffer you can enter Lisp expressions and evaluate them with +@kbd{C-j}, like in Emacs's @file{*scratch*} buffer. + +@end table + +@node SLIME Trace Dialog +@section SLIME Trace Dialog + +The @SLIME{} Trace Dialog, in package @code{slime-trace-dialog}, is a +tracing facility, similar to Common Lisp's @code{trace}, but +interactive rather than purely textual. It is an Emacs 24-only +contrib. + +You use it just like you would regular @code{trace}: after tracing a +function, calling it causes interesting information about that +particular call to be reported. + +However, instead of printing the trace results to the +the @code{*trace-output*} stream (usually the REPL), the @SLIME{} +Trace Dialog collects and stores them in your lisp environment until, +on user's request, they are fetched into Emacs and displayed in a +dialog-like interactive view. + +To use this contrib, add it to @code{slime-contribs} in your +@code{~/.emacs}, either directly by setting up @code{slime-fancy} +(@pxref{slime-fancy}). + +@example +;; setting up 'slime-fancy would also have worked +(add-to-list 'slime-contribs 'slime-trace-dialog) +@end example + +After starting up @SLIME{}, @SLIME{}'s Trace Dialog installs +a @emph{Trace} menu in the menu-bar of any @code{slime-mode} buffer and +adds two new commands, with respective key-bindings: + +@table @kbd +@kbditem{C-c M-t, slime-trace-dialog-toggle-trace} +If point is on a symbol name, toggle tracing of its function +definition. If point is not on a symbol, prompt user for a function. + +With a @kbd{C-u} prefix argument, and if your lisp implementation +allows it, attempt to decipher lambdas, methods and other complicated +function signatures. + +The function is traced for the @SLIME{} Trace Dialog only, i.e. it is +not found in the list returned by Common Lisp's @code{trace}. + +@kbditem{C-c T, slime-trace-dialog} +Pop to the interactive SLIME Trace Dialog buffer associated with the +current connection (@pxref{Multiple connections}). +@end table + +@page +Consider the (useless) program: + +@example +(defun foo (n) (if (plusp n) (* n (bar (1- n))) 1)) +(defun bar (n) (if (plusp n) (* n (foo (1- n))) 1)) +@end example + +After tracing both @code{foo} and @code{bar} with @kbd{C-c M-t}, +calling call @code{(foo 2)} and moving to the trace dialog with +@kbd{C-c T}, we are presented with this buffer. + +@example +Traced specs (2) [refresh] + [untrace all] + [untrace] common-lisp-user::bar + [untrace] common-lisp-user::foo + +Trace collection status (3/3) [refresh] + [clear] + + 0 - common-lisp-user::foo + | > 2 + | < 2 + 1 `--- common-lisp-user::bar + | > 1 + | < 1 + 2 `-- common-lisp-user::foo + > 0 + < 1 +@end example + +The dialog is divided into sections displaying the functions already +traced, the trace collection progress and the actual trace tree that +follow your program's logic. The most important key-bindings in this +buffer are: + +@table @kbd +@kbditem{g, slime-trace-dialog-fetch-status} +Update information on the trace collection and traced specs. +@kbditem{G, slime-trace-dialog-fetch-traces} +Fetch the next batch of outstanding (not fetched yet) traces. With a +@kbd{C-u} prefix argument, repeat until no more outstanding traces. +@kbditem{C-k, slime-trace-dialog-clear-fetched-traces} +Prompt for confirmation, then clear all traces, both fetched and +outstanding. +@end table + +The arguments and return values below each entry are interactive +buttons. Clicking them opens the inspector +(@pxref{Inspector}). Invoking @kbd{M-RET} +(@code{slime-trace-dialog-copy-down-to-repl}) returns them to the REPL +for manipulation (@pxref{REPL}). The number left of each entry +indicates its absolute position in the calling order, which might +differ from display order in case multiple threads call the same +traced function. + +@code{slime-trace-dialog-hide-details-mode} hides arguments and return +values so you can concentrate on the calling logic. Additionally, +@code{slime-trace-dialog-autofollow-mode} will automatically +display additional detail about an entry when the cursor moves over +it. + +@node slime-sprof +@section @code{slime-sprof} + +@code{slime-sprof} is a package for integrating SBCL's statistical profiler, sb-sprof. + +The variable @code{slime-sprof-exclude-swank} controls whether to +display swank functions. The default value is NIL. + +@table @kbd + +@cmditem{slime-sprof-start} +Start profiling. + +@cmditem{slime-sprof-stop} +Stop profiling. +@cmditem{slime-sprof-report} +Report results of the profiling. +@end table + +The following keys are defined in slime-sprof-browser mode: +@table @kbd + +@kbditem{RET, slime-sprof-browser-toggle} +Expand / collapse function details (callers, calls to) +@kbditem{v, slime-sprof-browser-view-source} +View function sources. +@kbditem{d, slime-sprof-browser-disassemble-function} +Disassemble function. +@kbditem{s, slime-sprof-toggle-swank-exclusion} +Toggle exclusion of swank functions from the report. + +@end table + +@node SLIME Enhanced M-. +@section SLIME Enhanced M-. +@code{slime-mdot-fu} enables meta-point to jump to local variables +bound with @code{let} and @code{let*}, in addition to function bindings +declared with @code{flet} and @code{labels}, via +@code{slime-edit-local-definition}. + +@node slime-fancy +@section Meta package: @code{slime-fancy} + +@code{slime-fancy} is a meta package which loads a combination of the +most popular packages. + +@node Quicklisp +@section Quicklisp +The package @code{slime-quicklisp} adds support for loading Quicklisp +systems in the REPL buffer. In order for this to work, Quicklisp +should have already been loaded in the Lisp implementation. Refer +to @url{https://www.quicklisp.org/} for Quicklisp installation +details. + +The package installs the following REPL shortcuts (@pxref{Shortcuts}): + +@table @kbd +@item quicklisp-quickload (aka ql) +Load a Quicklisp system. +@end table + +@c ----------------------- +@node Credits +@chapter Credits + +@emph{The soppy ending...} + +@unnumberedsec Hackers of the good hack + +@SLIME{} is an Extension of @acronym{SLIM} by Eric Marsden. At the +time of writing, the authors and code-contributors of @SLIME{} are: + +@include contributors.texi + +... not counting the bundled code from @file{hyperspec.el}, +@cite{CLOCC}, and the @cite{CMU AI Repository}. + +Many people on the @code{slime-devel} mailing list have made non-code +contributions to @SLIME{}. Life is hard though: you gotta send code to +get your name in the manual. @code{:-)} + +@unnumberedsec Thanks! + +We're indebted to the good people of @code{common-lisp.net} for their +hosting and help, and for rescuing us from ``Sourceforge hell.'' + +Implementors of the Lisps that we support have been a great help. We'd +like to thank the @acronym{CMUCL} maintainers for their helpful +answers, Craig Norvell and Kevin Layer at Franz providing Allegro CL +licenses for @SLIME{} development, and Peter Graves for his help to +get @SLIME{} running with @acronym{ABCL}. + +Most of all we're happy to be working with the Lisp implementors +who've joined in the @SLIME{} development: Dan Barlow and Christophe +Rhodes of @acronym{SBCL}, Gary Byers of OpenMCL, and Martin Simmons of +LispWorks. Thanks also to Alain Picard and Memetrics for funding +Martin's initial work on the LispWorks backend! + +@ignore +This index is currently ignored, because texinfo's built-in indexing +produces nicer results. -- Helmut Eller + +@c@node Index to Functions +@c@appendix Index to Functions + +These functions are all available (when relevant). To find the +keybinding (if there is one) refer to the function description. + +@c Note to editors: @fcnindex{...} lines commented out below are place holders +@c ---------------- +@c They have yet to be documented +@c Please feel free to add descriptions in the text where appropriate, add the +@c appropriate anchors and uncomment them. +@c +@c [jkc] + +@table @code +@fcnindex{common-lisp-hyperspec-format} +@fcnindex{sldb-abort} +@c @fcnindex{sldb-activate} +@c @fcnindex{sldb-add-face} +@c @fcnindex{sldb-backward-frame} +@c @fcnindex{sldb-beginning-of-backtrace} +@c @fcnindex{sldb-break} +@c @fcnindex{sldb-break-on-return} +@fcnindex{sldb-break-with-default-debugger} +@c @fcnindex{sldb-buffers} +@c @fcnindex{sldb-catch-tags} +@fcnindex{sldb-continue} +@c @fcnindex{sldb-debugged-continuations} +@c @fcnindex{sldb-default-action} +@c @fcnindex{sldb-default-action/mouse} +@c @fcnindex{sldb-delete-overlays} +@c @fcnindex{sldb-details-down} +@c @fcnindex{sldb-details-up} +@fcnindex{sldb-disassemble} +@c @fcnindex{sldb-dispatch-extras} +@c @fcnindex{sldb-down} +@c @fcnindex{sldb-end-of-backtrace} +@fcnindex{sldb-eval-in-frame} +@c @fcnindex{sldb-exit} +@c @fcnindex{sldb-fetch-all-frames} +@c @fcnindex{sldb-fetch-more-frames} +@c @fcnindex{sldb-find-buffer} +@c @fcnindex{sldb-format-reference-node} +@c @fcnindex{sldb-format-reference-source} +@c @fcnindex{sldb-forward-frame} +@c @fcnindex{sldb-frame-details-visible-p} +@c @fcnindex{sldb-frame-locals} +@c @fcnindex{sldb-frame-number-at-point} +@c @fcnindex{sldb-frame-region} +@c @fcnindex{sldb-get-buffer} +@c @fcnindex{sldb-get-default-buffer} +@c @fcnindex{sldb-goto-last-frame} +@c @fcnindex{sldb-help-summary} +@c @fcnindex{sldb-hide-frame-details} +@c @fcnindex{sldb-highlight-sexp} +@c @fcnindex{sldb-insert-condition} +@c @fcnindex{sldb-insert-frame} +@c @fcnindex{sldb-insert-frames} +@c @fcnindex{sldb-insert-locals} +@c @fcnindex{sldb-insert-references} +@c @fcnindex{sldb-insert-restarts} +@c @fcnindex{sldb-inspect-condition} +@fcnindex{sldb-inspect-in-frame} +@c @fcnindex{sldb-inspect-var} +@c @fcnindex{sldb-invoke-restart} +@c @fcnindex{sldb-level} +@c @fcnindex{sldb-list-catch-tags} +@c @fcnindex{sldb-list-locals} +@c @fcnindex{sldb-lookup-reference} +@c @fcnindex{sldb-maybe-recenter-region} +@c @fcnindex{sldb-mode-hook} +@c @fcnindex{sldb-next} +@c @fcnindex{sldb-out} +@fcnindex{sldb-pprint-eval-in-frame} +@c @fcnindex{sldb-previous-frame-number} +@c @fcnindex{sldb-print-condition} +@c @fcnindex{sldb-prune-initial-frames} +@fcnindex{sldb-quit} +@c @fcnindex{sldb-reference-properties} +@c @fcnindex{sldb-restart-at-point} +@fcnindex{sldb-restart-frame} +@fcnindex{sldb-return-from-frame} +@c @fcnindex{sldb-setup} +@c @fcnindex{sldb-show-frame-details} +@c @fcnindex{sldb-show-frame-source} +@fcnindex{sldb-show-source} +@fcnindex{sldb-step} +@c @fcnindex{sldb-sugar-move} +@fcnindex{sldb-toggle-details} +@c @fcnindex{sldb-up} +@c @fcnindex{sldb-var-number-at-point} +@c @fcnindex{sldb-xemacs-emulate-point-entered-hook} +@c @fcnindex{sldb-xemacs-post-command-hook} + + +@c @fcnindex{inferior-slime-closing-return} +@c @fcnindex{inferior-slime-indent-line} +@c @fcnindex{inferior-slime-mode} +@c @fcnindex{inferior-slime-return} +@fcnindex{slime-abort-connection} +@fcnindex{slime-apropos} +@fcnindex{slime-apropos-all} +@fcnindex{slime-apropos-package} +@c @fcnindex{slime-arglist} +@fcnindex{slime-autodoc-mode} +@c @fcnindex{slime-autodoc-start-timer} +@c @fcnindex{slime-background-activities-enabled-p} +@c @fcnindex{slime-background-message} +@c @fcnindex{slime-browse-classes} +@c @fcnindex{slime-browse-xrefs} +@fcnindex{slime-call-defun} +@fcnindex{slime-calls-who} +@c @fcnindex{slime-check-coding-system} +@fcnindex{slime-close-all-sexp} +@fcnindex{slime-close-parens-at-point} +@fcnindex{slime-compile-and-load-file} +@fcnindex{slime-compile-defun} +@fcnindex{slime-compile-file} +@fcnindex{slime-compile-region} +@fcnindex{slime-compiler-macroexpand} +@fcnindex{slime-compiler-macroexpand-1} +@c @fcnindex{slime-compiler-notes-default-action-or-show-details} +@c @fcnindex{slime-compiler-notes-default-action-or-show-details/mouse} +@c @fcnindex{slime-compiler-notes-quit} +@c @fcnindex{slime-compiler-notes-show-details} +@c @fcnindex{slime-complete-form} +@fcnindex{slime-complete-symbol} +@fcnindex{slime-connect} +@fcnindex{slime-connection-list-make-default} +@c @fcnindex{slime-connection-list-mode} +@c @fcnindex{slime-copy-presentation-at-point} +@fcnindex{slime-describe-function} +@fcnindex{slime-describe-symbol} +@fcnindex{slime-disassemble-symbol} +@fcnindex{slime-disconnect} +@c @fcnindex{slime-documentation} +@fcnindex{slime-edit-definition} +@fcnindex{slime-edit-definition-other-frame} +@fcnindex{slime-edit-definition-other-window} +@fcnindex{slime-edit-definition-with-etags} +@fcnindex{slime-edit-value} +@c @fcnindex{slime-edit-value-commit} +@c @fcnindex{slime-edit-value-mode} +@fcnindex{slime-ensure-typeout-frame} +@c @fcnindex{slime-eval-buffer} +@fcnindex{slime-eval-defun} +@fcnindex{slime-eval-last-expression} +@c @fcnindex{slime-eval-print-last-expression} +@fcnindex{slime-eval-region} +@fcnindex{slime-fuzzy-abort} +@fcnindex{slime-fuzzy-complete-symbol} +@fcnindex{slime-fuzzy-completions-mode} +@c @fcnindex{slime-fuzzy-next} +@c @fcnindex{slime-fuzzy-prev} +@c @fcnindex{slime-fuzzy-select} +@c @fcnindex{slime-fuzzy-select/mouse} +@fcnindex{slime-goto-connection} +@fcnindex{slime-goto-xref} +@c @fcnindex{slime-handle-repl-shortcut} +@c @fcnindex{slime-highlight-notes} +@fcnindex{slime-hyperspec-lookup} +@c @fcnindex{slime-indent-and-complete-symbol} +@c @fcnindex{slime-init-keymaps} +@c @fcnindex{slime-insert-arglist} +@c @fcnindex{slime-insert-balanced-comments} +@fcnindex{slime-inspect} +@fcnindex{slime-inspector-copy-down} +@fcnindex{slime-inspector-describe} +@fcnindex{slime-inspector-next} +@c @fcnindex{slime-inspector-next-inspectable-object} +@fcnindex{slime-inspector-quit} +@c @fcnindex{slime-inspector-reinspect} +@fcnindex{slime-interactive-eval} +@fcnindex{slime-interrupt} +@fcnindex{slime-list-callees} +@fcnindex{slime-list-callers} +@c @fcnindex{slime-list-compiler-notes} +@fcnindex{slime-list-connections} +@c @fcnindex{slime-list-repl-shortcuts} +@fcnindex{slime-list-threads} +@fcnindex{slime-load-file} +@c @fcnindex{slime-load-system} +@fcnindex{slime-macroexpand-1} +@fcnindex{slime-macroexpand-1-inplace} +@fcnindex{slime-macroexpand-all} +@c @fcnindex{slime-make-default-connection} +@c @fcnindex{slime-make-typeout-frame} +@fcnindex{slime-mode} +@c @fcnindex{slime-next-location} +@fcnindex{slime-next-note} +@fcnindex{slime-nop} +@c @fcnindex{slime-ping} +@fcnindex{slime-pop-find-definition-stack} +@fcnindex{slime-pprint-eval-last-expression} +@c @fcnindex{slime-presentation-menu} +@c @fcnindex{slime-pretty-lambdas} +@fcnindex{slime-previous-note} +@fcnindex{slime-profile-package} +@fcnindex{slime-profile-report} +@fcnindex{slime-profile-reset} +@fcnindex{slime-profiled-functions} +@fcnindex{slime-quit} +@c @fcnindex{slime-quit-connection-at-point} +@c @fcnindex{slime-quit-lisp} +@c @fcnindex{slime-re-evaluate-defvar} +@c @fcnindex{slime-recompile-bytecode} +@c @fcnindex{slime-register-lisp-implementation} +@fcnindex{slime-reindent-defun} +@c @fcnindex{slime-remove-balanced-comments} +@fcnindex{slime-remove-notes} +@c @fcnindex{slime-repl} +@fcnindex{slime-repl-beginning-of-defun} +@fcnindex{slime-repl-bol} +@fcnindex{slime-repl-clear-buffer} +@fcnindex{slime-repl-clear-output} +@fcnindex{slime-repl-closing-return} +@c @fcnindex{slime-repl-compile-and-load} +@c @fcnindex{slime-repl-compile-system} +@c @fcnindex{slime-repl-compile/force-system} +@c @fcnindex{slime-repl-defparameter} +@fcnindex{slime-repl-end-of-defun} +@c @fcnindex{slime-repl-eol} +@c @fcnindex{slime-repl-load-system} +@c @fcnindex{slime-repl-load/force-system} +@c @fcnindex{slime-repl-mode} +@fcnindex{slime-repl-newline-and-indent} +@fcnindex{slime-repl-next-input} +@fcnindex{slime-repl-next-matching-input} +@fcnindex{slime-repl-next-prompt} +@c @fcnindex{slime-repl-pop-directory} +@c @fcnindex{slime-repl-pop-packages} +@fcnindex{slime-repl-previous-input} +@fcnindex{slime-repl-previous-matching-input} +@fcnindex{slime-repl-previous-prompt} +@c @fcnindex{slime-repl-push-directory} +@c @fcnindex{slime-repl-push-package} +@c @fcnindex{slime-repl-read-break} +@c @fcnindex{slime-repl-read-mode} +@fcnindex{slime-repl-return} +@fcnindex{slime-repl-set-package} +@c @fcnindex{slime-repl-shortcut-help} +@c @fcnindex{slime-reset} +@c @fcnindex{slime-restart-connection-at-point} +@c @fcnindex{slime-restart-inferior-lisp} +@c @fcnindex{slime-restart-inferior-lisp-aux} +@fcnindex{slime-scratch} +@c @fcnindex{slime-select-lisp-implementation} +@fcnindex{slime-selector} +@c @fcnindex{slime-send-sigint} +@c @fcnindex{slime-set-default-directory} +@c @fcnindex{slime-set-package} +@c @fcnindex{slime-show-xref} +@fcnindex{slime-space} +@c @fcnindex{slime-start-and-load} +@fcnindex{slime-switch-to-output-buffer} +@fcnindex{slime-sync-package-and-default-directory} +@c @fcnindex{slime-temp-buffer-mode} +@fcnindex{slime-temp-buffer-quit} +@c @fcnindex{slime-thread-attach} +@c @fcnindex{slime-thread-debug} +@c @fcnindex{slime-thread-control-mode} +@c @fcnindex{slime-thread-kill} +@c @fcnindex{slime-thread-quit} +@fcnindex{slime-toggle-profile-fdefinition} +@fcnindex{slime-toggle-trace-fdefinition} +@fcnindex{slime-undefine-function} +@fcnindex{slime-unprofile-all} +@fcnindex{slime-untrace-all} +@fcnindex{slime-update-connection-list} +@c @fcnindex{slime-update-indentation} ??? +@fcnindex{slime-who-binds} +@fcnindex{slime-who-calls} +@fcnindex{slime-who-macroexpands} +@fcnindex{slime-who-references} +@fcnindex{slime-who-sets} +@fcnindex{slime-who-specializes} +@c @fcnindex{slime-xref-mode} +@c @fcnindex{slime-xref-quit} +@end table + +@end ignore + +@node Key Index +@unnumbered Key (Character) Index +@printindex ky + +@node Command Index +@unnumbered Command and Function Index +@printindex fn + +@node Variable Index +@unnumbered Variable and Concept Index +@printindex vr + +@bye +Local Variables: +paragraph-start: "@[a-zA-Z]+\\({[^}]+}\\)?[ \n]\\|[ ]*$" +paragraph-separate: "@[a-zA-Z]+\\({[^}]+}\\)?[ \n]\\|[ ]*$" +End: diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/doc/texinfo-tabulate.awk b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/doc/texinfo-tabulate.awk new file mode 100644 index 0000000..87e7fe7 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/doc/texinfo-tabulate.awk @@ -0,0 +1,21 @@ +#!/usr/bin/env awk -f +# +# Format input lines into a multi-column texinfo table. +# Note: does not do texinfo-escaping of the input. + +# This code has been placed in the Public Domain. All warranties +# are disclaimed. + +BEGIN { + columns = 3; + printf("@multitable @columnfractions"); + for (i = 0; i < columns; i++) + printf(" %f", 1.0/columns); + print +} + +{ if (NR % columns == 1) printf("\n@item %s", $0); + else printf(" @tab %s", $0); } + +END { printf("\n@end multitable\n"); } + diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/lib/.nosearch b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/lib/.nosearch new file mode 100644 index 0000000..5529475 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/lib/.nosearch @@ -0,0 +1 @@ +;; normal-top-level-add-subdirs-to-load-path needs this file diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/lib/cl-lib.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/lib/cl-lib.el new file mode 100644 index 0000000..ce11309 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/lib/cl-lib.el @@ -0,0 +1,410 @@ +;;; cl-lib.el --- Properly prefixed CL functions and macros -*- coding: utf-8 -*- + +;; Copyright (C) 2012, 2013, 2014 Free Software Foundation, Inc. + +;; Author: Stefan Monnier +;; vcomment: Emacs-24.3's version is 1.0 so this has to stay below. +;; Version: 0.5 + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; This is a forward compatibility package, which provides (a subset of) the +;; features of the cl-lib package introduced in Emacs-24.3, for use on +;; previous emacsen. + +;; Make sure this is installed *late* in your `load-path`, i.e. after Emacs's +;; built-in .../lisp/emacs-lisp directory, so that if/when you upgrade to +;; Emacs-24.3, the built-in version of the file will take precedence, otherwise +;; you could get into trouble (although we try to hack our way around the +;; problem in case it happens). + +;; This code is largely copied from Emacs-24.3's cl.el, with the alias bindings +;; simply reversed. + +;;; Code: + +;; We need to handle the situation where this package is used with an Emacs +;; that comes with a real cl-lib (i.e. ≥24.3). + +;; First line of defense: try to make sure the built-in cl-lib comes earlier in +;; load-path so we never get loaded: +;;;###autoload (let ((d (file-name-directory #$))) +;;;###autoload (when (member d load-path) +;;;###autoload (setq load-path (append (remove d load-path) (list d))))) + +(when (functionp 'macroexp--compiler-macro) + ;; `macroexp--compiler-macro' was introduced as part of the big CL + ;; reorganization which moved/reimplemented some of CL into core (mostly the + ;; setf and compiler-macro support), so its presence indicates we're running + ;; in an Emacs that comes with the new cl-lib.el, where this file should + ;; never be loaded! + (message "Real cl-lib shadowed by compatibility cl-lib? (%s)" load-file-name) + (when load-file-name + ;; (message "Let's try to patch things up") + (let ((loaddir (file-name-directory load-file-name)) + load-path-dir) + ;; Find the problematic directory from load-path. + (dolist (dir load-path) + (if (equal loaddir (expand-file-name (file-name-as-directory dir))) + (setq load-path-dir dir))) + (when load-path-dir + ;; (message "Let's move the offending dir to the end") + (setq load-path (append (remove load-path-dir load-path) + (list load-path-dir))) + ;; Here we could manually load cl-lib and then return immediately. + ;; But Emacs currently doesn't provide any way for a file to "return + ;; immediately", so instead we make sure the rest of the file does not + ;; throw away any pre-existing definition. + )))) + +(require 'cl) + +;; Some of Emacs-24.3's cl.el definition are not just aliases, because either +;; the feature was dropped from cl-lib.el or because the cl-lib version is +;; not fully compatible. +;; Let's just not include them here, since it is very important that if code +;; works with this cl-lib.el it should also work with Emacs-24.3's cl-lib.el, +;; whereas the reverse is much less important. + +(dolist (var '( + ;; loop-result-var + ;; loop-result + ;; loop-initially + ;; loop-finally + ;; loop-bindings + ;; loop-args + ;; bind-inits + ;; bind-block + ;; lambda-list-keywords + float-negative-epsilon + float-epsilon + least-negative-normalized-float + least-positive-normalized-float + least-negative-float + least-positive-float + most-negative-float + most-positive-float + ;; custom-print-functions + )) + (let ((new (intern (format "cl-%s" var)))) + (unless (boundp new) (defvaralias new var)))) + +;; The following cl-lib functions were already defined in the old cl.el, +;; with a different meaning: +;; - cl-position and cl-delete-duplicates +;; the two meanings are clearly different, but we can distinguish which was +;; meant by looking at the arguments. +;; - cl-member +;; the old meaning hasn't been used for a long time and is a subset of the +;; new, so we can simply override it. +;; - cl-adjoin +;; the old meaning is actually the same as the new except for optimizations. + +(dolist (fun '( + (get* . cl-get) + (random* . cl-random) + (rem* . cl-rem) + (mod* . cl-mod) + (round* . cl-round) + (truncate* . cl-truncate) + (ceiling* . cl-ceiling) + (floor* . cl-floor) + (rassoc* . cl-rassoc) + (assoc* . cl-assoc) + ;; (member* . cl-member) ;Handle specially below. + (delete* . cl-delete) + (remove* . cl-remove) + (defsubst* . cl-defsubst) + (sort* . cl-sort) + (function* . cl-function) + (defmacro* . cl-defmacro) + (defun* . cl-defun) + (mapcar* . cl-mapcar) + + remprop + getf + tailp + list-length + nreconc + revappend + concatenate + subseq + random-state-p + make-random-state + signum + isqrt + lcm + gcd + notevery + notany + every + some + mapcon + mapcan + mapl + maplist + map + equalp + coerce + tree-equal + nsublis + sublis + nsubst-if-not + nsubst-if + nsubst + subst-if-not + subst-if + subsetp + nset-exclusive-or + set-exclusive-or + nset-difference + set-difference + nintersection + intersection + nunion + union + rassoc-if-not + rassoc-if + assoc-if-not + assoc-if + member-if-not + member-if + merge + stable-sort + search + mismatch + count-if-not + count-if + count + position-if-not + position-if + ;; position ;Handle specially via defadvice below. + find-if-not + find-if + find + nsubstitute-if-not + nsubstitute-if + nsubstitute + substitute-if-not + substitute-if + substitute + ;; delete-duplicates ;Handle specially via defadvice below. + remove-duplicates + delete-if-not + delete-if + remove-if-not + remove-if + replace + fill + reduce + compiler-macroexpand + define-compiler-macro + assert + check-type + typep + deftype + defstruct + callf2 + callf + letf* + letf + rotatef + shiftf + remf + psetf + declare + the + locally + multiple-value-setq + multiple-value-bind + symbol-macrolet + macrolet + progv + psetq + do-all-symbols + do-symbols + dotimes + dolist + do* + do + loop + return-from + return + block + etypecase + typecase + ecase + case + load-time-value + eval-when + destructuring-bind + gentemp + gensym + pairlis + acons + subst + ;; adjoin ;It's already defined. + copy-list + ldiff + list* + cddddr + cdddar + cddadr + cddaar + cdaddr + cdadar + cdaadr + cdaaar + cadddr + caddar + cadadr + cadaar + caaddr + caadar + caaadr + caaaar + cdddr + cddar + cdadr + cdaar + caddr + cadar + caadr + caaar + tenth + ninth + eighth + seventh + sixth + fifth + fourth + third + endp + rest + second + first + svref + copy-seq + evenp + oddp + minusp + plusp + floatp-safe + declaim + proclaim + nth-value + multiple-value-call + multiple-value-apply + multiple-value-list + values-list + values + pushnew + decf + incf + + dolist + dotimes + )) + (let ((new (if (consp fun) (prog1 (cdr fun) (setq fun (car fun))) + (intern (format "cl-%s" fun))))) + (if (fboundp new) + (unless (or (eq (symbol-function new) fun) + (eq new (and (symbolp fun) (fboundp fun) + (symbol-function fun)))) + (message "%S already defined, not rebinding" new)) + (defalias new fun)))) + +(unless (symbolp (symbol-function 'position)) + (autoload 'cl-position "cl-seq") + (defadvice cl-position (around cl-lib (cl-item cl-seq &rest cl-keys) activate) + (let ((argk (ad-get-args 2))) + (if (or (null argk) (keywordp (car argk))) + ;; This is a call to cl-lib's `cl-position'. + (setq ad-return-value + (apply #'position (ad-get-arg 0) (ad-get-arg 1) argk)) + ;; Must be a call to cl's old `cl-position'. + ad-do-it)))) + +(unless (symbolp (symbol-function 'delete-duplicates)) + (autoload 'cl-delete-duplicates "cl-seq") + (defadvice cl-delete-duplicates (around cl-lib (cl-seq &rest cl-keys) activate) + (let ((argk (ad-get-args 1))) + (if (or (null argk) (keywordp (car argk))) + ;; This is a call to cl-lib's `cl-delete-duplicates'. + (setq ad-return-value + (apply #'delete-duplicates (ad-get-arg 0) argk)) + ;; Must be a call to cl's old `cl-delete-duplicates'. + ad-do-it)))) + +(when (or (not (fboundp 'cl-member)) + (eq (symbol-function 'cl-member) #'memq)) + (defalias 'cl-member #'member*)) + +;; `cl-labels' is not 100% compatible with `labels' when using dynamic scoping +;; (mostly because it does not turn lambdas that refer to those functions into +;; closures). OTOH it is compatible when using lexical scoping. + +(unless (fboundp 'cl-labels) + (defmacro cl-labels (&rest args) + (unless (and (boundp 'lexical-binding) lexical-binding) + ;; We used to signal an error rather than a message, but in many uses of + ;; cl-labels, the value of lexical-binding doesn't actually matter. + ;; More importantly, the value of `lexical-binding' here is unreliable + ;; (it does not necessarily reflect faithfully whether the output of this + ;; macro will be interpreted as lexically bound code or not). + (message "This `cl-labels' requires `lexical-binding' to be non-nil")) + `(labels ,@args))) + +;;;; ChangeLog: + +;; 2014-02-25 Stefan Monnier +;; +;; Fixes: debbugs:16671 +;; +;; * cl-lib.el (cl-position, cl-delete-duplicate): Don't advise if >=24.3. +;; (load-path): Try to make sure we're at the end. +;; +;; 2014-01-25 Stefan Monnier +;; +;; * cl-lib.el: Resolve conflicts with old internal definitions +;; (bug#16353). +;; (dolist fun): Don't skip definitions silently. +;; (define-setf-expander): Remove, not in cl-lib. +;; (cl-position, cl-delete-duplicates): Add advice to distinguish the use +;; case. +;; (cl-member): Override old definition. +;; +;; 2013-05-22 Stefan Monnier +;; +;; * cl-lib.el (cl-labels): Demote error to message and improve it. +;; +;; 2012-11-30 Stefan Monnier +;; +;; * cl-lib.el: Try and patch things up in case we're hiding the real +;; cl-lib. +;; +;; 2012-11-22 Stefan Monnier +;; +;; Add cl-letf and cl-labels. +;; +;; 2012-11-16 Stefan Monnier +;; +;; * packages/cl-lib: New package. +;; + + +(provide 'cl-lib) +;;; cl-lib.el ends here diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/lib/ert-x.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/lib/ert-x.el new file mode 100644 index 0000000..53b76f7 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/lib/ert-x.el @@ -0,0 +1,2544 @@ +;;; ert.el --- Emacs Lisp Regression Testing + +;; Copyright (C) 2007, 2008, 2010 Free Software Foundation, Inc. + +;; Author: Christian M. Ohler +;; Keywords: lisp, tools + +;; This file is NOT part of GNU Emacs. + +;; This program is free software: you can redistribute it and/or +;; modify it under the terms of the GNU General Public License as +;; published by the Free Software Foundation, either version 3 of the +;; License, or (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see `http://www.gnu.org/licenses/'. + +;;; Commentary: + +;; ERT is a tool for automated testing in Emacs Lisp. Its main +;; features are facilities for defining and running test cases and +;; reporting the results as well as for debugging test failures +;; interactively. +;; +;; The main entry points are `ert-deftest', which is similar to +;; `defun' but defines a test, and `ert-run-tests-interactively', +;; which runs tests and offers an interactive interface for inspecting +;; results and debugging. There is also +;; `ert-run-tests-batch-and-exit' for non-interactive use. +;; +;; The body of `ert-deftest' forms resembles a function body, but the +;; additional operators `should', `should-not' and `should-error' are +;; available. `should' is similar to cl's `assert', but signals a +;; different error when its condition is violated that is caught and +;; processed by ERT. In addition, it analyzes its argument form and +;; records information that helps debugging (`assert' tries to do +;; something similar when its second argument SHOW-ARGS is true, but +;; `should' is more sophisticated). For information on `should-not' +;; and `should-error', see their docstrings. +;; +;; See ERT's info manual as well as the docstrings for more details. +;; To compile the manual, run `makeinfo ert.texinfo' in the ERT +;; directory, then C-u M-x info ert.info in Emacs to view it. +;; +;; To see some examples of tests written in ERT, see its self-tests in +;; ert-tests.el. Some of these are tricky due to the bootstrapping +;; problem of writing tests for a testing tool, others test simple +;; functions and are straightforward. + +;;; Code: + +(eval-when-compile + (require 'cl)) +(require 'button) +(require 'debug) +(require 'easymenu) +(require 'ewoc) +(require 'find-func) +(require 'help) + + +;;; UI customization options. + +(defgroup ert () + "ERT, the Emacs Lisp regression testing tool." + :prefix "ert-" + :group 'lisp) + +(defface ert-test-result-expected '((((class color) (background light)) + :background "green1") + (((class color) (background dark)) + :background "green3")) + "Face used for expected results in the ERT results buffer." + :group 'ert) + +(defface ert-test-result-unexpected '((((class color) (background light)) + :background "red1") + (((class color) (background dark)) + :background "red3")) + "Face used for unexpected results in the ERT results buffer." + :group 'ert) + + +;;; Copies/reimplementations of cl functions. + +(defun ert--cl-do-remf (plist tag) + "Copy of `cl-do-remf'. Modify PLIST by removing TAG." + (let ((p (cdr plist))) + (while (and (cdr p) (not (eq (car (cdr p)) tag))) (setq p (cdr (cdr p)))) + (and (cdr p) (progn (setcdr p (cdr (cdr (cdr p)))) t)))) + +(defun ert--remprop (sym tag) + "Copy of `cl-remprop'. Modify SYM's plist by removing TAG." + (let ((plist (symbol-plist sym))) + (if (and plist (eq tag (car plist))) + (progn (setplist sym (cdr (cdr plist))) t) + (ert--cl-do-remf plist tag)))) + +(defun ert--remove-if-not (ert-pred ert-list) + "A reimplementation of `remove-if-not'. + +ERT-PRED is a predicate, ERT-LIST is the input list." + (loop for ert-x in ert-list + if (funcall ert-pred ert-x) + collect ert-x)) + +(defun ert--intersection (a b) + "A reimplementation of `intersection'. Intersect the sets A and B. + +Elements are compared using `eql'." + (loop for x in a + if (memql x b) + collect x)) + +(defun ert--set-difference (a b) + "A reimplementation of `set-difference'. Subtract the set B from the set A. + +Elements are compared using `eql'." + (loop for x in a + unless (memql x b) + collect x)) + +(defun ert--set-difference-eq (a b) + "A reimplementation of `set-difference'. Subtract the set B from the set A. + +Elements are compared using `eq'." + (loop for x in a + unless (memq x b) + collect x)) + +(defun ert--union (a b) + "A reimplementation of `union'. Compute the union of the sets A and B. + +Elements are compared using `eql'." + (append a (ert--set-difference b a))) + +(eval-and-compile + (defvar ert--gensym-counter 0)) + +(eval-and-compile + (defun ert--gensym (&optional prefix) + "Only allows string PREFIX, not compatible with CL." + (unless prefix (setq prefix "G")) + (make-symbol (format "%s%s" + prefix + (prog1 ert--gensym-counter + (incf ert--gensym-counter)))))) + +(defun ert--coerce-to-vector (x) + "Coerce X to a vector." + (when (char-table-p x) (error "Not supported")) + (if (vectorp x) + x + (vconcat x))) + +(defun* ert--remove* (x list &key key test) + "Does not support all the keywords of remove*." + (unless key (setq key #'identity)) + (unless test (setq test #'eql)) + (loop for y in list + unless (funcall test x (funcall key y)) + collect y)) + +(defun ert--string-position (c s) + "Return the position of the first occurrence of C in S, or nil if none." + (loop for i from 0 + for x across s + when (eql x c) return i)) + +(defun ert--mismatch (a b) + "Return index of first element that differs between A and B. + +Like `mismatch'. Uses `equal' for comparison." + (cond ((or (listp a) (listp b)) + (ert--mismatch (ert--coerce-to-vector a) + (ert--coerce-to-vector b))) + ((> (length a) (length b)) + (ert--mismatch b a)) + (t + (let ((la (length a)) + (lb (length b))) + (assert (arrayp a) t) + (assert (arrayp b) t) + (assert (<= la lb) t) + (loop for i below la + when (not (equal (aref a i) (aref b i))) return i + finally (return (if (/= la lb) + la + (assert (equal a b) t) + nil))))))) + +(defun ert--subseq (seq start &optional end) + "Return a subsequence of SEQ from START to END." + (when (char-table-p seq) (error "Not supported")) + (let ((vector (substring (ert--coerce-to-vector seq) start end))) + (etypecase seq + (vector vector) + (string (concat vector)) + (list (append vector nil)) + (bool-vector (loop with result = (make-bool-vector (length vector) nil) + for i below (length vector) do + (setf (aref result i) (aref vector i)) + finally (return result))) + (char-table (assert nil))))) + +(defun ert-equal-including-properties (a b) + "Return t if A and B have similar structure and contents. + +This is like `equal-including-properties' except that it compares +the property values of text properties structurally (by +recursing) rather than with `eq'. Perhaps this is what +`equal-including-properties' should do in the first place; see +Emacs bug 6581 at URL `http://debbugs.gnu.org/cgi/bugreport.cgi?bug=6581'." + ;; This implementation is inefficient. Rather than making it + ;; efficient, let's hope bug 6581 gets fixed so that we can delete + ;; it altogether. + (not (ert--explain-not-equal-including-properties a b))) + + +;;; Defining and locating tests. + +;; The data structure that represents a test case. +(defstruct ert-test + (name nil) + (documentation nil) + (body (assert nil)) + (most-recent-result nil) + (expected-result-type ':passed) + (tags '())) + +(defun ert-test-boundp (symbol) + "Return non-nil if SYMBOL names a test." + (and (get symbol 'ert--test) t)) + +(defun ert-get-test (symbol) + "If SYMBOL names a test, return that. Signal an error otherwise." + (unless (ert-test-boundp symbol) (error "No test named `%S'" symbol)) + (get symbol 'ert--test)) + +(defun ert-set-test (symbol definition) + "Make SYMBOL name the test DEFINITION, and return DEFINITION." + (when (eq symbol 'nil) + ;; We disallow nil since `ert-test-at-point' and related functions + ;; want to return a test name, but also need an out-of-band value + ;; on failure. Nil is the most natural out-of-band value; using 0 + ;; or "" or signalling an error would be too awkward. + ;; + ;; Note that nil is still a valid value for the `name' slot in + ;; ert-test objects. It designates an anonymous test. + (error "Attempt to define a test named nil")) + (put symbol 'ert--test definition) + definition) + +(defun ert-make-test-unbound (symbol) + "Make SYMBOL name no test. Return SYMBOL." + (ert--remprop symbol 'ert--test) + symbol) + +(defun ert--parse-keys-and-body (keys-and-body) + "Split KEYS-AND-BODY into keyword-and-value pairs and the remaining body. + +KEYS-AND-BODY should have the form of a property list, with the +exception that only keywords are permitted as keys and that the +tail -- the body -- is a list of forms that does not start with a +keyword. + +Returns a two-element list containing the keys-and-values plist +and the body." + (let ((extracted-key-accu '()) + (remaining keys-and-body)) + (while (and (consp remaining) (keywordp (first remaining))) + (let ((keyword (pop remaining))) + (unless (consp remaining) + (error "Value expected after keyword %S in %S" + keyword keys-and-body)) + (when (assoc keyword extracted-key-accu) + (warn "Keyword %S appears more than once in %S" keyword + keys-and-body)) + (push (cons keyword (pop remaining)) extracted-key-accu))) + (setq extracted-key-accu (nreverse extracted-key-accu)) + (list (loop for (key . value) in extracted-key-accu + collect key + collect value) + remaining))) + +;;;###autoload +(defmacro* ert-deftest (name () &body docstring-keys-and-body) + "Define NAME (a symbol) as a test. + +BODY is evaluated as a `progn' when the test is run. It should +signal a condition on failure or just return if the test passes. + +`should', `should-not' and `should-error' are useful for +assertions in BODY. + +Use `ert' to run tests interactively. + +Tests that are expected to fail can be marked as such +using :expected-result. See `ert-test-result-type-p' for a +description of valid values for RESULT-TYPE. + +\(fn NAME () [DOCSTRING] [:expected-result RESULT-TYPE] \ +\[:tags '(TAG...)] BODY...)" + (declare (debug (&define :name test + name sexp [&optional stringp] + [&rest keywordp sexp] def-body)) + (doc-string 3) + (indent 2)) + (let ((documentation nil) + (documentation-supplied-p nil)) + (when (stringp (first docstring-keys-and-body)) + (setq documentation (pop docstring-keys-and-body) + documentation-supplied-p t)) + (destructuring-bind ((&key (expected-result nil expected-result-supplied-p) + (tags nil tags-supplied-p)) + body) + (ert--parse-keys-and-body docstring-keys-and-body) + `(progn + (ert-set-test ',name + (make-ert-test + :name ',name + ,@(when documentation-supplied-p + `(:documentation ,documentation)) + ,@(when expected-result-supplied-p + `(:expected-result-type ,expected-result)) + ,@(when tags-supplied-p + `(:tags ,tags)) + :body (lambda () ,@body))) + ;; This hack allows `symbol-file' to associate `ert-deftest' + ;; forms with files, and therefore enables `find-function' to + ;; work with tests. However, it leads to warnings in + ;; `unload-feature', which doesn't know how to undefine tests + ;; and has no mechanism for extension. + (push '(ert-deftest . ,name) current-load-list) + ',name)))) + +;; We use these `put' forms in addition to the (declare (indent)) in +;; the defmacro form since the `declare' alone does not lead to +;; correct indentation before the .el/.elc file is loaded. +;; Autoloading these `put' forms solves this. +;;;###autoload +(progn + ;; TODO(ohler): Figure out what these mean and make sure they are correct. + (put 'ert-deftest 'lisp-indent-function 2) + (put 'ert-info 'lisp-indent-function 1)) + +(defvar ert--find-test-regexp + (concat "^\\s-*(ert-deftest" + find-function-space-re + "%s\\(\\s-\\|$\\)") + "The regexp the `find-function' mechanisms use for finding test definitions.") + + +(put 'ert-test-failed 'error-conditions '(error ert-test-failed)) +(put 'ert-test-failed 'error-message "Test failed") + +(defun ert-pass () + "Terminate the current test and mark it passed. Does not return." + (throw 'ert--pass nil)) + +(defun ert-fail (data) + "Terminate the current test and mark it failed. Does not return. +DATA is displayed to the user and should state the reason of the failure." + (signal 'ert-test-failed (list data))) + + +;;; The `should' macros. + +(defvar ert--should-execution-observer nil) + +(defun ert--signal-should-execution (form-description) + "Tell the current `should' form observer (if any) about FORM-DESCRIPTION." + (when ert--should-execution-observer + (funcall ert--should-execution-observer form-description))) + +(defun ert--special-operator-p (thing) + "Return non-nil if THING is a symbol naming a special operator." + (and (symbolp thing) + (let ((definition (indirect-function thing t))) + (and (subrp definition) + (eql (cdr (subr-arity definition)) 'unevalled))))) + +(defun ert--expand-should-1 (whole form inner-expander) + "Helper function for the `should' macro and its variants." + (let ((form + ;; If `cl-macroexpand' isn't bound, the code that we're + ;; compiling doesn't depend on cl and thus doesn't need an + ;; environment arg for `macroexpand'. + (if (fboundp 'cl-macroexpand) + ;; Suppress warning about run-time call to cl funtion: we + ;; only call it if it's fboundp. + (with-no-warnings + (cl-macroexpand form (and (boundp 'cl-macro-environment) + cl-macro-environment))) + (macroexpand form)))) + (cond + ((or (atom form) (ert--special-operator-p (car form))) + (let ((value (ert--gensym "value-"))) + `(let ((,value (ert--gensym "ert-form-evaluation-aborted-"))) + ,(funcall inner-expander + `(setq ,value ,form) + `(list ',whole :form ',form :value ,value) + value) + ,value))) + (t + (let ((fn-name (car form)) + (arg-forms (cdr form))) + (assert (or (symbolp fn-name) + (and (consp fn-name) + (eql (car fn-name) 'lambda) + (listp (cdr fn-name))))) + (let ((fn (ert--gensym "fn-")) + (args (ert--gensym "args-")) + (value (ert--gensym "value-")) + (default-value (ert--gensym "ert-form-evaluation-aborted-"))) + `(let ((,fn (function ,fn-name)) + (,args (list ,@arg-forms))) + (let ((,value ',default-value)) + ,(funcall inner-expander + `(setq ,value (apply ,fn ,args)) + `(nconc (list ',whole) + (list :form `(,,fn ,@,args)) + (unless (eql ,value ',default-value) + (list :value ,value)) + (let ((-explainer- + (and (symbolp ',fn-name) + (get ',fn-name 'ert-explainer)))) + (when -explainer- + (list :explanation + (apply -explainer- ,args))))) + value) + ,value)))))))) + +(defun ert--expand-should (whole form inner-expander) + "Helper function for the `should' macro and its variants. + +Analyzes FORM and returns an expression that has the same +semantics under evaluation but records additional debugging +information. + +INNER-EXPANDER should be a function and is called with two +arguments: INNER-FORM and FORM-DESCRIPTION-FORM, where INNER-FORM +is an expression equivalent to FORM, and FORM-DESCRIPTION-FORM is +an expression that returns a description of FORM. INNER-EXPANDER +should return code that calls INNER-FORM and performs the checks +and error signalling specific to the particular variant of +`should'. The code that INNER-EXPANDER returns must not call +FORM-DESCRIPTION-FORM before it has called INNER-FORM." + (lexical-let ((inner-expander inner-expander)) + (ert--expand-should-1 + whole form + (lambda (inner-form form-description-form value-var) + (let ((form-description (ert--gensym "form-description-"))) + `(let (,form-description) + ,(funcall inner-expander + `(unwind-protect + ,inner-form + (setq ,form-description ,form-description-form) + (ert--signal-should-execution ,form-description)) + `,form-description + value-var))))))) + +(defmacro* should (form) + "Evaluate FORM. If it returns nil, abort the current test as failed. + +Returns the value of FORM." + (ert--expand-should `(should ,form) form + (lambda (inner-form form-description-form value-var) + `(unless ,inner-form + (ert-fail ,form-description-form))))) + +(defmacro* should-not (form) + "Evaluate FORM. If it returns non-nil, abort the current test as failed. + +Returns nil." + (ert--expand-should `(should-not ,form) form + (lambda (inner-form form-description-form value-var) + `(unless (not ,inner-form) + (ert-fail ,form-description-form))))) + +(defun ert--should-error-handle-error (form-description-fn + condition type exclude-subtypes) + "Helper function for `should-error'. + +Determines whether CONDITION matches TYPE and EXCLUDE-SUBTYPES, +and aborts the current test as failed if it doesn't." + (let ((signalled-conditions (get (car condition) 'error-conditions)) + (handled-conditions (etypecase type + (list type) + (symbol (list type))))) + (assert signalled-conditions) + (unless (ert--intersection signalled-conditions handled-conditions) + (ert-fail (append + (funcall form-description-fn) + (list + :condition condition + :fail-reason (concat "the error signalled did not" + " have the expected type"))))) + (when exclude-subtypes + (unless (member (car condition) handled-conditions) + (ert-fail (append + (funcall form-description-fn) + (list + :condition condition + :fail-reason (concat "the error signalled was a subtype" + " of the expected type")))))))) + +;; FIXME: The expansion will evaluate the keyword args (if any) in +;; nonstandard order. +(defmacro* should-error (form &rest keys &key type exclude-subtypes) + "Evaluate FORM and check that it signals an error. + +The error signalled needs to match TYPE. TYPE should be a list +of condition names. (It can also be a non-nil symbol, which is +equivalent to a singleton list containing that symbol.) If +EXCLUDE-SUBTYPES is nil, the error matches TYPE if one of its +condition names is an element of TYPE. If EXCLUDE-SUBTYPES is +non-nil, the error matches TYPE if it is an element of TYPE. + +If the error matches, returns (ERROR-SYMBOL . DATA) from the +error. If not, or if no error was signalled, abort the test as +failed." + (unless type (setq type ''error)) + (ert--expand-should + `(should-error ,form ,@keys) + form + (lambda (inner-form form-description-form value-var) + (let ((errorp (ert--gensym "errorp")) + (form-description-fn (ert--gensym "form-description-fn-"))) + `(let ((,errorp nil) + (,form-description-fn (lambda () ,form-description-form))) + (condition-case -condition- + ,inner-form + ;; We can't use ,type here because we want to evaluate it. + (error + (setq ,errorp t) + (ert--should-error-handle-error ,form-description-fn + -condition- + ,type ,exclude-subtypes) + (setq ,value-var -condition-))) + (unless ,errorp + (ert-fail (append + (funcall ,form-description-fn) + (list + :fail-reason "did not signal an error"))))))))) + + +;;; Explanation of `should' failures. + +;; TODO(ohler): Rework explanations so that they are displayed in a +;; similar way to `ert-info' messages; in particular, allow text +;; buttons in explanations that give more detail or open an ediff +;; buffer. Perhaps explanations should be reported through `ert-info' +;; rather than as part of the condition. + +(defun ert--proper-list-p (x) + "Return non-nil if X is a proper list, nil otherwise." + (loop + for firstp = t then nil + for fast = x then (cddr fast) + for slow = x then (cdr slow) do + (when (null fast) (return t)) + (when (not (consp fast)) (return nil)) + (when (null (cdr fast)) (return t)) + (when (not (consp (cdr fast))) (return nil)) + (when (and (not firstp) (eq fast slow)) (return nil)))) + +(defun ert--explain-format-atom (x) + "Format the atom X for `ert--explain-not-equal'." + (typecase x + (fixnum (list x (format "#x%x" x) (format "?%c" x))) + (t x))) + +(defun ert--explain-not-equal (a b) + "Explainer function for `equal'. + +Returns a programmer-readable explanation of why A and B are not +`equal', or nil if they are." + (if (not (equal (type-of a) (type-of b))) + `(different-types ,a ,b) + (etypecase a + (cons + (let ((a-proper-p (ert--proper-list-p a)) + (b-proper-p (ert--proper-list-p b))) + (if (not (eql (not a-proper-p) (not b-proper-p))) + `(one-list-proper-one-improper ,a ,b) + (if a-proper-p + (if (not (equal (length a) (length b))) + `(proper-lists-of-different-length ,(length a) ,(length b) + ,a ,b + first-mismatch-at + ,(ert--mismatch a b)) + (loop for i from 0 + for ai in a + for bi in b + for xi = (ert--explain-not-equal ai bi) + do (when xi (return `(list-elt ,i ,xi))) + finally (assert (equal a b) t))) + (let ((car-x (ert--explain-not-equal (car a) (car b)))) + (if car-x + `(car ,car-x) + (let ((cdr-x (ert--explain-not-equal (cdr a) (cdr b)))) + (if cdr-x + `(cdr ,cdr-x) + (assert (equal a b) t) + nil)))))))) + (array (if (not (equal (length a) (length b))) + `(arrays-of-different-length ,(length a) ,(length b) + ,a ,b + ,@(unless (char-table-p a) + `(first-mismatch-at + ,(ert--mismatch a b)))) + (loop for i from 0 + for ai across a + for bi across b + for xi = (ert--explain-not-equal ai bi) + do (when xi (return `(array-elt ,i ,xi))) + finally (assert (equal a b) t)))) + (atom (if (not (equal a b)) + (if (and (symbolp a) (symbolp b) (string= a b)) + `(different-symbols-with-the-same-name ,a ,b) + `(different-atoms ,(ert--explain-format-atom a) + ,(ert--explain-format-atom b))) + nil))))) +(put 'equal 'ert-explainer 'ert--explain-not-equal) + +(defun ert--significant-plist-keys (plist) + "Return the keys of PLIST that have non-null values, in order." + (assert (zerop (mod (length plist) 2)) t) + (loop for (key value . rest) on plist by #'cddr + unless (or (null value) (memq key accu)) collect key into accu + finally (return accu))) + +(defun ert--plist-difference-explanation (a b) + "Return a programmer-readable explanation of why A and B are different plists. + +Returns nil if they are equivalent, i.e., have the same value for +each key, where absent values are treated as nil. The order of +key/value pairs in each list does not matter." + (assert (zerop (mod (length a) 2)) t) + (assert (zerop (mod (length b) 2)) t) + ;; Normalizing the plists would be another way to do this but it + ;; requires a total ordering on all lisp objects (since any object + ;; is valid as a text property key). Perhaps defining such an + ;; ordering is useful in other contexts, too, but it's a lot of + ;; work, so let's punt on it for now. + (let* ((keys-a (ert--significant-plist-keys a)) + (keys-b (ert--significant-plist-keys b)) + (keys-in-a-not-in-b (ert--set-difference-eq keys-a keys-b)) + (keys-in-b-not-in-a (ert--set-difference-eq keys-b keys-a))) + (flet ((explain-with-key (key) + (let ((value-a (plist-get a key)) + (value-b (plist-get b key))) + (assert (not (equal value-a value-b)) t) + `(different-properties-for-key + ,key ,(ert--explain-not-equal-including-properties value-a + value-b))))) + (cond (keys-in-a-not-in-b + (explain-with-key (first keys-in-a-not-in-b))) + (keys-in-b-not-in-a + (explain-with-key (first keys-in-b-not-in-a))) + (t + (loop for key in keys-a + when (not (equal (plist-get a key) (plist-get b key))) + return (explain-with-key key))))))) + +(defun ert--abbreviate-string (s len suffixp) + "Shorten string S to at most LEN chars. + +If SUFFIXP is non-nil, returns a suffix of S, otherwise a prefix." + (let ((n (length s))) + (cond ((< n len) + s) + (suffixp + (substring s (- n len))) + (t + (substring s 0 len))))) + +(defun ert--explain-not-equal-including-properties (a b) + "Explainer function for `ert-equal-including-properties'. + +Returns a programmer-readable explanation of why A and B are not +`ert-equal-including-properties', or nil if they are." + (if (not (equal a b)) + (ert--explain-not-equal a b) + (assert (stringp a) t) + (assert (stringp b) t) + (assert (eql (length a) (length b)) t) + (loop for i from 0 to (length a) + for props-a = (text-properties-at i a) + for props-b = (text-properties-at i b) + for difference = (ert--plist-difference-explanation props-a props-b) + do (when difference + (return `(char ,i ,(substring-no-properties a i (1+ i)) + ,difference + context-before + ,(ert--abbreviate-string + (substring-no-properties a 0 i) + 10 t) + context-after + ,(ert--abbreviate-string + (substring-no-properties a (1+ i)) + 10 nil)))) + ;; TODO(ohler): Get `equal-including-properties' fixed in + ;; Emacs, delete `ert-equal-including-properties', and + ;; re-enable this assertion. + ;;finally (assert (equal-including-properties a b) t) + ))) +(put 'ert-equal-including-properties + 'ert-explainer + 'ert--explain-not-equal-including-properties) + + +;;; Implementation of `ert-info'. + +;; TODO(ohler): The name `info' clashes with +;; `ert--test-execution-info'. One or both should be renamed. +(defvar ert--infos '() + "The stack of `ert-info' infos that currently apply. + +Bound dynamically. This is a list of (PREFIX . MESSAGE) pairs.") + +(defmacro* ert-info ((message-form &key ((:prefix prefix-form) "Info: ")) + &body body) + "Evaluate MESSAGE-FORM and BODY, and report the message if BODY fails. + +To be used within ERT tests. MESSAGE-FORM should evaluate to a +string that will be displayed together with the test result if +the test fails. PREFIX-FORM should evaluate to a string as well +and is displayed in front of the value of MESSAGE-FORM." + (declare (debug ((form &rest [sexp form]) body)) + (indent 1)) + `(let ((ert--infos (cons (cons ,prefix-form ,message-form) ert--infos))) + ,@body)) + + + +;;; Facilities for running a single test. + +(defvar ert-debug-on-error nil + "Non-nil means enter debugger when a test fails or terminates with an error.") + +;; The data structures that represent the result of running a test. +(defstruct ert-test-result + (messages nil) + (should-forms nil) + ) +(defstruct (ert-test-passed (:include ert-test-result))) +(defstruct (ert-test-result-with-condition (:include ert-test-result)) + (condition (assert nil)) + (backtrace (assert nil)) + (infos (assert nil))) +(defstruct (ert-test-quit (:include ert-test-result-with-condition))) +(defstruct (ert-test-failed (:include ert-test-result-with-condition))) +(defstruct (ert-test-aborted-with-non-local-exit (:include ert-test-result))) + + +(defun ert--record-backtrace () + "Record the current backtrace (as a list) and return it." + ;; Since the backtrace is stored in the result object, result + ;; objects must only be printed with appropriate limits + ;; (`print-level' and `print-length') in place. For interactive + ;; use, the cost of ensuring this possibly outweighs the advantage + ;; of storing the backtrace for + ;; `ert-results-pop-to-backtrace-for-test-at-point' given that we + ;; already have `ert-results-rerun-test-debugging-errors-at-point'. + ;; For batch use, however, printing the backtrace may be useful. + (loop + ;; 6 is the number of frames our own debugger adds (when + ;; compiled; more when interpreted). FIXME: Need to describe a + ;; procedure for determining this constant. + for i from 6 + for frame = (backtrace-frame i) + while frame + collect frame)) + +(defun ert--print-backtrace (backtrace) + "Format the backtrace BACKTRACE to the current buffer." + ;; This is essentially a reimplementation of Fbacktrace + ;; (src/eval.c), but for a saved backtrace, not the current one. + (let ((print-escape-newlines t) + (print-level 8) + (print-length 50)) + (dolist (frame backtrace) + (ecase (first frame) + ((nil) + ;; Special operator. + (destructuring-bind (special-operator &rest arg-forms) + (cdr frame) + (insert + (format " %S\n" (list* special-operator arg-forms))))) + ((t) + ;; Function call. + (destructuring-bind (fn &rest args) (cdr frame) + (insert (format " %S(" fn)) + (loop for firstp = t then nil + for arg in args do + (unless firstp + (insert " ")) + (insert (format "%S" arg))) + (insert ")\n"))))))) + +;; A container for the state of the execution of a single test and +;; environment data needed during its execution. +(defstruct ert--test-execution-info + (test (assert nil)) + (result (assert nil)) + ;; A thunk that may be called when RESULT has been set to its final + ;; value and test execution should be terminated. Should not + ;; return. + (exit-continuation (assert nil)) + ;; The binding of `debugger' outside of the execution of the test. + next-debugger + ;; The binding of `ert-debug-on-error' that is in effect for the + ;; execution of the current test. We store it to avoid being + ;; affected by any new bindings the test itself may establish. (I + ;; don't remember whether this feature is important.) + ert-debug-on-error) + +(defun ert--run-test-debugger (info debugger-args) + "During a test run, `debugger' is bound to a closure that calls this function. + +This function records failures and errors and either terminates +the test silently or calls the interactive debugger, as +appropriate. + +INFO is the ert--test-execution-info corresponding to this test +run. DEBUGGER-ARGS are the arguments to `debugger'." + (destructuring-bind (first-debugger-arg &rest more-debugger-args) + debugger-args + (ecase first-debugger-arg + ((lambda debug t exit nil) + (apply (ert--test-execution-info-next-debugger info) debugger-args)) + (error + (let* ((condition (first more-debugger-args)) + (type (case (car condition) + ((quit) 'quit) + (otherwise 'failed))) + (backtrace (ert--record-backtrace)) + (infos (reverse ert--infos))) + (setf (ert--test-execution-info-result info) + (ecase type + (quit + (make-ert-test-quit :condition condition + :backtrace backtrace + :infos infos)) + (failed + (make-ert-test-failed :condition condition + :backtrace backtrace + :infos infos)))) + ;; Work around Emacs' heuristic (in eval.c) for detecting + ;; errors in the debugger. + (incf num-nonmacro-input-events) + ;; FIXME: We should probably implement more fine-grained + ;; control a la non-t `debug-on-error' here. + (cond + ((ert--test-execution-info-ert-debug-on-error info) + (apply (ert--test-execution-info-next-debugger info) debugger-args)) + (t)) + (funcall (ert--test-execution-info-exit-continuation info))))))) + +(defun ert--run-test-internal (ert-test-execution-info) + "Low-level function to run a test according to ERT-TEST-EXECUTION-INFO. + +This mainly sets up debugger-related bindings." + (lexical-let ((info ert-test-execution-info)) + (setf (ert--test-execution-info-next-debugger info) debugger + (ert--test-execution-info-ert-debug-on-error info) ert-debug-on-error) + (catch 'ert--pass + ;; For now, each test gets its own temp buffer and its own + ;; window excursion, just to be safe. If this turns out to be + ;; too expensive, we can remove it. + (with-temp-buffer + (save-window-excursion + (let ((debugger (lambda (&rest debugger-args) + (ert--run-test-debugger info debugger-args))) + (debug-on-error t) + (debug-on-quit t) + ;; FIXME: Do we need to store the old binding of this + ;; and consider it in `ert--run-test-debugger'? + (debug-ignored-errors nil) + (ert--infos '())) + (funcall (ert-test-body (ert--test-execution-info-test info)))))) + (ert-pass)) + (setf (ert--test-execution-info-result info) (make-ert-test-passed))) + nil) + +(defun ert--force-message-log-buffer-truncation () + "Immediately truncate *Messages* buffer according to `message-log-max'. + +This can be useful after reducing the value of `message-log-max'." + (with-current-buffer (get-buffer-create "*Messages*") + ;; This is a reimplementation of this part of message_dolog() in xdisp.c: + ;; if (NATNUMP (Vmessage_log_max)) + ;; { + ;; scan_newline (Z, Z_BYTE, BEG, BEG_BYTE, + ;; -XFASTINT (Vmessage_log_max) - 1, 0); + ;; del_range_both (BEG, BEG_BYTE, PT, PT_BYTE, 0); + ;; } + (when (and (integerp message-log-max) (>= message-log-max 0)) + (let ((begin (point-min)) + (end (save-excursion + (goto-char (point-max)) + (forward-line (- message-log-max)) + (point)))) + (delete-region begin end))))) + +(defvar ert--running-tests nil + "List of tests that are currently in execution. + +This list is empty while no test is running, has one element +while a test is running, two elements while a test run from +inside a test is running, etc. The list is in order of nesting, +innermost test first. + +The elements are of type `ert-test'.") + +(defun ert-run-test (ert-test) + "Run ERT-TEST. + +Returns the result and stores it in ERT-TEST's `most-recent-result' slot." + (setf (ert-test-most-recent-result ert-test) nil) + (block error + (lexical-let ((begin-marker + (with-current-buffer (get-buffer-create "*Messages*") + (set-marker (make-marker) (point-max))))) + (unwind-protect + (lexical-let ((info (make-ert--test-execution-info + :test ert-test + :result + (make-ert-test-aborted-with-non-local-exit) + :exit-continuation (lambda () + (return-from error nil)))) + (should-form-accu (list))) + (unwind-protect + (let ((ert--should-execution-observer + (lambda (form-description) + (push form-description should-form-accu))) + (message-log-max t) + (ert--running-tests (cons ert-test ert--running-tests))) + (ert--run-test-internal info)) + (let ((result (ert--test-execution-info-result info))) + (setf (ert-test-result-messages result) + (with-current-buffer (get-buffer-create "*Messages*") + (buffer-substring begin-marker (point-max)))) + (ert--force-message-log-buffer-truncation) + (setq should-form-accu (nreverse should-form-accu)) + (setf (ert-test-result-should-forms result) + should-form-accu) + (setf (ert-test-most-recent-result ert-test) result)))) + (set-marker begin-marker nil)))) + (ert-test-most-recent-result ert-test)) + +(defun ert-running-test () + "Return the top-level test currently executing." + (car (last ert--running-tests))) + + +;;; Test selectors. + +(defun ert-test-result-type-p (result result-type) + "Return non-nil if RESULT matches type RESULT-TYPE. + +Valid result types: + +nil -- Never matches. +t -- Always matches. +:failed, :passed -- Matches corresponding results. +\(and TYPES...\) -- Matches if all TYPES match. +\(or TYPES...\) -- Matches if some TYPES match. +\(not TYPE\) -- Matches if TYPE does not match. +\(satisfies PREDICATE\) -- Matches if PREDICATE returns true when called with + RESULT." + ;; It would be easy to add `member' and `eql' types etc., but I + ;; haven't bothered yet. + (etypecase result-type + ((member nil) nil) + ((member t) t) + ((member :failed) (ert-test-failed-p result)) + ((member :passed) (ert-test-passed-p result)) + (cons + (destructuring-bind (operator &rest operands) result-type + (ecase operator + (and + (case (length operands) + (0 t) + (t + (and (ert-test-result-type-p result (first operands)) + (ert-test-result-type-p result `(and ,@(rest operands))))))) + (or + (case (length operands) + (0 nil) + (t + (or (ert-test-result-type-p result (first operands)) + (ert-test-result-type-p result `(or ,@(rest operands))))))) + (not + (assert (eql (length operands) 1)) + (not (ert-test-result-type-p result (first operands)))) + (satisfies + (assert (eql (length operands) 1)) + (funcall (first operands) result))))))) + +(defun ert-test-result-expected-p (test result) + "Return non-nil if TEST's expected result type matches RESULT." + (ert-test-result-type-p result (ert-test-expected-result-type test))) + +(defun ert-select-tests (selector universe) + "Return the tests that match SELECTOR. + +UNIVERSE specifies the set of tests to select from; it should be +a list of tests, or t, which refers to all tests named by symbols +in `obarray'. + +Returns the set of tests as a list. + +Valid selectors: + +nil -- Selects the empty set. +t -- Selects UNIVERSE. +:new -- Selects all tests that have not been run yet. +:failed, :passed -- Select tests according to their most recent result. +:expected, :unexpected -- Select tests according to their most recent result. +a string -- Selects all tests that have a name that matches the string, + a regexp. +a test -- Selects that test. +a symbol -- Selects the test that the symbol names, errors if none. +\(member TESTS...\) -- Selects TESTS, a list of tests or symbols naming tests. +\(eql TEST\) -- Selects TEST, a test or a symbol naming a test. +\(and SELECTORS...\) -- Selects the tests that match all SELECTORS. +\(or SELECTORS...\) -- Selects the tests that match any SELECTOR. +\(not SELECTOR\) -- Selects all tests that do not match SELECTOR. +\(tag TAG) -- Selects all tests that have TAG on their tags list. +\(satisfies PREDICATE\) -- Selects all tests that satisfy PREDICATE. + +Only selectors that require a superset of tests, such +as (satisfies ...), strings, :new, etc. make use of UNIVERSE. +Selectors that do not, such as \(member ...\), just return the +set implied by them without checking whether it is really +contained in UNIVERSE." + ;; This code needs to match the etypecase in + ;; `ert-insert-human-readable-selector'. + (etypecase selector + ((member nil) nil) + ((member t) (etypecase universe + (list universe) + ((member t) (ert-select-tests "" universe)))) + ((member :new) (ert-select-tests + `(satisfies ,(lambda (test) + (null (ert-test-most-recent-result test)))) + universe)) + ((member :failed) (ert-select-tests + `(satisfies ,(lambda (test) + (ert-test-result-type-p + (ert-test-most-recent-result test) + ':failed))) + universe)) + ((member :passed) (ert-select-tests + `(satisfies ,(lambda (test) + (ert-test-result-type-p + (ert-test-most-recent-result test) + ':passed))) + universe)) + ((member :expected) (ert-select-tests + `(satisfies + ,(lambda (test) + (ert-test-result-expected-p + test + (ert-test-most-recent-result test)))) + universe)) + ((member :unexpected) (ert-select-tests `(not :expected) universe)) + (string + (etypecase universe + ((member t) (mapcar #'ert-get-test + (apropos-internal selector #'ert-test-boundp))) + (list (ert--remove-if-not (lambda (test) + (and (ert-test-name test) + (string-match selector + (ert-test-name test)))) + universe)))) + (ert-test (list selector)) + (symbol + (assert (ert-test-boundp selector)) + (list (ert-get-test selector))) + (cons + (destructuring-bind (operator &rest operands) selector + (ecase operator + (member + (mapcar (lambda (purported-test) + (etypecase purported-test + (symbol (assert (ert-test-boundp purported-test)) + (ert-get-test purported-test)) + (ert-test purported-test))) + operands)) + (eql + (assert (eql (length operands) 1)) + (ert-select-tests `(member ,@operands) universe)) + (and + ;; Do these definitions of AND, NOT and OR satisfy de + ;; Morgan's laws? Should they? + (case (length operands) + (0 (ert-select-tests 't universe)) + (t (ert-select-tests `(and ,@(rest operands)) + (ert-select-tests (first operands) + universe))))) + (not + (assert (eql (length operands) 1)) + (let ((all-tests (ert-select-tests 't universe))) + (ert--set-difference all-tests + (ert-select-tests (first operands) + all-tests)))) + (or + (case (length operands) + (0 (ert-select-tests 'nil universe)) + (t (ert--union (ert-select-tests (first operands) universe) + (ert-select-tests `(or ,@(rest operands)) + universe))))) + (tag + (assert (eql (length operands) 1)) + (let ((tag (first operands))) + (ert-select-tests `(satisfies + ,(lambda (test) + (member tag (ert-test-tags test)))) + universe))) + (satisfies + (assert (eql (length operands) 1)) + (ert--remove-if-not (first operands) + (ert-select-tests 't universe)))))))) + +(defun ert--insert-human-readable-selector (selector) + "Insert a human-readable presentation of SELECTOR into the current buffer." + ;; This is needed to avoid printing the (huge) contents of the + ;; `backtrace' slot of the result objects in the + ;; `most-recent-result' slots of test case objects in (eql ...) or + ;; (member ...) selectors. + (labels ((rec (selector) + ;; This code needs to match the etypecase in `ert-select-tests'. + (etypecase selector + ((or (member nil t + :new :failed :passed + :expected :unexpected) + string + symbol) + selector) + (ert-test + (if (ert-test-name selector) + (make-symbol (format "<%S>" (ert-test-name selector))) + (make-symbol ""))) + (cons + (destructuring-bind (operator &rest operands) selector + (ecase operator + ((member eql and not or) + `(,operator ,@(mapcar #'rec operands))) + ((member tag satisfies) + selector))))))) + (insert (format "%S" (rec selector))))) + + +;;; Facilities for running a whole set of tests. + +;; The data structure that contains the set of tests being executed +;; during one particular test run, their results, the state of the +;; execution, and some statistics. +;; +;; The data about results and expected results of tests may seem +;; redundant here, since the test objects also carry such information. +;; However, the information in the test objects may be more recent, it +;; may correspond to a different test run. We need the information +;; that corresponds to this run in order to be able to update the +;; statistics correctly when a test is re-run interactively and has a +;; different result than before. +(defstruct ert--stats + (selector (assert nil)) + ;; The tests, in order. + (tests (assert nil) :type vector) + ;; A map of test names (or the test objects themselves for unnamed + ;; tests) to indices into the `tests' vector. + (test-map (assert nil) :type hash-table) + ;; The results of the tests during this run, in order. + (test-results (assert nil) :type vector) + ;; The start times of the tests, in order, as reported by + ;; `current-time'. + (test-start-times (assert nil) :type vector) + ;; The end times of the tests, in order, as reported by + ;; `current-time'. + (test-end-times (assert nil) :type vector) + (passed-expected 0) + (passed-unexpected 0) + (failed-expected 0) + (failed-unexpected 0) + (start-time nil) + (end-time nil) + (aborted-p nil) + (current-test nil) + ;; The time at or after which the next redisplay should occur, as a + ;; float. + (next-redisplay 0.0)) + +(defun ert-stats-completed-expected (stats) + "Return the number of tests in STATS that had expected results." + (+ (ert--stats-passed-expected stats) + (ert--stats-failed-expected stats))) + +(defun ert-stats-completed-unexpected (stats) + "Return the number of tests in STATS that had unexpected results." + (+ (ert--stats-passed-unexpected stats) + (ert--stats-failed-unexpected stats))) + +(defun ert-stats-completed (stats) + "Number of tests in STATS that have run so far." + (+ (ert-stats-completed-expected stats) + (ert-stats-completed-unexpected stats))) + +(defun ert-stats-total (stats) + "Number of tests in STATS, regardless of whether they have run yet." + (length (ert--stats-tests stats))) + +;; The stats object of the current run, dynamically bound. This is +;; used for the mode line progress indicator. +(defvar ert--current-run-stats nil) + +(defun ert--stats-test-key (test) + "Return the key used for TEST in the test map of ert--stats objects. + +Returns the name of TEST if it has one, or TEST itself otherwise." + (or (ert-test-name test) test)) + +(defun ert--stats-set-test-and-result (stats pos test result) + "Change STATS by replacing the test at position POS with TEST and RESULT. + +Also changes the counters in STATS to match." + (let* ((tests (ert--stats-tests stats)) + (results (ert--stats-test-results stats)) + (old-test (aref tests pos)) + (map (ert--stats-test-map stats))) + (flet ((update (d) + (if (ert-test-result-expected-p (aref tests pos) + (aref results pos)) + (etypecase (aref results pos) + (ert-test-passed (incf (ert--stats-passed-expected stats) d)) + (ert-test-failed (incf (ert--stats-failed-expected stats) d)) + (null) + (ert-test-aborted-with-non-local-exit)) + (etypecase (aref results pos) + (ert-test-passed (incf (ert--stats-passed-unexpected stats) d)) + (ert-test-failed (incf (ert--stats-failed-unexpected stats) d)) + (null) + (ert-test-aborted-with-non-local-exit))))) + ;; Adjust counters to remove the result that is currently in stats. + (update -1) + ;; Put new test and result into stats. + (setf (aref tests pos) test + (aref results pos) result) + (remhash (ert--stats-test-key old-test) map) + (setf (gethash (ert--stats-test-key test) map) pos) + ;; Adjust counters to match new result. + (update +1) + nil))) + +(defun ert--make-stats (tests selector) + "Create a new `ert--stats' object for running TESTS. + +SELECTOR is the selector that was used to select TESTS." + (setq tests (ert--coerce-to-vector tests)) + (let ((map (make-hash-table :size (length tests)))) + (loop for i from 0 + for test across tests + for key = (ert--stats-test-key test) do + (assert (not (gethash key map))) + (setf (gethash key map) i)) + (make-ert--stats :selector selector + :tests tests + :test-map map + :test-results (make-vector (length tests) nil) + :test-start-times (make-vector (length tests) nil) + :test-end-times (make-vector (length tests) nil)))) + +(defun ert-run-or-rerun-test (stats test listener) + ;; checkdoc-order: nil + "Run the single test TEST and record the result using STATS and LISTENER." + (let ((ert--current-run-stats stats) + (pos (ert--stats-test-pos stats test))) + (ert--stats-set-test-and-result stats pos test nil) + ;; Call listener after setting/before resetting + ;; (ert--stats-current-test stats); the listener might refresh the + ;; mode line display, and if the value is not set yet/any more + ;; during this refresh, the mode line will flicker unnecessarily. + (setf (ert--stats-current-test stats) test) + (funcall listener 'test-started stats test) + (setf (ert-test-most-recent-result test) nil) + (setf (aref (ert--stats-test-start-times stats) pos) (current-time)) + (unwind-protect + (ert-run-test test) + (setf (aref (ert--stats-test-end-times stats) pos) (current-time)) + (let ((result (ert-test-most-recent-result test))) + (ert--stats-set-test-and-result stats pos test result) + (funcall listener 'test-ended stats test result)) + (setf (ert--stats-current-test stats) nil)))) + +(defun ert-run-tests (selector listener) + "Run the tests specified by SELECTOR, sending progress updates to LISTENER." + (let* ((tests (ert-select-tests selector t)) + (stats (ert--make-stats tests selector))) + (setf (ert--stats-start-time stats) (current-time)) + (funcall listener 'run-started stats) + (let ((abortedp t)) + (unwind-protect + (let ((ert--current-run-stats stats)) + (force-mode-line-update) + (unwind-protect + (progn + (loop for test in tests do + (ert-run-or-rerun-test stats test listener)) + (setq abortedp nil)) + (setf (ert--stats-aborted-p stats) abortedp) + (setf (ert--stats-end-time stats) (current-time)) + (funcall listener 'run-ended stats abortedp))) + (force-mode-line-update)) + stats))) + +(defun ert--stats-test-pos (stats test) + ;; checkdoc-order: nil + "Return the position (index) of TEST in the run represented by STATS." + (gethash (ert--stats-test-key test) (ert--stats-test-map stats))) + + +;;; Formatting functions shared across UIs. + +(defun ert--format-time-iso8601 (time) + "Format TIME in the variant of ISO 8601 used for timestamps in ERT." + (format-time-string "%Y-%m-%d %T%z" time)) + +(defun ert-char-for-test-result (result expectedp) + "Return a character that represents the test result RESULT. + +EXPECTEDP specifies whether the result was expected." + (let ((s (etypecase result + (ert-test-passed ".P") + (ert-test-failed "fF") + (null "--") + (ert-test-aborted-with-non-local-exit "aA")))) + (elt s (if expectedp 0 1)))) + +(defun ert-string-for-test-result (result expectedp) + "Return a string that represents the test result RESULT. + +EXPECTEDP specifies whether the result was expected." + (let ((s (etypecase result + (ert-test-passed '("passed" "PASSED")) + (ert-test-failed '("failed" "FAILED")) + (null '("unknown" "UNKNOWN")) + (ert-test-aborted-with-non-local-exit '("aborted" "ABORTED"))))) + (elt s (if expectedp 0 1)))) + +(defun ert--pp-with-indentation-and-newline (object) + "Pretty-print OBJECT, indenting it to the current column of point. +Ensures a final newline is inserted." + (let ((begin (point))) + (pp object (current-buffer)) + (unless (bolp) (insert "\n")) + (save-excursion + (goto-char begin) + (indent-sexp)))) + +(defun ert--insert-infos (result) + "Insert `ert-info' infos from RESULT into current buffer. + +RESULT must be an `ert-test-result-with-condition'." + (check-type result ert-test-result-with-condition) + (dolist (info (ert-test-result-with-condition-infos result)) + (destructuring-bind (prefix . message) info + (let ((begin (point)) + (indentation (make-string (+ (length prefix) 4) ?\s)) + (end nil)) + (unwind-protect + (progn + (insert message "\n") + (setq end (copy-marker (point))) + (goto-char begin) + (insert " " prefix) + (forward-line 1) + (while (< (point) end) + (insert indentation) + (forward-line 1))) + (when end (set-marker end nil))))))) + + +;;; Running tests in batch mode. + +(defvar ert-batch-backtrace-right-margin 70 + "*The maximum line length for printing backtraces in `ert-run-tests-batch'.") + +;;;###autoload +(defun ert-run-tests-batch (&optional selector) + "Run the tests specified by SELECTOR, printing results to the terminal. + +SELECTOR works as described in `ert-select-tests', except if +SELECTOR is nil, in which case all tests rather than none will be +run; this makes the command line \"emacs -batch -l my-tests.el -f +ert-run-tests-batch-and-exit\" useful. + +Returns the stats object." + (unless selector (setq selector 't)) + (ert-run-tests + selector + (lambda (event-type &rest event-args) + (ecase event-type + (run-started + (destructuring-bind (stats) event-args + (message "Running %s tests (%s)" + (length (ert--stats-tests stats)) + (ert--format-time-iso8601 (ert--stats-start-time stats))))) + (run-ended + (destructuring-bind (stats abortedp) event-args + (let ((unexpected (ert-stats-completed-unexpected stats)) + (expected-failures (ert--stats-failed-expected stats))) + (message "\n%sRan %s tests, %s results as expected%s (%s)%s\n" + (if (not abortedp) + "" + "Aborted: ") + (ert-stats-total stats) + (ert-stats-completed-expected stats) + (if (zerop unexpected) + "" + (format ", %s unexpected" unexpected)) + (ert--format-time-iso8601 (ert--stats-end-time stats)) + (if (zerop expected-failures) + "" + (format "\n%s expected failures" expected-failures))) + (unless (zerop unexpected) + (message "%s unexpected results:" unexpected) + (loop for test across (ert--stats-tests stats) + for result = (ert-test-most-recent-result test) do + (when (not (ert-test-result-expected-p test result)) + (message "%9s %S" + (ert-string-for-test-result result nil) + (ert-test-name test)))) + (message "%s" ""))))) + (test-started + ) + (test-ended + (destructuring-bind (stats test result) event-args + (unless (ert-test-result-expected-p test result) + (etypecase result + (ert-test-passed + (message "Test %S passed unexpectedly" (ert-test-name test))) + (ert-test-result-with-condition + (message "Test %S backtrace:" (ert-test-name test)) + (with-temp-buffer + (ert--print-backtrace (ert-test-result-with-condition-backtrace + result)) + (goto-char (point-min)) + (while (not (eobp)) + (let ((start (point)) + (end (progn (end-of-line) (point)))) + (setq end (min end + (+ start ert-batch-backtrace-right-margin))) + (message "%s" (buffer-substring-no-properties + start end))) + (forward-line 1))) + (with-temp-buffer + (ert--insert-infos result) + (insert " ") + (let ((print-escape-newlines t) + (print-level 5) + (print-length 10)) + (let ((begin (point))) + (ert--pp-with-indentation-and-newline + (ert-test-result-with-condition-condition result)))) + (goto-char (1- (point-max))) + (assert (looking-at "\n")) + (delete-char 1) + (message "Test %S condition:" (ert-test-name test)) + (message "%s" (buffer-string)))) + (ert-test-aborted-with-non-local-exit + (message "Test %S aborted with non-local exit" + (ert-test-name test))))) + (let* ((max (prin1-to-string (length (ert--stats-tests stats)))) + (format-string (concat "%9s %" + (prin1-to-string (length max)) + "s/" max " %S"))) + (message format-string + (ert-string-for-test-result result + (ert-test-result-expected-p + test result)) + (1+ (ert--stats-test-pos stats test)) + (ert-test-name test))))))))) + +;;;###autoload +(defun ert-run-tests-batch-and-exit (&optional selector) + "Like `ert-run-tests-batch', but exits Emacs when done. + +The exit status will be 0 if all test results were as expected, 1 +on unexpected results, or 2 if the framework detected an error +outside of the tests (e.g. invalid SELECTOR or bug in the code +that runs the tests)." + (unwind-protect + (let ((stats (ert-run-tests-batch selector))) + (kill-emacs (if (zerop (ert-stats-completed-unexpected stats)) 0 1))) + (unwind-protect + (progn + (message "Error running tests") + (backtrace)) + (kill-emacs 2)))) + + +;;; Utility functions for load/unload actions. + +(defun ert--activate-font-lock-keywords () + "Activate font-lock keywords for some of ERT's symbols." + (font-lock-add-keywords + nil + '(("(\\(\\\\s *\\(\\sw+\\)?" + (1 font-lock-keyword-face nil t) + (2 font-lock-function-name-face nil t))))) + +(defun* ert--remove-from-list (list-var element &key key test) + "Remove ELEMENT from the value of LIST-VAR if present. + +This can be used as an inverse of `add-to-list'." + (unless key (setq key #'identity)) + (unless test (setq test #'equal)) + (setf (symbol-value list-var) + (ert--remove* element + (symbol-value list-var) + :key key + :test test))) + + +;;; Some basic interactive functions. + +(defun ert-read-test-name (prompt &optional default history + add-default-to-prompt) + "Read the name of a test and return it as a symbol. + +Prompt with PROMPT. If DEFAULT is a valid test name, use it as a +default. HISTORY is the history to use; see `completing-read'. +If ADD-DEFAULT-TO-PROMPT is non-nil, PROMPT will be modified to +include the default, if any. + +Signals an error if no test name was read." + (etypecase default + (string (let ((symbol (intern-soft default))) + (unless (and symbol (ert-test-boundp symbol)) + (setq default nil)))) + (symbol (setq default + (if (ert-test-boundp default) + (symbol-name default) + nil))) + (ert-test (setq default (ert-test-name default)))) + (when add-default-to-prompt + (setq prompt (if (null default) + (format "%s: " prompt) + (format "%s (default %s): " prompt default)))) + (let ((input (completing-read prompt obarray #'ert-test-boundp + t nil history default nil))) + ;; completing-read returns an empty string if default was nil and + ;; the user just hit enter. + (let ((sym (intern-soft input))) + (if (ert-test-boundp sym) + sym + (error "Input does not name a test"))))) + +(defun ert-read-test-name-at-point (prompt) + "Read the name of a test and return it as a symbol. +As a default, use the symbol at point, or the test at point if in +the ERT results buffer. Prompt with PROMPT, augmented with the +default (if any)." + (ert-read-test-name prompt (ert-test-at-point) nil t)) + +(defun ert-find-test-other-window (test-name) + "Find, in another window, the definition of TEST-NAME." + (interactive (list (ert-read-test-name-at-point "Find test definition: "))) + (find-function-do-it test-name 'ert-deftest 'switch-to-buffer-other-window)) + +(defun ert-delete-test (test-name) + "Make the test TEST-NAME unbound. + +Nothing more than an interactive interface to `ert-make-test-unbound'." + (interactive (list (ert-read-test-name-at-point "Delete test"))) + (ert-make-test-unbound test-name)) + +(defun ert-delete-all-tests () + "Make all symbols in `obarray' name no test." + (interactive) + (when (interactive-p) + (unless (y-or-n-p "Delete all tests? ") + (error "Aborted"))) + ;; We can't use `ert-select-tests' here since that gives us only + ;; test objects, and going from them back to the test name symbols + ;; can fail if the `ert-test' defstruct has been redefined. + (mapc #'ert-make-test-unbound (apropos-internal "" #'ert-test-boundp)) + t) + + +;;; Display of test progress and results. + +;; An entry in the results buffer ewoc. There is one entry per test. +(defstruct ert--ewoc-entry + (test (assert nil)) + ;; If the result of this test was expected, its ewoc entry is hidden + ;; initially. + (hidden-p (assert nil)) + ;; An ewoc entry may be collapsed to hide details such as the error + ;; condition. + ;; + ;; I'm not sure the ability to expand and collapse entries is still + ;; a useful feature. + (expanded-p t) + ;; By default, the ewoc entry presents the error condition with + ;; certain limits on how much to print (`print-level', + ;; `print-length'). The user can interactively switch to a set of + ;; higher limits. + (extended-printer-limits-p nil)) + +;; Variables local to the results buffer. + +;; The ewoc. +(defvar ert--results-ewoc) +;; The stats object. +(defvar ert--results-stats) +;; A string with one character per test. Each character represents +;; the result of the corresponding test. The string is displayed near +;; the top of the buffer and serves as a progress bar. +(defvar ert--results-progress-bar-string) +;; The position where the progress bar button begins. +(defvar ert--results-progress-bar-button-begin) +;; The test result listener that updates the buffer when tests are run. +(defvar ert--results-listener) + +(defun ert-insert-test-name-button (test-name) + "Insert a button that links to TEST-NAME." + (insert-text-button (format "%S" test-name) + :type 'ert--test-name-button + 'ert-test-name test-name)) + +(defun ert--results-format-expected-unexpected (expected unexpected) + "Return a string indicating EXPECTED expected results, UNEXPECTED unexpected." + (if (zerop unexpected) + (format "%s" expected) + (format "%s (%s unexpected)" (+ expected unexpected) unexpected))) + +(defun ert--results-update-ewoc-hf (ewoc stats) + "Update the header and footer of EWOC to show certain information from STATS. + +Also sets `ert--results-progress-bar-button-begin'." + (let ((run-count (ert-stats-completed stats)) + (results-buffer (current-buffer)) + ;; Need to save buffer-local value. + (font-lock font-lock-mode)) + (ewoc-set-hf + ewoc + ;; header + (with-temp-buffer + (insert "Selector: ") + (ert--insert-human-readable-selector (ert--stats-selector stats)) + (insert "\n") + (insert + (format (concat "Passed: %s\n" + "Failed: %s\n" + "Total: %s/%s\n\n") + (ert--results-format-expected-unexpected + (ert--stats-passed-expected stats) + (ert--stats-passed-unexpected stats)) + (ert--results-format-expected-unexpected + (ert--stats-failed-expected stats) + (ert--stats-failed-unexpected stats)) + run-count + (ert-stats-total stats))) + (insert + (format "Started at: %s\n" + (ert--format-time-iso8601 (ert--stats-start-time stats)))) + ;; FIXME: This is ugly. Need to properly define invariants of + ;; the `stats' data structure. + (let ((state (cond ((ert--stats-aborted-p stats) 'aborted) + ((ert--stats-current-test stats) 'running) + ((ert--stats-end-time stats) 'finished) + (t 'preparing)))) + (ecase state + (preparing + (insert "")) + (aborted + (cond ((ert--stats-current-test stats) + (insert "Aborted during test: ") + (ert-insert-test-name-button + (ert-test-name (ert--stats-current-test stats)))) + (t + (insert "Aborted.")))) + (running + (assert (ert--stats-current-test stats)) + (insert "Running test: ") + (ert-insert-test-name-button (ert-test-name + (ert--stats-current-test stats)))) + (finished + (assert (not (ert--stats-current-test stats))) + (insert "Finished."))) + (insert "\n") + (if (ert--stats-end-time stats) + (insert + (format "%s%s\n" + (if (ert--stats-aborted-p stats) + "Aborted at: " + "Finished at: ") + (ert--format-time-iso8601 (ert--stats-end-time stats)))) + (insert "\n")) + (insert "\n")) + (let ((progress-bar-string (with-current-buffer results-buffer + ert--results-progress-bar-string))) + (let ((progress-bar-button-begin + (insert-text-button progress-bar-string + :type 'ert--results-progress-bar-button + 'face (or (and font-lock + (ert-face-for-stats stats)) + 'button)))) + ;; The header gets copied verbatim to the results buffer, + ;; and all positions remain the same, so + ;; `progress-bar-button-begin' will be the right position + ;; even in the results buffer. + (with-current-buffer results-buffer + (set (make-local-variable 'ert--results-progress-bar-button-begin) + progress-bar-button-begin)))) + (insert "\n\n") + (buffer-string)) + ;; footer + ;; + ;; We actually want an empty footer, but that would trigger a bug + ;; in ewoc, sometimes clearing the entire buffer. (It's possible + ;; that this bug has been fixed since this has been tested; we + ;; should test it again.) + "\n"))) + + +(defvar ert-test-run-redisplay-interval-secs .1 + "How many seconds ERT should wait between redisplays while running tests. + +While running tests, ERT shows the current progress, and this variable +determines how frequently the progress display is updated.") + +(defun ert--results-update-stats-display (ewoc stats) + "Update EWOC and the mode line to show data from STATS." + ;; TODO(ohler): investigate using `make-progress-reporter'. + (ert--results-update-ewoc-hf ewoc stats) + (force-mode-line-update) + (redisplay t) + (setf (ert--stats-next-redisplay stats) + (+ (float-time) ert-test-run-redisplay-interval-secs))) + +(defun ert--results-update-stats-display-maybe (ewoc stats) + "Call `ert--results-update-stats-display' if not called recently. + +EWOC and STATS are arguments for `ert--results-update-stats-display'." + (when (>= (float-time) (ert--stats-next-redisplay stats)) + (ert--results-update-stats-display ewoc stats))) + +(defun ert--tests-running-mode-line-indicator () + "Return a string for the mode line that shows the test run progress." + (let* ((stats ert--current-run-stats) + (tests-total (ert-stats-total stats)) + (tests-completed (ert-stats-completed stats))) + (if (>= tests-completed tests-total) + (format " ERT(%s/%s,finished)" tests-completed tests-total) + (format " ERT(%s/%s):%s" + (1+ tests-completed) + tests-total + (if (null (ert--stats-current-test stats)) + "?" + (format "%S" + (ert-test-name (ert--stats-current-test stats)))))))) + +(defun ert--make-xrefs-region (begin end) + "Attach cross-references to function names between BEGIN and END. + +BEGIN and END specify a region in the current buffer." + (save-excursion + (save-restriction + (narrow-to-region begin (point)) + ;; Inhibit optimization in `debugger-make-xrefs' that would + ;; sometimes insert unrelated backtrace info into our buffer. + (let ((debugger-previous-backtrace nil)) + (debugger-make-xrefs))))) + +(defun ert--string-first-line (s) + "Return the first line of S, or S if it contains no newlines. + +The return value does not include the line terminator." + (substring s 0 (ert--string-position ?\n s))) + +(defun ert-face-for-test-result (expectedp) + "Return a face that shows whether a test result was expected or unexpected. + +If EXPECTEDP is nil, returns the face for unexpected results; if +non-nil, returns the face for expected results.." + (if expectedp 'ert-test-result-expected 'ert-test-result-unexpected)) + +(defun ert-face-for-stats (stats) + "Return a face that represents STATS." + (cond ((ert--stats-aborted-p stats) 'nil) + ((plusp (ert-stats-completed-unexpected stats)) + (ert-face-for-test-result nil)) + ((eql (ert-stats-completed-expected stats) (ert-stats-total stats)) + (ert-face-for-test-result t)) + (t 'nil))) + +(defun ert--print-test-for-ewoc (entry) + "The ewoc print function for ewoc test entries. ENTRY is the entry to print." + (let* ((test (ert--ewoc-entry-test entry)) + (stats ert--results-stats) + (result (let ((pos (ert--stats-test-pos stats test))) + (assert pos) + (aref (ert--stats-test-results stats) pos))) + (hiddenp (ert--ewoc-entry-hidden-p entry)) + (expandedp (ert--ewoc-entry-expanded-p entry)) + (extended-printer-limits-p (ert--ewoc-entry-extended-printer-limits-p + entry))) + (cond (hiddenp) + (t + (let ((expectedp (ert-test-result-expected-p test result))) + (insert-text-button (format "%c" (ert-char-for-test-result + result expectedp)) + :type 'ert--results-expand-collapse-button + 'face (or (and font-lock-mode + (ert-face-for-test-result + expectedp)) + 'button))) + (insert " ") + (ert-insert-test-name-button (ert-test-name test)) + (insert "\n") + (when (and expandedp (not (eql result 'nil))) + (when (ert-test-documentation test) + (insert " " + (propertize + (ert--string-first-line (ert-test-documentation test)) + 'font-lock-face 'font-lock-doc-face) + "\n")) + (etypecase result + (ert-test-passed + (if (ert-test-result-expected-p test result) + (insert " passed\n") + (insert " passed unexpectedly\n")) + (insert "")) + (ert-test-result-with-condition + (ert--insert-infos result) + (let ((print-escape-newlines t) + (print-level (if extended-printer-limits-p 12 6)) + (print-length (if extended-printer-limits-p 100 10))) + (insert " ") + (let ((begin (point))) + (ert--pp-with-indentation-and-newline + (ert-test-result-with-condition-condition result)) + (ert--make-xrefs-region begin (point))))) + (ert-test-aborted-with-non-local-exit + (insert " aborted\n"))) + (insert "\n"))))) + nil) + +(defun ert--results-font-lock-function (enabledp) + "Redraw the ERT results buffer after font-lock-mode was switched on or off. + +ENABLEDP is true if font-lock-mode is switched on, false +otherwise." + (ert--results-update-ewoc-hf ert--results-ewoc ert--results-stats) + (ewoc-refresh ert--results-ewoc) + (font-lock-default-function enabledp)) + +(defun ert--setup-results-buffer (stats listener buffer-name) + "Set up a test results buffer. + +STATS is the stats object; LISTENER is the results listener; +BUFFER-NAME, if non-nil, is the buffer name to use." + (unless buffer-name (setq buffer-name "*ert*")) + (let ((buffer (get-buffer-create buffer-name))) + (with-current-buffer buffer + (setq buffer-read-only t) + (let ((inhibit-read-only t)) + (buffer-disable-undo) + (erase-buffer) + (ert-results-mode) + ;; Erase buffer again in case switching out of the previous + ;; mode inserted anything. (This happens e.g. when switching + ;; from ert-results-mode to ert-results-mode when + ;; font-lock-mode turns itself off in change-major-mode-hook.) + (erase-buffer) + (set (make-local-variable 'font-lock-function) + 'ert--results-font-lock-function) + (let ((ewoc (ewoc-create 'ert--print-test-for-ewoc nil nil t))) + (set (make-local-variable 'ert--results-ewoc) ewoc) + (set (make-local-variable 'ert--results-stats) stats) + (set (make-local-variable 'ert--results-progress-bar-string) + (make-string (ert-stats-total stats) + (ert-char-for-test-result nil t))) + (set (make-local-variable 'ert--results-listener) listener) + (loop for test across (ert--stats-tests stats) do + (ewoc-enter-last ewoc + (make-ert--ewoc-entry :test test :hidden-p t))) + (ert--results-update-ewoc-hf ert--results-ewoc ert--results-stats) + (goto-char (1- (point-max))) + buffer))))) + + +(defvar ert--selector-history nil + "List of recent test selectors read from terminal.") + +;; Should OUTPUT-BUFFER-NAME and MESSAGE-FN really be arguments here? +;; They are needed only for our automated self-tests at the moment. +;; Or should there be some other mechanism? +;;;###autoload +(defun ert-run-tests-interactively (selector + &optional output-buffer-name message-fn) + "Run the tests specified by SELECTOR and display the results in a buffer. + +SELECTOR works as described in `ert-select-tests'. +OUTPUT-BUFFER-NAME and MESSAGE-FN should normally be nil; they +are used for automated self-tests and specify which buffer to use +and how to display message." + (interactive + (list (let ((default (if ert--selector-history + ;; Can't use `first' here as this form is + ;; not compiled, and `first' is not + ;; defined without cl. + (car ert--selector-history) + "t"))) + (read-from-minibuffer (if (null default) + "Run tests: " + (format "Run tests (default %s): " default)) + nil nil t 'ert--selector-history + default nil)) + nil)) + (unless message-fn (setq message-fn 'message)) + (lexical-let ((output-buffer-name output-buffer-name) + buffer + listener + (message-fn message-fn)) + (setq listener + (lambda (event-type &rest event-args) + (ecase event-type + (run-started + (destructuring-bind (stats) event-args + (setq buffer (ert--setup-results-buffer stats + listener + output-buffer-name)) + (pop-to-buffer buffer))) + (run-ended + (destructuring-bind (stats abortedp) event-args + (funcall message-fn + "%sRan %s tests, %s results were as expected%s" + (if (not abortedp) + "" + "Aborted: ") + (ert-stats-total stats) + (ert-stats-completed-expected stats) + (let ((unexpected + (ert-stats-completed-unexpected stats))) + (if (zerop unexpected) + "" + (format ", %s unexpected" unexpected)))) + (ert--results-update-stats-display (with-current-buffer buffer + ert--results-ewoc) + stats))) + (test-started + (destructuring-bind (stats test) event-args + (with-current-buffer buffer + (let* ((ewoc ert--results-ewoc) + (pos (ert--stats-test-pos stats test)) + (node (ewoc-nth ewoc pos))) + (assert node) + (setf (ert--ewoc-entry-test (ewoc-data node)) test) + (aset ert--results-progress-bar-string pos + (ert-char-for-test-result nil t)) + (ert--results-update-stats-display-maybe ewoc stats) + (ewoc-invalidate ewoc node))))) + (test-ended + (destructuring-bind (stats test result) event-args + (with-current-buffer buffer + (let* ((ewoc ert--results-ewoc) + (pos (ert--stats-test-pos stats test)) + (node (ewoc-nth ewoc pos))) + (when (ert--ewoc-entry-hidden-p (ewoc-data node)) + (setf (ert--ewoc-entry-hidden-p (ewoc-data node)) + (ert-test-result-expected-p test result))) + (aset ert--results-progress-bar-string pos + (ert-char-for-test-result result + (ert-test-result-expected-p + test result))) + (ert--results-update-stats-display-maybe ewoc stats) + (ewoc-invalidate ewoc node)))))))) + (ert-run-tests + selector + listener))) +;;;###autoload +(defalias 'ert 'ert-run-tests-interactively) + + +;;; Simple view mode for auxiliary information like stack traces or +;;; messages. Mainly binds "q" for quit. + +(define-derived-mode ert-simple-view-mode fundamental-mode "ERT-View" + "Major mode for viewing auxiliary information in ERT.") + +(loop for (key binding) in + '(("q" quit-window) + ) + do + (define-key ert-simple-view-mode-map key binding)) + + +;;; Commands and button actions for the results buffer. + +(define-derived-mode ert-results-mode fundamental-mode "ERT-Results" + "Major mode for viewing results of ERT test runs.") + +(loop for (key binding) in + '(;; Stuff that's not in the menu. + ("\t" forward-button) + ([backtab] backward-button) + ("j" ert-results-jump-between-summary-and-result) + ("q" quit-window) + ("L" ert-results-toggle-printer-limits-for-test-at-point) + ("n" ert-results-next-test) + ("p" ert-results-previous-test) + ;; Stuff that is in the menu. + ("R" ert-results-rerun-all-tests) + ("r" ert-results-rerun-test-at-point) + ("d" ert-results-rerun-test-at-point-debugging-errors) + ("." ert-results-find-test-at-point-other-window) + ("b" ert-results-pop-to-backtrace-for-test-at-point) + ("m" ert-results-pop-to-messages-for-test-at-point) + ("l" ert-results-pop-to-should-forms-for-test-at-point) + ("h" ert-results-describe-test-at-point) + ("D" ert-delete-test) + ("T" ert-results-pop-to-timings) + ) + do + (define-key ert-results-mode-map key binding)) + +(easy-menu-define ert-results-mode-menu ert-results-mode-map + "Menu for `ert-results-mode'." + '("ERT Results" + ["Re-run all tests" ert-results-rerun-all-tests] + "--" + ["Re-run test" ert-results-rerun-test-at-point] + ["Debug test" ert-results-rerun-test-at-point-debugging-errors] + ["Show test definition" ert-results-find-test-at-point-other-window] + "--" + ["Show backtrace" ert-results-pop-to-backtrace-for-test-at-point] + ["Show messages" ert-results-pop-to-messages-for-test-at-point] + ["Show `should' forms" ert-results-pop-to-should-forms-for-test-at-point] + ["Describe test" ert-results-describe-test-at-point] + "--" + ["Delete test" ert-delete-test] + "--" + ["Show execution time of each test" ert-results-pop-to-timings] + )) + +(define-button-type 'ert--results-progress-bar-button + 'action #'ert--results-progress-bar-button-action + 'help-echo "mouse-2, RET: Reveal test result") + +(define-button-type 'ert--test-name-button + 'action #'ert--test-name-button-action + 'help-echo "mouse-2, RET: Find test definition") + +(define-button-type 'ert--results-expand-collapse-button + 'action #'ert--results-expand-collapse-button-action + 'help-echo "mouse-2, RET: Expand/collapse test result") + +(defun ert--results-test-node-or-null-at-point () + "If point is on a valid ewoc node, return it; return nil otherwise. + +To be used in the ERT results buffer." + (let* ((ewoc ert--results-ewoc) + (node (ewoc-locate ewoc))) + ;; `ewoc-locate' will return an arbitrary node when point is on + ;; header or footer, or when all nodes are invisible. So we need + ;; to validate its return value here. + ;; + ;; Update: I'm seeing nil being returned in some cases now, + ;; perhaps this has been changed? + (if (and node + (>= (point) (ewoc-location node)) + (not (ert--ewoc-entry-hidden-p (ewoc-data node)))) + node + nil))) + +(defun ert--results-test-node-at-point () + "If point is on a valid ewoc node, return it; signal an error otherwise. + +To be used in the ERT results buffer." + (or (ert--results-test-node-or-null-at-point) + (error "No test at point"))) + +(defun ert-results-next-test () + "Move point to the next test. + +To be used in the ERT results buffer." + (interactive) + (ert--results-move (ewoc-locate ert--results-ewoc) 'ewoc-next + "No tests below")) + +(defun ert-results-previous-test () + "Move point to the previous test. + +To be used in the ERT results buffer." + (interactive) + (ert--results-move (ewoc-locate ert--results-ewoc) 'ewoc-prev + "No tests above")) + +(defun ert--results-move (node ewoc-fn error-message) + "Move point from NODE to the previous or next node. + +EWOC-FN specifies the direction and should be either `ewoc-prev' +or `ewoc-next'. If there are no more nodes in that direction, an +error is signalled with the message ERROR-MESSAGE." + (loop + (setq node (funcall ewoc-fn ert--results-ewoc node)) + (when (null node) + (error "%s" error-message)) + (unless (ert--ewoc-entry-hidden-p (ewoc-data node)) + (goto-char (ewoc-location node)) + (return)))) + +(defun ert--results-expand-collapse-button-action (button) + "Expand or collapse the test node BUTTON belongs to." + (let* ((ewoc ert--results-ewoc) + (node (save-excursion + (goto-char (ert--button-action-position)) + (ert--results-test-node-at-point))) + (entry (ewoc-data node))) + (setf (ert--ewoc-entry-expanded-p entry) + (not (ert--ewoc-entry-expanded-p entry))) + (ewoc-invalidate ewoc node))) + +(defun ert-results-find-test-at-point-other-window () + "Find the definition of the test at point in another window. + +To be used in the ERT results buffer." + (interactive) + (let ((name (ert-test-at-point))) + (unless name + (error "No test at point")) + (ert-find-test-other-window name))) + +(defun ert--test-name-button-action (button) + "Find the definition of the test BUTTON belongs to, in another window." + (let ((name (button-get button 'ert-test-name))) + (ert-find-test-other-window name))) + +(defun ert--ewoc-position (ewoc node) + ;; checkdoc-order: nil + "Return the position of NODE in EWOC, or nil if NODE is not in EWOC." + (loop for i from 0 + for node-here = (ewoc-nth ewoc 0) then (ewoc-next ewoc node-here) + do (when (eql node node-here) + (return i)) + finally (return nil))) + +(defun ert-results-jump-between-summary-and-result () + "Jump back and forth between the test run summary and individual test results. + +From an ewoc node, jumps to the character that represents the +same test in the progress bar, and vice versa. + +To be used in the ERT results buffer." + ;; Maybe this command isn't actually needed much, but if it is, it + ;; seems like an indication that the UI design is not optimal. If + ;; jumping back and forth between a summary at the top of the buffer + ;; and the error log in the remainder of the buffer is useful, then + ;; the summary apparently needs to be easily accessible from the + ;; error log, and perhaps it would be better to have it in a + ;; separate buffer to keep it visible. + (interactive) + (let ((ewoc ert--results-ewoc) + (progress-bar-begin ert--results-progress-bar-button-begin)) + (cond ((ert--results-test-node-or-null-at-point) + (let* ((node (ert--results-test-node-at-point)) + (pos (ert--ewoc-position ewoc node))) + (goto-char (+ progress-bar-begin pos)))) + ((and (<= progress-bar-begin (point)) + (< (point) (button-end (button-at progress-bar-begin)))) + (let* ((node (ewoc-nth ewoc (- (point) progress-bar-begin))) + (entry (ewoc-data node))) + (when (ert--ewoc-entry-hidden-p entry) + (setf (ert--ewoc-entry-hidden-p entry) nil) + (ewoc-invalidate ewoc node)) + (ewoc-goto-node ewoc node))) + (t + (goto-char progress-bar-begin))))) + +(defun ert-test-at-point () + "Return the name of the test at point as a symbol, or nil if none." + (or (and (eql major-mode 'ert-results-mode) + (let ((test (ert--results-test-at-point-no-redefinition))) + (and test (ert-test-name test)))) + (let* ((thing (thing-at-point 'symbol)) + (sym (intern-soft thing))) + (and (ert-test-boundp sym) + sym)))) + +(defun ert--results-test-at-point-no-redefinition () + "Return the test at point, or nil. + +To be used in the ERT results buffer." + (assert (eql major-mode 'ert-results-mode)) + (if (ert--results-test-node-or-null-at-point) + (let* ((node (ert--results-test-node-at-point)) + (test (ert--ewoc-entry-test (ewoc-data node)))) + test) + (let ((progress-bar-begin ert--results-progress-bar-button-begin)) + (when (and (<= progress-bar-begin (point)) + (< (point) (button-end (button-at progress-bar-begin)))) + (let* ((test-index (- (point) progress-bar-begin)) + (test (aref (ert--stats-tests ert--results-stats) + test-index))) + test))))) + +(defun ert--results-test-at-point-allow-redefinition () + "Look up the test at point, and check whether it has been redefined. + +To be used in the ERT results buffer. + +Returns a list of two elements: the test (or nil) and a symbol +specifying whether the test has been redefined. + +If a new test has been defined with the same name as the test at +point, replaces the test at point with the new test, and returns +the new test and the symbol `redefined'. + +If the test has been deleted, returns the old test and the symbol +`deleted'. + +If the test is still current, returns the test and the symbol nil. + +If there is no test at point, returns a list with two nils." + (let ((test (ert--results-test-at-point-no-redefinition))) + (cond ((null test) + `(nil nil)) + ((null (ert-test-name test)) + `(,test nil)) + (t + (let* ((name (ert-test-name test)) + (new-test (and (ert-test-boundp name) + (ert-get-test name)))) + (cond ((eql test new-test) + `(,test nil)) + ((null new-test) + `(,test deleted)) + (t + (ert--results-update-after-test-redefinition + (ert--stats-test-pos ert--results-stats test) + new-test) + `(,new-test redefined)))))))) + +(defun ert--results-update-after-test-redefinition (pos new-test) + "Update results buffer after the test at pos POS has been redefined. + +Also updates the stats object. NEW-TEST is the new test +definition." + (let* ((stats ert--results-stats) + (ewoc ert--results-ewoc) + (node (ewoc-nth ewoc pos)) + (entry (ewoc-data node))) + (ert--stats-set-test-and-result stats pos new-test nil) + (setf (ert--ewoc-entry-test entry) new-test + (aref ert--results-progress-bar-string pos) (ert-char-for-test-result + nil t)) + (ewoc-invalidate ewoc node)) + nil) + +(defun ert--button-action-position () + "The buffer position where the last button action was triggered." + (cond ((integerp last-command-event) + (point)) + ((eventp last-command-event) + (posn-point (event-start last-command-event))) + (t (assert nil)))) + +(defun ert--results-progress-bar-button-action (button) + "Jump to details for the test represented by the character clicked in BUTTON." + (goto-char (ert--button-action-position)) + (ert-results-jump-between-summary-and-result)) + +(defun ert-results-rerun-all-tests () + "Re-run all tests, using the same selector. + +To be used in the ERT results buffer." + (interactive) + (assert (eql major-mode 'ert-results-mode)) + (let ((selector (ert--stats-selector ert--results-stats))) + (ert-run-tests-interactively selector (buffer-name)))) + +(defun ert-results-rerun-test-at-point () + "Re-run the test at point. + +To be used in the ERT results buffer." + (interactive) + (destructuring-bind (test redefinition-state) + (ert--results-test-at-point-allow-redefinition) + (when (null test) + (error "No test at point")) + (let* ((stats ert--results-stats) + (progress-message (format "Running %stest %S" + (ecase redefinition-state + ((nil) "") + (redefined "new definition of ") + (deleted "deleted ")) + (ert-test-name test)))) + ;; Need to save and restore point manually here: When point is on + ;; the first visible ewoc entry while the header is updated, point + ;; moves to the top of the buffer. This is undesirable, and a + ;; simple `save-excursion' doesn't prevent it. + (let ((point (point))) + (unwind-protect + (unwind-protect + (progn + (message "%s..." progress-message) + (ert-run-or-rerun-test stats test + ert--results-listener)) + (ert--results-update-stats-display ert--results-ewoc stats) + (message "%s...%s" + progress-message + (let ((result (ert-test-most-recent-result test))) + (ert-string-for-test-result + result (ert-test-result-expected-p test result))))) + (goto-char point)))))) + +(defun ert-results-rerun-test-at-point-debugging-errors () + "Re-run the test at point with `ert-debug-on-error' bound to t. + +To be used in the ERT results buffer." + (interactive) + (let ((ert-debug-on-error t)) + (ert-results-rerun-test-at-point))) + +(defun ert-results-pop-to-backtrace-for-test-at-point () + "Display the backtrace for the test at point. + +To be used in the ERT results buffer." + (interactive) + (let* ((test (ert--results-test-at-point-no-redefinition)) + (stats ert--results-stats) + (pos (ert--stats-test-pos stats test)) + (result (aref (ert--stats-test-results stats) pos))) + (etypecase result + (ert-test-passed (error "Test passed, no backtrace available")) + (ert-test-result-with-condition + (let ((backtrace (ert-test-result-with-condition-backtrace result)) + (buffer (get-buffer-create "*ERT Backtrace*"))) + (pop-to-buffer buffer) + (setq buffer-read-only t) + (let ((inhibit-read-only t)) + (buffer-disable-undo) + (erase-buffer) + (ert-simple-view-mode) + ;; Use unibyte because `debugger-setup-buffer' also does so. + (set-buffer-multibyte nil) + (setq truncate-lines t) + (ert--print-backtrace backtrace) + (debugger-make-xrefs) + (goto-char (point-min)) + (insert "Backtrace for test `") + (ert-insert-test-name-button (ert-test-name test)) + (insert "':\n"))))))) + +(defun ert-results-pop-to-messages-for-test-at-point () + "Display the part of the *Messages* buffer generated during the test at point. + +To be used in the ERT results buffer." + (interactive) + (let* ((test (ert--results-test-at-point-no-redefinition)) + (stats ert--results-stats) + (pos (ert--stats-test-pos stats test)) + (result (aref (ert--stats-test-results stats) pos))) + (let ((buffer (get-buffer-create "*ERT Messages*"))) + (pop-to-buffer buffer) + (setq buffer-read-only t) + (let ((inhibit-read-only t)) + (buffer-disable-undo) + (erase-buffer) + (ert-simple-view-mode) + (insert (ert-test-result-messages result)) + (goto-char (point-min)) + (insert "Messages for test `") + (ert-insert-test-name-button (ert-test-name test)) + (insert "':\n"))))) + +(defun ert-results-pop-to-should-forms-for-test-at-point () + "Display the list of `should' forms executed during the test at point. + +To be used in the ERT results buffer." + (interactive) + (let* ((test (ert--results-test-at-point-no-redefinition)) + (stats ert--results-stats) + (pos (ert--stats-test-pos stats test)) + (result (aref (ert--stats-test-results stats) pos))) + (let ((buffer (get-buffer-create "*ERT list of should forms*"))) + (pop-to-buffer buffer) + (setq buffer-read-only t) + (let ((inhibit-read-only t)) + (buffer-disable-undo) + (erase-buffer) + (ert-simple-view-mode) + (if (null (ert-test-result-should-forms result)) + (insert "\n(No should forms during this test.)\n") + (loop for form-description in (ert-test-result-should-forms result) + for i from 1 do + (insert "\n") + (insert (format "%s: " i)) + (let ((begin (point))) + (ert--pp-with-indentation-and-newline form-description) + (ert--make-xrefs-region begin (point))))) + (goto-char (point-min)) + (insert "`should' forms executed during test `") + (ert-insert-test-name-button (ert-test-name test)) + (insert "':\n") + (insert "\n") + (insert (concat "(Values are shallow copies and may have " + "looked different during the test if they\n" + "have been modified destructively.)\n")) + (forward-line 1))))) + +(defun ert-results-toggle-printer-limits-for-test-at-point () + "Toggle how much of the condition to print for the test at point. + +To be used in the ERT results buffer." + (interactive) + (let* ((ewoc ert--results-ewoc) + (node (ert--results-test-node-at-point)) + (entry (ewoc-data node))) + (setf (ert--ewoc-entry-extended-printer-limits-p entry) + (not (ert--ewoc-entry-extended-printer-limits-p entry))) + (ewoc-invalidate ewoc node))) + +(defun ert-results-pop-to-timings () + "Display test timings for the last run. + +To be used in the ERT results buffer." + (interactive) + (let* ((stats ert--results-stats) + (start-times (ert--stats-test-start-times stats)) + (end-times (ert--stats-test-end-times stats)) + (buffer (get-buffer-create "*ERT timings*")) + (data (loop for test across (ert--stats-tests stats) + for start-time across (ert--stats-test-start-times stats) + for end-time across (ert--stats-test-end-times stats) + collect (list test + (float-time (subtract-time end-time + start-time)))))) + (setq data (sort data (lambda (a b) + (> (second a) (second b))))) + (pop-to-buffer buffer) + (setq buffer-read-only t) + (let ((inhibit-read-only t)) + (buffer-disable-undo) + (erase-buffer) + (ert-simple-view-mode) + (if (null data) + (insert "(No data)\n") + (insert (format "%-3s %8s %8s\n" "" "time" "cumul")) + (loop for (test time) in data + for cumul-time = time then (+ cumul-time time) + for i from 1 do + (let ((begin (point))) + (insert (format "%3s: %8.3f %8.3f " i time cumul-time)) + (ert-insert-test-name-button (ert-test-name test)) + (insert "\n")))) + (goto-char (point-min)) + (insert "Tests by run time (seconds):\n\n") + (forward-line 1)))) + +;;;###autoload +(defun ert-describe-test (test-or-test-name) + "Display the documentation for TEST-OR-TEST-NAME (a symbol or ert-test)." + (interactive (list (ert-read-test-name-at-point "Describe test"))) + (when (< emacs-major-version 24) + (error "Requires Emacs 24")) + (let (test-name + test-definition) + (etypecase test-or-test-name + (symbol (setq test-name test-or-test-name + test-definition (ert-get-test test-or-test-name))) + (ert-test (setq test-name (ert-test-name test-or-test-name) + test-definition test-or-test-name))) + (help-setup-xref (list #'ert-describe-test test-or-test-name) + (called-interactively-p 'interactive)) + (save-excursion + (with-help-window (help-buffer) + (with-current-buffer (help-buffer) + (insert (if test-name (format "%S" test-name) "")) + (insert " is a test") + (let ((file-name (and test-name + (symbol-file test-name 'ert-deftest)))) + (when file-name + (insert " defined in `" (file-name-nondirectory file-name) "'") + (save-excursion + (re-search-backward "`\\([^`']+\\)'" nil t) + (help-xref-button 1 'help-function-def test-name file-name))) + (insert ".") + (fill-region-as-paragraph (point-min) (point)) + (insert "\n\n") + (unless (and (ert-test-boundp test-name) + (eql (ert-get-test test-name) test-definition)) + (let ((begin (point))) + (insert "Note: This test has been redefined or deleted, " + "this documentation refers to an old definition.") + (fill-region-as-paragraph begin (point))) + (insert "\n\n")) + (insert (or (ert-test-documentation test-definition) + "It is not documented.") + "\n"))))))) + +(defun ert-results-describe-test-at-point () + "Display the documentation of the test at point. + +To be used in the ERT results buffer." + (interactive) + (ert-describe-test (ert--results-test-at-point-no-redefinition))) + + +;;; Actions on load/unload. + +(add-to-list 'find-function-regexp-alist '(ert-deftest . ert--find-test-regexp)) +(add-to-list 'minor-mode-alist '(ert--current-run-stats + (:eval + (ert--tests-running-mode-line-indicator)))) +(add-to-list 'emacs-lisp-mode-hook 'ert--activate-font-lock-keywords) + +(defun ert--unload-function () + "Unload function to undo the side-effects of loading ert.el." + (ert--remove-from-list 'find-function-regexp-alist 'ert-deftest :key #'car) + (ert--remove-from-list 'minor-mode-alist 'ert--current-run-stats :key #'car) + (ert--remove-from-list 'emacs-lisp-mode-hook + 'ert--activate-font-lock-keywords) + nil) + +(defvar ert-unload-hook '()) +(add-hook 'ert-unload-hook 'ert--unload-function) + + +(provide 'ert) + +;;; ert.el ends here diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/lib/ert.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/lib/ert.el new file mode 100644 index 0000000..53b76f7 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/lib/ert.el @@ -0,0 +1,2544 @@ +;;; ert.el --- Emacs Lisp Regression Testing + +;; Copyright (C) 2007, 2008, 2010 Free Software Foundation, Inc. + +;; Author: Christian M. Ohler +;; Keywords: lisp, tools + +;; This file is NOT part of GNU Emacs. + +;; This program is free software: you can redistribute it and/or +;; modify it under the terms of the GNU General Public License as +;; published by the Free Software Foundation, either version 3 of the +;; License, or (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see `http://www.gnu.org/licenses/'. + +;;; Commentary: + +;; ERT is a tool for automated testing in Emacs Lisp. Its main +;; features are facilities for defining and running test cases and +;; reporting the results as well as for debugging test failures +;; interactively. +;; +;; The main entry points are `ert-deftest', which is similar to +;; `defun' but defines a test, and `ert-run-tests-interactively', +;; which runs tests and offers an interactive interface for inspecting +;; results and debugging. There is also +;; `ert-run-tests-batch-and-exit' for non-interactive use. +;; +;; The body of `ert-deftest' forms resembles a function body, but the +;; additional operators `should', `should-not' and `should-error' are +;; available. `should' is similar to cl's `assert', but signals a +;; different error when its condition is violated that is caught and +;; processed by ERT. In addition, it analyzes its argument form and +;; records information that helps debugging (`assert' tries to do +;; something similar when its second argument SHOW-ARGS is true, but +;; `should' is more sophisticated). For information on `should-not' +;; and `should-error', see their docstrings. +;; +;; See ERT's info manual as well as the docstrings for more details. +;; To compile the manual, run `makeinfo ert.texinfo' in the ERT +;; directory, then C-u M-x info ert.info in Emacs to view it. +;; +;; To see some examples of tests written in ERT, see its self-tests in +;; ert-tests.el. Some of these are tricky due to the bootstrapping +;; problem of writing tests for a testing tool, others test simple +;; functions and are straightforward. + +;;; Code: + +(eval-when-compile + (require 'cl)) +(require 'button) +(require 'debug) +(require 'easymenu) +(require 'ewoc) +(require 'find-func) +(require 'help) + + +;;; UI customization options. + +(defgroup ert () + "ERT, the Emacs Lisp regression testing tool." + :prefix "ert-" + :group 'lisp) + +(defface ert-test-result-expected '((((class color) (background light)) + :background "green1") + (((class color) (background dark)) + :background "green3")) + "Face used for expected results in the ERT results buffer." + :group 'ert) + +(defface ert-test-result-unexpected '((((class color) (background light)) + :background "red1") + (((class color) (background dark)) + :background "red3")) + "Face used for unexpected results in the ERT results buffer." + :group 'ert) + + +;;; Copies/reimplementations of cl functions. + +(defun ert--cl-do-remf (plist tag) + "Copy of `cl-do-remf'. Modify PLIST by removing TAG." + (let ((p (cdr plist))) + (while (and (cdr p) (not (eq (car (cdr p)) tag))) (setq p (cdr (cdr p)))) + (and (cdr p) (progn (setcdr p (cdr (cdr (cdr p)))) t)))) + +(defun ert--remprop (sym tag) + "Copy of `cl-remprop'. Modify SYM's plist by removing TAG." + (let ((plist (symbol-plist sym))) + (if (and plist (eq tag (car plist))) + (progn (setplist sym (cdr (cdr plist))) t) + (ert--cl-do-remf plist tag)))) + +(defun ert--remove-if-not (ert-pred ert-list) + "A reimplementation of `remove-if-not'. + +ERT-PRED is a predicate, ERT-LIST is the input list." + (loop for ert-x in ert-list + if (funcall ert-pred ert-x) + collect ert-x)) + +(defun ert--intersection (a b) + "A reimplementation of `intersection'. Intersect the sets A and B. + +Elements are compared using `eql'." + (loop for x in a + if (memql x b) + collect x)) + +(defun ert--set-difference (a b) + "A reimplementation of `set-difference'. Subtract the set B from the set A. + +Elements are compared using `eql'." + (loop for x in a + unless (memql x b) + collect x)) + +(defun ert--set-difference-eq (a b) + "A reimplementation of `set-difference'. Subtract the set B from the set A. + +Elements are compared using `eq'." + (loop for x in a + unless (memq x b) + collect x)) + +(defun ert--union (a b) + "A reimplementation of `union'. Compute the union of the sets A and B. + +Elements are compared using `eql'." + (append a (ert--set-difference b a))) + +(eval-and-compile + (defvar ert--gensym-counter 0)) + +(eval-and-compile + (defun ert--gensym (&optional prefix) + "Only allows string PREFIX, not compatible with CL." + (unless prefix (setq prefix "G")) + (make-symbol (format "%s%s" + prefix + (prog1 ert--gensym-counter + (incf ert--gensym-counter)))))) + +(defun ert--coerce-to-vector (x) + "Coerce X to a vector." + (when (char-table-p x) (error "Not supported")) + (if (vectorp x) + x + (vconcat x))) + +(defun* ert--remove* (x list &key key test) + "Does not support all the keywords of remove*." + (unless key (setq key #'identity)) + (unless test (setq test #'eql)) + (loop for y in list + unless (funcall test x (funcall key y)) + collect y)) + +(defun ert--string-position (c s) + "Return the position of the first occurrence of C in S, or nil if none." + (loop for i from 0 + for x across s + when (eql x c) return i)) + +(defun ert--mismatch (a b) + "Return index of first element that differs between A and B. + +Like `mismatch'. Uses `equal' for comparison." + (cond ((or (listp a) (listp b)) + (ert--mismatch (ert--coerce-to-vector a) + (ert--coerce-to-vector b))) + ((> (length a) (length b)) + (ert--mismatch b a)) + (t + (let ((la (length a)) + (lb (length b))) + (assert (arrayp a) t) + (assert (arrayp b) t) + (assert (<= la lb) t) + (loop for i below la + when (not (equal (aref a i) (aref b i))) return i + finally (return (if (/= la lb) + la + (assert (equal a b) t) + nil))))))) + +(defun ert--subseq (seq start &optional end) + "Return a subsequence of SEQ from START to END." + (when (char-table-p seq) (error "Not supported")) + (let ((vector (substring (ert--coerce-to-vector seq) start end))) + (etypecase seq + (vector vector) + (string (concat vector)) + (list (append vector nil)) + (bool-vector (loop with result = (make-bool-vector (length vector) nil) + for i below (length vector) do + (setf (aref result i) (aref vector i)) + finally (return result))) + (char-table (assert nil))))) + +(defun ert-equal-including-properties (a b) + "Return t if A and B have similar structure and contents. + +This is like `equal-including-properties' except that it compares +the property values of text properties structurally (by +recursing) rather than with `eq'. Perhaps this is what +`equal-including-properties' should do in the first place; see +Emacs bug 6581 at URL `http://debbugs.gnu.org/cgi/bugreport.cgi?bug=6581'." + ;; This implementation is inefficient. Rather than making it + ;; efficient, let's hope bug 6581 gets fixed so that we can delete + ;; it altogether. + (not (ert--explain-not-equal-including-properties a b))) + + +;;; Defining and locating tests. + +;; The data structure that represents a test case. +(defstruct ert-test + (name nil) + (documentation nil) + (body (assert nil)) + (most-recent-result nil) + (expected-result-type ':passed) + (tags '())) + +(defun ert-test-boundp (symbol) + "Return non-nil if SYMBOL names a test." + (and (get symbol 'ert--test) t)) + +(defun ert-get-test (symbol) + "If SYMBOL names a test, return that. Signal an error otherwise." + (unless (ert-test-boundp symbol) (error "No test named `%S'" symbol)) + (get symbol 'ert--test)) + +(defun ert-set-test (symbol definition) + "Make SYMBOL name the test DEFINITION, and return DEFINITION." + (when (eq symbol 'nil) + ;; We disallow nil since `ert-test-at-point' and related functions + ;; want to return a test name, but also need an out-of-band value + ;; on failure. Nil is the most natural out-of-band value; using 0 + ;; or "" or signalling an error would be too awkward. + ;; + ;; Note that nil is still a valid value for the `name' slot in + ;; ert-test objects. It designates an anonymous test. + (error "Attempt to define a test named nil")) + (put symbol 'ert--test definition) + definition) + +(defun ert-make-test-unbound (symbol) + "Make SYMBOL name no test. Return SYMBOL." + (ert--remprop symbol 'ert--test) + symbol) + +(defun ert--parse-keys-and-body (keys-and-body) + "Split KEYS-AND-BODY into keyword-and-value pairs and the remaining body. + +KEYS-AND-BODY should have the form of a property list, with the +exception that only keywords are permitted as keys and that the +tail -- the body -- is a list of forms that does not start with a +keyword. + +Returns a two-element list containing the keys-and-values plist +and the body." + (let ((extracted-key-accu '()) + (remaining keys-and-body)) + (while (and (consp remaining) (keywordp (first remaining))) + (let ((keyword (pop remaining))) + (unless (consp remaining) + (error "Value expected after keyword %S in %S" + keyword keys-and-body)) + (when (assoc keyword extracted-key-accu) + (warn "Keyword %S appears more than once in %S" keyword + keys-and-body)) + (push (cons keyword (pop remaining)) extracted-key-accu))) + (setq extracted-key-accu (nreverse extracted-key-accu)) + (list (loop for (key . value) in extracted-key-accu + collect key + collect value) + remaining))) + +;;;###autoload +(defmacro* ert-deftest (name () &body docstring-keys-and-body) + "Define NAME (a symbol) as a test. + +BODY is evaluated as a `progn' when the test is run. It should +signal a condition on failure or just return if the test passes. + +`should', `should-not' and `should-error' are useful for +assertions in BODY. + +Use `ert' to run tests interactively. + +Tests that are expected to fail can be marked as such +using :expected-result. See `ert-test-result-type-p' for a +description of valid values for RESULT-TYPE. + +\(fn NAME () [DOCSTRING] [:expected-result RESULT-TYPE] \ +\[:tags '(TAG...)] BODY...)" + (declare (debug (&define :name test + name sexp [&optional stringp] + [&rest keywordp sexp] def-body)) + (doc-string 3) + (indent 2)) + (let ((documentation nil) + (documentation-supplied-p nil)) + (when (stringp (first docstring-keys-and-body)) + (setq documentation (pop docstring-keys-and-body) + documentation-supplied-p t)) + (destructuring-bind ((&key (expected-result nil expected-result-supplied-p) + (tags nil tags-supplied-p)) + body) + (ert--parse-keys-and-body docstring-keys-and-body) + `(progn + (ert-set-test ',name + (make-ert-test + :name ',name + ,@(when documentation-supplied-p + `(:documentation ,documentation)) + ,@(when expected-result-supplied-p + `(:expected-result-type ,expected-result)) + ,@(when tags-supplied-p + `(:tags ,tags)) + :body (lambda () ,@body))) + ;; This hack allows `symbol-file' to associate `ert-deftest' + ;; forms with files, and therefore enables `find-function' to + ;; work with tests. However, it leads to warnings in + ;; `unload-feature', which doesn't know how to undefine tests + ;; and has no mechanism for extension. + (push '(ert-deftest . ,name) current-load-list) + ',name)))) + +;; We use these `put' forms in addition to the (declare (indent)) in +;; the defmacro form since the `declare' alone does not lead to +;; correct indentation before the .el/.elc file is loaded. +;; Autoloading these `put' forms solves this. +;;;###autoload +(progn + ;; TODO(ohler): Figure out what these mean and make sure they are correct. + (put 'ert-deftest 'lisp-indent-function 2) + (put 'ert-info 'lisp-indent-function 1)) + +(defvar ert--find-test-regexp + (concat "^\\s-*(ert-deftest" + find-function-space-re + "%s\\(\\s-\\|$\\)") + "The regexp the `find-function' mechanisms use for finding test definitions.") + + +(put 'ert-test-failed 'error-conditions '(error ert-test-failed)) +(put 'ert-test-failed 'error-message "Test failed") + +(defun ert-pass () + "Terminate the current test and mark it passed. Does not return." + (throw 'ert--pass nil)) + +(defun ert-fail (data) + "Terminate the current test and mark it failed. Does not return. +DATA is displayed to the user and should state the reason of the failure." + (signal 'ert-test-failed (list data))) + + +;;; The `should' macros. + +(defvar ert--should-execution-observer nil) + +(defun ert--signal-should-execution (form-description) + "Tell the current `should' form observer (if any) about FORM-DESCRIPTION." + (when ert--should-execution-observer + (funcall ert--should-execution-observer form-description))) + +(defun ert--special-operator-p (thing) + "Return non-nil if THING is a symbol naming a special operator." + (and (symbolp thing) + (let ((definition (indirect-function thing t))) + (and (subrp definition) + (eql (cdr (subr-arity definition)) 'unevalled))))) + +(defun ert--expand-should-1 (whole form inner-expander) + "Helper function for the `should' macro and its variants." + (let ((form + ;; If `cl-macroexpand' isn't bound, the code that we're + ;; compiling doesn't depend on cl and thus doesn't need an + ;; environment arg for `macroexpand'. + (if (fboundp 'cl-macroexpand) + ;; Suppress warning about run-time call to cl funtion: we + ;; only call it if it's fboundp. + (with-no-warnings + (cl-macroexpand form (and (boundp 'cl-macro-environment) + cl-macro-environment))) + (macroexpand form)))) + (cond + ((or (atom form) (ert--special-operator-p (car form))) + (let ((value (ert--gensym "value-"))) + `(let ((,value (ert--gensym "ert-form-evaluation-aborted-"))) + ,(funcall inner-expander + `(setq ,value ,form) + `(list ',whole :form ',form :value ,value) + value) + ,value))) + (t + (let ((fn-name (car form)) + (arg-forms (cdr form))) + (assert (or (symbolp fn-name) + (and (consp fn-name) + (eql (car fn-name) 'lambda) + (listp (cdr fn-name))))) + (let ((fn (ert--gensym "fn-")) + (args (ert--gensym "args-")) + (value (ert--gensym "value-")) + (default-value (ert--gensym "ert-form-evaluation-aborted-"))) + `(let ((,fn (function ,fn-name)) + (,args (list ,@arg-forms))) + (let ((,value ',default-value)) + ,(funcall inner-expander + `(setq ,value (apply ,fn ,args)) + `(nconc (list ',whole) + (list :form `(,,fn ,@,args)) + (unless (eql ,value ',default-value) + (list :value ,value)) + (let ((-explainer- + (and (symbolp ',fn-name) + (get ',fn-name 'ert-explainer)))) + (when -explainer- + (list :explanation + (apply -explainer- ,args))))) + value) + ,value)))))))) + +(defun ert--expand-should (whole form inner-expander) + "Helper function for the `should' macro and its variants. + +Analyzes FORM and returns an expression that has the same +semantics under evaluation but records additional debugging +information. + +INNER-EXPANDER should be a function and is called with two +arguments: INNER-FORM and FORM-DESCRIPTION-FORM, where INNER-FORM +is an expression equivalent to FORM, and FORM-DESCRIPTION-FORM is +an expression that returns a description of FORM. INNER-EXPANDER +should return code that calls INNER-FORM and performs the checks +and error signalling specific to the particular variant of +`should'. The code that INNER-EXPANDER returns must not call +FORM-DESCRIPTION-FORM before it has called INNER-FORM." + (lexical-let ((inner-expander inner-expander)) + (ert--expand-should-1 + whole form + (lambda (inner-form form-description-form value-var) + (let ((form-description (ert--gensym "form-description-"))) + `(let (,form-description) + ,(funcall inner-expander + `(unwind-protect + ,inner-form + (setq ,form-description ,form-description-form) + (ert--signal-should-execution ,form-description)) + `,form-description + value-var))))))) + +(defmacro* should (form) + "Evaluate FORM. If it returns nil, abort the current test as failed. + +Returns the value of FORM." + (ert--expand-should `(should ,form) form + (lambda (inner-form form-description-form value-var) + `(unless ,inner-form + (ert-fail ,form-description-form))))) + +(defmacro* should-not (form) + "Evaluate FORM. If it returns non-nil, abort the current test as failed. + +Returns nil." + (ert--expand-should `(should-not ,form) form + (lambda (inner-form form-description-form value-var) + `(unless (not ,inner-form) + (ert-fail ,form-description-form))))) + +(defun ert--should-error-handle-error (form-description-fn + condition type exclude-subtypes) + "Helper function for `should-error'. + +Determines whether CONDITION matches TYPE and EXCLUDE-SUBTYPES, +and aborts the current test as failed if it doesn't." + (let ((signalled-conditions (get (car condition) 'error-conditions)) + (handled-conditions (etypecase type + (list type) + (symbol (list type))))) + (assert signalled-conditions) + (unless (ert--intersection signalled-conditions handled-conditions) + (ert-fail (append + (funcall form-description-fn) + (list + :condition condition + :fail-reason (concat "the error signalled did not" + " have the expected type"))))) + (when exclude-subtypes + (unless (member (car condition) handled-conditions) + (ert-fail (append + (funcall form-description-fn) + (list + :condition condition + :fail-reason (concat "the error signalled was a subtype" + " of the expected type")))))))) + +;; FIXME: The expansion will evaluate the keyword args (if any) in +;; nonstandard order. +(defmacro* should-error (form &rest keys &key type exclude-subtypes) + "Evaluate FORM and check that it signals an error. + +The error signalled needs to match TYPE. TYPE should be a list +of condition names. (It can also be a non-nil symbol, which is +equivalent to a singleton list containing that symbol.) If +EXCLUDE-SUBTYPES is nil, the error matches TYPE if one of its +condition names is an element of TYPE. If EXCLUDE-SUBTYPES is +non-nil, the error matches TYPE if it is an element of TYPE. + +If the error matches, returns (ERROR-SYMBOL . DATA) from the +error. If not, or if no error was signalled, abort the test as +failed." + (unless type (setq type ''error)) + (ert--expand-should + `(should-error ,form ,@keys) + form + (lambda (inner-form form-description-form value-var) + (let ((errorp (ert--gensym "errorp")) + (form-description-fn (ert--gensym "form-description-fn-"))) + `(let ((,errorp nil) + (,form-description-fn (lambda () ,form-description-form))) + (condition-case -condition- + ,inner-form + ;; We can't use ,type here because we want to evaluate it. + (error + (setq ,errorp t) + (ert--should-error-handle-error ,form-description-fn + -condition- + ,type ,exclude-subtypes) + (setq ,value-var -condition-))) + (unless ,errorp + (ert-fail (append + (funcall ,form-description-fn) + (list + :fail-reason "did not signal an error"))))))))) + + +;;; Explanation of `should' failures. + +;; TODO(ohler): Rework explanations so that they are displayed in a +;; similar way to `ert-info' messages; in particular, allow text +;; buttons in explanations that give more detail or open an ediff +;; buffer. Perhaps explanations should be reported through `ert-info' +;; rather than as part of the condition. + +(defun ert--proper-list-p (x) + "Return non-nil if X is a proper list, nil otherwise." + (loop + for firstp = t then nil + for fast = x then (cddr fast) + for slow = x then (cdr slow) do + (when (null fast) (return t)) + (when (not (consp fast)) (return nil)) + (when (null (cdr fast)) (return t)) + (when (not (consp (cdr fast))) (return nil)) + (when (and (not firstp) (eq fast slow)) (return nil)))) + +(defun ert--explain-format-atom (x) + "Format the atom X for `ert--explain-not-equal'." + (typecase x + (fixnum (list x (format "#x%x" x) (format "?%c" x))) + (t x))) + +(defun ert--explain-not-equal (a b) + "Explainer function for `equal'. + +Returns a programmer-readable explanation of why A and B are not +`equal', or nil if they are." + (if (not (equal (type-of a) (type-of b))) + `(different-types ,a ,b) + (etypecase a + (cons + (let ((a-proper-p (ert--proper-list-p a)) + (b-proper-p (ert--proper-list-p b))) + (if (not (eql (not a-proper-p) (not b-proper-p))) + `(one-list-proper-one-improper ,a ,b) + (if a-proper-p + (if (not (equal (length a) (length b))) + `(proper-lists-of-different-length ,(length a) ,(length b) + ,a ,b + first-mismatch-at + ,(ert--mismatch a b)) + (loop for i from 0 + for ai in a + for bi in b + for xi = (ert--explain-not-equal ai bi) + do (when xi (return `(list-elt ,i ,xi))) + finally (assert (equal a b) t))) + (let ((car-x (ert--explain-not-equal (car a) (car b)))) + (if car-x + `(car ,car-x) + (let ((cdr-x (ert--explain-not-equal (cdr a) (cdr b)))) + (if cdr-x + `(cdr ,cdr-x) + (assert (equal a b) t) + nil)))))))) + (array (if (not (equal (length a) (length b))) + `(arrays-of-different-length ,(length a) ,(length b) + ,a ,b + ,@(unless (char-table-p a) + `(first-mismatch-at + ,(ert--mismatch a b)))) + (loop for i from 0 + for ai across a + for bi across b + for xi = (ert--explain-not-equal ai bi) + do (when xi (return `(array-elt ,i ,xi))) + finally (assert (equal a b) t)))) + (atom (if (not (equal a b)) + (if (and (symbolp a) (symbolp b) (string= a b)) + `(different-symbols-with-the-same-name ,a ,b) + `(different-atoms ,(ert--explain-format-atom a) + ,(ert--explain-format-atom b))) + nil))))) +(put 'equal 'ert-explainer 'ert--explain-not-equal) + +(defun ert--significant-plist-keys (plist) + "Return the keys of PLIST that have non-null values, in order." + (assert (zerop (mod (length plist) 2)) t) + (loop for (key value . rest) on plist by #'cddr + unless (or (null value) (memq key accu)) collect key into accu + finally (return accu))) + +(defun ert--plist-difference-explanation (a b) + "Return a programmer-readable explanation of why A and B are different plists. + +Returns nil if they are equivalent, i.e., have the same value for +each key, where absent values are treated as nil. The order of +key/value pairs in each list does not matter." + (assert (zerop (mod (length a) 2)) t) + (assert (zerop (mod (length b) 2)) t) + ;; Normalizing the plists would be another way to do this but it + ;; requires a total ordering on all lisp objects (since any object + ;; is valid as a text property key). Perhaps defining such an + ;; ordering is useful in other contexts, too, but it's a lot of + ;; work, so let's punt on it for now. + (let* ((keys-a (ert--significant-plist-keys a)) + (keys-b (ert--significant-plist-keys b)) + (keys-in-a-not-in-b (ert--set-difference-eq keys-a keys-b)) + (keys-in-b-not-in-a (ert--set-difference-eq keys-b keys-a))) + (flet ((explain-with-key (key) + (let ((value-a (plist-get a key)) + (value-b (plist-get b key))) + (assert (not (equal value-a value-b)) t) + `(different-properties-for-key + ,key ,(ert--explain-not-equal-including-properties value-a + value-b))))) + (cond (keys-in-a-not-in-b + (explain-with-key (first keys-in-a-not-in-b))) + (keys-in-b-not-in-a + (explain-with-key (first keys-in-b-not-in-a))) + (t + (loop for key in keys-a + when (not (equal (plist-get a key) (plist-get b key))) + return (explain-with-key key))))))) + +(defun ert--abbreviate-string (s len suffixp) + "Shorten string S to at most LEN chars. + +If SUFFIXP is non-nil, returns a suffix of S, otherwise a prefix." + (let ((n (length s))) + (cond ((< n len) + s) + (suffixp + (substring s (- n len))) + (t + (substring s 0 len))))) + +(defun ert--explain-not-equal-including-properties (a b) + "Explainer function for `ert-equal-including-properties'. + +Returns a programmer-readable explanation of why A and B are not +`ert-equal-including-properties', or nil if they are." + (if (not (equal a b)) + (ert--explain-not-equal a b) + (assert (stringp a) t) + (assert (stringp b) t) + (assert (eql (length a) (length b)) t) + (loop for i from 0 to (length a) + for props-a = (text-properties-at i a) + for props-b = (text-properties-at i b) + for difference = (ert--plist-difference-explanation props-a props-b) + do (when difference + (return `(char ,i ,(substring-no-properties a i (1+ i)) + ,difference + context-before + ,(ert--abbreviate-string + (substring-no-properties a 0 i) + 10 t) + context-after + ,(ert--abbreviate-string + (substring-no-properties a (1+ i)) + 10 nil)))) + ;; TODO(ohler): Get `equal-including-properties' fixed in + ;; Emacs, delete `ert-equal-including-properties', and + ;; re-enable this assertion. + ;;finally (assert (equal-including-properties a b) t) + ))) +(put 'ert-equal-including-properties + 'ert-explainer + 'ert--explain-not-equal-including-properties) + + +;;; Implementation of `ert-info'. + +;; TODO(ohler): The name `info' clashes with +;; `ert--test-execution-info'. One or both should be renamed. +(defvar ert--infos '() + "The stack of `ert-info' infos that currently apply. + +Bound dynamically. This is a list of (PREFIX . MESSAGE) pairs.") + +(defmacro* ert-info ((message-form &key ((:prefix prefix-form) "Info: ")) + &body body) + "Evaluate MESSAGE-FORM and BODY, and report the message if BODY fails. + +To be used within ERT tests. MESSAGE-FORM should evaluate to a +string that will be displayed together with the test result if +the test fails. PREFIX-FORM should evaluate to a string as well +and is displayed in front of the value of MESSAGE-FORM." + (declare (debug ((form &rest [sexp form]) body)) + (indent 1)) + `(let ((ert--infos (cons (cons ,prefix-form ,message-form) ert--infos))) + ,@body)) + + + +;;; Facilities for running a single test. + +(defvar ert-debug-on-error nil + "Non-nil means enter debugger when a test fails or terminates with an error.") + +;; The data structures that represent the result of running a test. +(defstruct ert-test-result + (messages nil) + (should-forms nil) + ) +(defstruct (ert-test-passed (:include ert-test-result))) +(defstruct (ert-test-result-with-condition (:include ert-test-result)) + (condition (assert nil)) + (backtrace (assert nil)) + (infos (assert nil))) +(defstruct (ert-test-quit (:include ert-test-result-with-condition))) +(defstruct (ert-test-failed (:include ert-test-result-with-condition))) +(defstruct (ert-test-aborted-with-non-local-exit (:include ert-test-result))) + + +(defun ert--record-backtrace () + "Record the current backtrace (as a list) and return it." + ;; Since the backtrace is stored in the result object, result + ;; objects must only be printed with appropriate limits + ;; (`print-level' and `print-length') in place. For interactive + ;; use, the cost of ensuring this possibly outweighs the advantage + ;; of storing the backtrace for + ;; `ert-results-pop-to-backtrace-for-test-at-point' given that we + ;; already have `ert-results-rerun-test-debugging-errors-at-point'. + ;; For batch use, however, printing the backtrace may be useful. + (loop + ;; 6 is the number of frames our own debugger adds (when + ;; compiled; more when interpreted). FIXME: Need to describe a + ;; procedure for determining this constant. + for i from 6 + for frame = (backtrace-frame i) + while frame + collect frame)) + +(defun ert--print-backtrace (backtrace) + "Format the backtrace BACKTRACE to the current buffer." + ;; This is essentially a reimplementation of Fbacktrace + ;; (src/eval.c), but for a saved backtrace, not the current one. + (let ((print-escape-newlines t) + (print-level 8) + (print-length 50)) + (dolist (frame backtrace) + (ecase (first frame) + ((nil) + ;; Special operator. + (destructuring-bind (special-operator &rest arg-forms) + (cdr frame) + (insert + (format " %S\n" (list* special-operator arg-forms))))) + ((t) + ;; Function call. + (destructuring-bind (fn &rest args) (cdr frame) + (insert (format " %S(" fn)) + (loop for firstp = t then nil + for arg in args do + (unless firstp + (insert " ")) + (insert (format "%S" arg))) + (insert ")\n"))))))) + +;; A container for the state of the execution of a single test and +;; environment data needed during its execution. +(defstruct ert--test-execution-info + (test (assert nil)) + (result (assert nil)) + ;; A thunk that may be called when RESULT has been set to its final + ;; value and test execution should be terminated. Should not + ;; return. + (exit-continuation (assert nil)) + ;; The binding of `debugger' outside of the execution of the test. + next-debugger + ;; The binding of `ert-debug-on-error' that is in effect for the + ;; execution of the current test. We store it to avoid being + ;; affected by any new bindings the test itself may establish. (I + ;; don't remember whether this feature is important.) + ert-debug-on-error) + +(defun ert--run-test-debugger (info debugger-args) + "During a test run, `debugger' is bound to a closure that calls this function. + +This function records failures and errors and either terminates +the test silently or calls the interactive debugger, as +appropriate. + +INFO is the ert--test-execution-info corresponding to this test +run. DEBUGGER-ARGS are the arguments to `debugger'." + (destructuring-bind (first-debugger-arg &rest more-debugger-args) + debugger-args + (ecase first-debugger-arg + ((lambda debug t exit nil) + (apply (ert--test-execution-info-next-debugger info) debugger-args)) + (error + (let* ((condition (first more-debugger-args)) + (type (case (car condition) + ((quit) 'quit) + (otherwise 'failed))) + (backtrace (ert--record-backtrace)) + (infos (reverse ert--infos))) + (setf (ert--test-execution-info-result info) + (ecase type + (quit + (make-ert-test-quit :condition condition + :backtrace backtrace + :infos infos)) + (failed + (make-ert-test-failed :condition condition + :backtrace backtrace + :infos infos)))) + ;; Work around Emacs' heuristic (in eval.c) for detecting + ;; errors in the debugger. + (incf num-nonmacro-input-events) + ;; FIXME: We should probably implement more fine-grained + ;; control a la non-t `debug-on-error' here. + (cond + ((ert--test-execution-info-ert-debug-on-error info) + (apply (ert--test-execution-info-next-debugger info) debugger-args)) + (t)) + (funcall (ert--test-execution-info-exit-continuation info))))))) + +(defun ert--run-test-internal (ert-test-execution-info) + "Low-level function to run a test according to ERT-TEST-EXECUTION-INFO. + +This mainly sets up debugger-related bindings." + (lexical-let ((info ert-test-execution-info)) + (setf (ert--test-execution-info-next-debugger info) debugger + (ert--test-execution-info-ert-debug-on-error info) ert-debug-on-error) + (catch 'ert--pass + ;; For now, each test gets its own temp buffer and its own + ;; window excursion, just to be safe. If this turns out to be + ;; too expensive, we can remove it. + (with-temp-buffer + (save-window-excursion + (let ((debugger (lambda (&rest debugger-args) + (ert--run-test-debugger info debugger-args))) + (debug-on-error t) + (debug-on-quit t) + ;; FIXME: Do we need to store the old binding of this + ;; and consider it in `ert--run-test-debugger'? + (debug-ignored-errors nil) + (ert--infos '())) + (funcall (ert-test-body (ert--test-execution-info-test info)))))) + (ert-pass)) + (setf (ert--test-execution-info-result info) (make-ert-test-passed))) + nil) + +(defun ert--force-message-log-buffer-truncation () + "Immediately truncate *Messages* buffer according to `message-log-max'. + +This can be useful after reducing the value of `message-log-max'." + (with-current-buffer (get-buffer-create "*Messages*") + ;; This is a reimplementation of this part of message_dolog() in xdisp.c: + ;; if (NATNUMP (Vmessage_log_max)) + ;; { + ;; scan_newline (Z, Z_BYTE, BEG, BEG_BYTE, + ;; -XFASTINT (Vmessage_log_max) - 1, 0); + ;; del_range_both (BEG, BEG_BYTE, PT, PT_BYTE, 0); + ;; } + (when (and (integerp message-log-max) (>= message-log-max 0)) + (let ((begin (point-min)) + (end (save-excursion + (goto-char (point-max)) + (forward-line (- message-log-max)) + (point)))) + (delete-region begin end))))) + +(defvar ert--running-tests nil + "List of tests that are currently in execution. + +This list is empty while no test is running, has one element +while a test is running, two elements while a test run from +inside a test is running, etc. The list is in order of nesting, +innermost test first. + +The elements are of type `ert-test'.") + +(defun ert-run-test (ert-test) + "Run ERT-TEST. + +Returns the result and stores it in ERT-TEST's `most-recent-result' slot." + (setf (ert-test-most-recent-result ert-test) nil) + (block error + (lexical-let ((begin-marker + (with-current-buffer (get-buffer-create "*Messages*") + (set-marker (make-marker) (point-max))))) + (unwind-protect + (lexical-let ((info (make-ert--test-execution-info + :test ert-test + :result + (make-ert-test-aborted-with-non-local-exit) + :exit-continuation (lambda () + (return-from error nil)))) + (should-form-accu (list))) + (unwind-protect + (let ((ert--should-execution-observer + (lambda (form-description) + (push form-description should-form-accu))) + (message-log-max t) + (ert--running-tests (cons ert-test ert--running-tests))) + (ert--run-test-internal info)) + (let ((result (ert--test-execution-info-result info))) + (setf (ert-test-result-messages result) + (with-current-buffer (get-buffer-create "*Messages*") + (buffer-substring begin-marker (point-max)))) + (ert--force-message-log-buffer-truncation) + (setq should-form-accu (nreverse should-form-accu)) + (setf (ert-test-result-should-forms result) + should-form-accu) + (setf (ert-test-most-recent-result ert-test) result)))) + (set-marker begin-marker nil)))) + (ert-test-most-recent-result ert-test)) + +(defun ert-running-test () + "Return the top-level test currently executing." + (car (last ert--running-tests))) + + +;;; Test selectors. + +(defun ert-test-result-type-p (result result-type) + "Return non-nil if RESULT matches type RESULT-TYPE. + +Valid result types: + +nil -- Never matches. +t -- Always matches. +:failed, :passed -- Matches corresponding results. +\(and TYPES...\) -- Matches if all TYPES match. +\(or TYPES...\) -- Matches if some TYPES match. +\(not TYPE\) -- Matches if TYPE does not match. +\(satisfies PREDICATE\) -- Matches if PREDICATE returns true when called with + RESULT." + ;; It would be easy to add `member' and `eql' types etc., but I + ;; haven't bothered yet. + (etypecase result-type + ((member nil) nil) + ((member t) t) + ((member :failed) (ert-test-failed-p result)) + ((member :passed) (ert-test-passed-p result)) + (cons + (destructuring-bind (operator &rest operands) result-type + (ecase operator + (and + (case (length operands) + (0 t) + (t + (and (ert-test-result-type-p result (first operands)) + (ert-test-result-type-p result `(and ,@(rest operands))))))) + (or + (case (length operands) + (0 nil) + (t + (or (ert-test-result-type-p result (first operands)) + (ert-test-result-type-p result `(or ,@(rest operands))))))) + (not + (assert (eql (length operands) 1)) + (not (ert-test-result-type-p result (first operands)))) + (satisfies + (assert (eql (length operands) 1)) + (funcall (first operands) result))))))) + +(defun ert-test-result-expected-p (test result) + "Return non-nil if TEST's expected result type matches RESULT." + (ert-test-result-type-p result (ert-test-expected-result-type test))) + +(defun ert-select-tests (selector universe) + "Return the tests that match SELECTOR. + +UNIVERSE specifies the set of tests to select from; it should be +a list of tests, or t, which refers to all tests named by symbols +in `obarray'. + +Returns the set of tests as a list. + +Valid selectors: + +nil -- Selects the empty set. +t -- Selects UNIVERSE. +:new -- Selects all tests that have not been run yet. +:failed, :passed -- Select tests according to their most recent result. +:expected, :unexpected -- Select tests according to their most recent result. +a string -- Selects all tests that have a name that matches the string, + a regexp. +a test -- Selects that test. +a symbol -- Selects the test that the symbol names, errors if none. +\(member TESTS...\) -- Selects TESTS, a list of tests or symbols naming tests. +\(eql TEST\) -- Selects TEST, a test or a symbol naming a test. +\(and SELECTORS...\) -- Selects the tests that match all SELECTORS. +\(or SELECTORS...\) -- Selects the tests that match any SELECTOR. +\(not SELECTOR\) -- Selects all tests that do not match SELECTOR. +\(tag TAG) -- Selects all tests that have TAG on their tags list. +\(satisfies PREDICATE\) -- Selects all tests that satisfy PREDICATE. + +Only selectors that require a superset of tests, such +as (satisfies ...), strings, :new, etc. make use of UNIVERSE. +Selectors that do not, such as \(member ...\), just return the +set implied by them without checking whether it is really +contained in UNIVERSE." + ;; This code needs to match the etypecase in + ;; `ert-insert-human-readable-selector'. + (etypecase selector + ((member nil) nil) + ((member t) (etypecase universe + (list universe) + ((member t) (ert-select-tests "" universe)))) + ((member :new) (ert-select-tests + `(satisfies ,(lambda (test) + (null (ert-test-most-recent-result test)))) + universe)) + ((member :failed) (ert-select-tests + `(satisfies ,(lambda (test) + (ert-test-result-type-p + (ert-test-most-recent-result test) + ':failed))) + universe)) + ((member :passed) (ert-select-tests + `(satisfies ,(lambda (test) + (ert-test-result-type-p + (ert-test-most-recent-result test) + ':passed))) + universe)) + ((member :expected) (ert-select-tests + `(satisfies + ,(lambda (test) + (ert-test-result-expected-p + test + (ert-test-most-recent-result test)))) + universe)) + ((member :unexpected) (ert-select-tests `(not :expected) universe)) + (string + (etypecase universe + ((member t) (mapcar #'ert-get-test + (apropos-internal selector #'ert-test-boundp))) + (list (ert--remove-if-not (lambda (test) + (and (ert-test-name test) + (string-match selector + (ert-test-name test)))) + universe)))) + (ert-test (list selector)) + (symbol + (assert (ert-test-boundp selector)) + (list (ert-get-test selector))) + (cons + (destructuring-bind (operator &rest operands) selector + (ecase operator + (member + (mapcar (lambda (purported-test) + (etypecase purported-test + (symbol (assert (ert-test-boundp purported-test)) + (ert-get-test purported-test)) + (ert-test purported-test))) + operands)) + (eql + (assert (eql (length operands) 1)) + (ert-select-tests `(member ,@operands) universe)) + (and + ;; Do these definitions of AND, NOT and OR satisfy de + ;; Morgan's laws? Should they? + (case (length operands) + (0 (ert-select-tests 't universe)) + (t (ert-select-tests `(and ,@(rest operands)) + (ert-select-tests (first operands) + universe))))) + (not + (assert (eql (length operands) 1)) + (let ((all-tests (ert-select-tests 't universe))) + (ert--set-difference all-tests + (ert-select-tests (first operands) + all-tests)))) + (or + (case (length operands) + (0 (ert-select-tests 'nil universe)) + (t (ert--union (ert-select-tests (first operands) universe) + (ert-select-tests `(or ,@(rest operands)) + universe))))) + (tag + (assert (eql (length operands) 1)) + (let ((tag (first operands))) + (ert-select-tests `(satisfies + ,(lambda (test) + (member tag (ert-test-tags test)))) + universe))) + (satisfies + (assert (eql (length operands) 1)) + (ert--remove-if-not (first operands) + (ert-select-tests 't universe)))))))) + +(defun ert--insert-human-readable-selector (selector) + "Insert a human-readable presentation of SELECTOR into the current buffer." + ;; This is needed to avoid printing the (huge) contents of the + ;; `backtrace' slot of the result objects in the + ;; `most-recent-result' slots of test case objects in (eql ...) or + ;; (member ...) selectors. + (labels ((rec (selector) + ;; This code needs to match the etypecase in `ert-select-tests'. + (etypecase selector + ((or (member nil t + :new :failed :passed + :expected :unexpected) + string + symbol) + selector) + (ert-test + (if (ert-test-name selector) + (make-symbol (format "<%S>" (ert-test-name selector))) + (make-symbol ""))) + (cons + (destructuring-bind (operator &rest operands) selector + (ecase operator + ((member eql and not or) + `(,operator ,@(mapcar #'rec operands))) + ((member tag satisfies) + selector))))))) + (insert (format "%S" (rec selector))))) + + +;;; Facilities for running a whole set of tests. + +;; The data structure that contains the set of tests being executed +;; during one particular test run, their results, the state of the +;; execution, and some statistics. +;; +;; The data about results and expected results of tests may seem +;; redundant here, since the test objects also carry such information. +;; However, the information in the test objects may be more recent, it +;; may correspond to a different test run. We need the information +;; that corresponds to this run in order to be able to update the +;; statistics correctly when a test is re-run interactively and has a +;; different result than before. +(defstruct ert--stats + (selector (assert nil)) + ;; The tests, in order. + (tests (assert nil) :type vector) + ;; A map of test names (or the test objects themselves for unnamed + ;; tests) to indices into the `tests' vector. + (test-map (assert nil) :type hash-table) + ;; The results of the tests during this run, in order. + (test-results (assert nil) :type vector) + ;; The start times of the tests, in order, as reported by + ;; `current-time'. + (test-start-times (assert nil) :type vector) + ;; The end times of the tests, in order, as reported by + ;; `current-time'. + (test-end-times (assert nil) :type vector) + (passed-expected 0) + (passed-unexpected 0) + (failed-expected 0) + (failed-unexpected 0) + (start-time nil) + (end-time nil) + (aborted-p nil) + (current-test nil) + ;; The time at or after which the next redisplay should occur, as a + ;; float. + (next-redisplay 0.0)) + +(defun ert-stats-completed-expected (stats) + "Return the number of tests in STATS that had expected results." + (+ (ert--stats-passed-expected stats) + (ert--stats-failed-expected stats))) + +(defun ert-stats-completed-unexpected (stats) + "Return the number of tests in STATS that had unexpected results." + (+ (ert--stats-passed-unexpected stats) + (ert--stats-failed-unexpected stats))) + +(defun ert-stats-completed (stats) + "Number of tests in STATS that have run so far." + (+ (ert-stats-completed-expected stats) + (ert-stats-completed-unexpected stats))) + +(defun ert-stats-total (stats) + "Number of tests in STATS, regardless of whether they have run yet." + (length (ert--stats-tests stats))) + +;; The stats object of the current run, dynamically bound. This is +;; used for the mode line progress indicator. +(defvar ert--current-run-stats nil) + +(defun ert--stats-test-key (test) + "Return the key used for TEST in the test map of ert--stats objects. + +Returns the name of TEST if it has one, or TEST itself otherwise." + (or (ert-test-name test) test)) + +(defun ert--stats-set-test-and-result (stats pos test result) + "Change STATS by replacing the test at position POS with TEST and RESULT. + +Also changes the counters in STATS to match." + (let* ((tests (ert--stats-tests stats)) + (results (ert--stats-test-results stats)) + (old-test (aref tests pos)) + (map (ert--stats-test-map stats))) + (flet ((update (d) + (if (ert-test-result-expected-p (aref tests pos) + (aref results pos)) + (etypecase (aref results pos) + (ert-test-passed (incf (ert--stats-passed-expected stats) d)) + (ert-test-failed (incf (ert--stats-failed-expected stats) d)) + (null) + (ert-test-aborted-with-non-local-exit)) + (etypecase (aref results pos) + (ert-test-passed (incf (ert--stats-passed-unexpected stats) d)) + (ert-test-failed (incf (ert--stats-failed-unexpected stats) d)) + (null) + (ert-test-aborted-with-non-local-exit))))) + ;; Adjust counters to remove the result that is currently in stats. + (update -1) + ;; Put new test and result into stats. + (setf (aref tests pos) test + (aref results pos) result) + (remhash (ert--stats-test-key old-test) map) + (setf (gethash (ert--stats-test-key test) map) pos) + ;; Adjust counters to match new result. + (update +1) + nil))) + +(defun ert--make-stats (tests selector) + "Create a new `ert--stats' object for running TESTS. + +SELECTOR is the selector that was used to select TESTS." + (setq tests (ert--coerce-to-vector tests)) + (let ((map (make-hash-table :size (length tests)))) + (loop for i from 0 + for test across tests + for key = (ert--stats-test-key test) do + (assert (not (gethash key map))) + (setf (gethash key map) i)) + (make-ert--stats :selector selector + :tests tests + :test-map map + :test-results (make-vector (length tests) nil) + :test-start-times (make-vector (length tests) nil) + :test-end-times (make-vector (length tests) nil)))) + +(defun ert-run-or-rerun-test (stats test listener) + ;; checkdoc-order: nil + "Run the single test TEST and record the result using STATS and LISTENER." + (let ((ert--current-run-stats stats) + (pos (ert--stats-test-pos stats test))) + (ert--stats-set-test-and-result stats pos test nil) + ;; Call listener after setting/before resetting + ;; (ert--stats-current-test stats); the listener might refresh the + ;; mode line display, and if the value is not set yet/any more + ;; during this refresh, the mode line will flicker unnecessarily. + (setf (ert--stats-current-test stats) test) + (funcall listener 'test-started stats test) + (setf (ert-test-most-recent-result test) nil) + (setf (aref (ert--stats-test-start-times stats) pos) (current-time)) + (unwind-protect + (ert-run-test test) + (setf (aref (ert--stats-test-end-times stats) pos) (current-time)) + (let ((result (ert-test-most-recent-result test))) + (ert--stats-set-test-and-result stats pos test result) + (funcall listener 'test-ended stats test result)) + (setf (ert--stats-current-test stats) nil)))) + +(defun ert-run-tests (selector listener) + "Run the tests specified by SELECTOR, sending progress updates to LISTENER." + (let* ((tests (ert-select-tests selector t)) + (stats (ert--make-stats tests selector))) + (setf (ert--stats-start-time stats) (current-time)) + (funcall listener 'run-started stats) + (let ((abortedp t)) + (unwind-protect + (let ((ert--current-run-stats stats)) + (force-mode-line-update) + (unwind-protect + (progn + (loop for test in tests do + (ert-run-or-rerun-test stats test listener)) + (setq abortedp nil)) + (setf (ert--stats-aborted-p stats) abortedp) + (setf (ert--stats-end-time stats) (current-time)) + (funcall listener 'run-ended stats abortedp))) + (force-mode-line-update)) + stats))) + +(defun ert--stats-test-pos (stats test) + ;; checkdoc-order: nil + "Return the position (index) of TEST in the run represented by STATS." + (gethash (ert--stats-test-key test) (ert--stats-test-map stats))) + + +;;; Formatting functions shared across UIs. + +(defun ert--format-time-iso8601 (time) + "Format TIME in the variant of ISO 8601 used for timestamps in ERT." + (format-time-string "%Y-%m-%d %T%z" time)) + +(defun ert-char-for-test-result (result expectedp) + "Return a character that represents the test result RESULT. + +EXPECTEDP specifies whether the result was expected." + (let ((s (etypecase result + (ert-test-passed ".P") + (ert-test-failed "fF") + (null "--") + (ert-test-aborted-with-non-local-exit "aA")))) + (elt s (if expectedp 0 1)))) + +(defun ert-string-for-test-result (result expectedp) + "Return a string that represents the test result RESULT. + +EXPECTEDP specifies whether the result was expected." + (let ((s (etypecase result + (ert-test-passed '("passed" "PASSED")) + (ert-test-failed '("failed" "FAILED")) + (null '("unknown" "UNKNOWN")) + (ert-test-aborted-with-non-local-exit '("aborted" "ABORTED"))))) + (elt s (if expectedp 0 1)))) + +(defun ert--pp-with-indentation-and-newline (object) + "Pretty-print OBJECT, indenting it to the current column of point. +Ensures a final newline is inserted." + (let ((begin (point))) + (pp object (current-buffer)) + (unless (bolp) (insert "\n")) + (save-excursion + (goto-char begin) + (indent-sexp)))) + +(defun ert--insert-infos (result) + "Insert `ert-info' infos from RESULT into current buffer. + +RESULT must be an `ert-test-result-with-condition'." + (check-type result ert-test-result-with-condition) + (dolist (info (ert-test-result-with-condition-infos result)) + (destructuring-bind (prefix . message) info + (let ((begin (point)) + (indentation (make-string (+ (length prefix) 4) ?\s)) + (end nil)) + (unwind-protect + (progn + (insert message "\n") + (setq end (copy-marker (point))) + (goto-char begin) + (insert " " prefix) + (forward-line 1) + (while (< (point) end) + (insert indentation) + (forward-line 1))) + (when end (set-marker end nil))))))) + + +;;; Running tests in batch mode. + +(defvar ert-batch-backtrace-right-margin 70 + "*The maximum line length for printing backtraces in `ert-run-tests-batch'.") + +;;;###autoload +(defun ert-run-tests-batch (&optional selector) + "Run the tests specified by SELECTOR, printing results to the terminal. + +SELECTOR works as described in `ert-select-tests', except if +SELECTOR is nil, in which case all tests rather than none will be +run; this makes the command line \"emacs -batch -l my-tests.el -f +ert-run-tests-batch-and-exit\" useful. + +Returns the stats object." + (unless selector (setq selector 't)) + (ert-run-tests + selector + (lambda (event-type &rest event-args) + (ecase event-type + (run-started + (destructuring-bind (stats) event-args + (message "Running %s tests (%s)" + (length (ert--stats-tests stats)) + (ert--format-time-iso8601 (ert--stats-start-time stats))))) + (run-ended + (destructuring-bind (stats abortedp) event-args + (let ((unexpected (ert-stats-completed-unexpected stats)) + (expected-failures (ert--stats-failed-expected stats))) + (message "\n%sRan %s tests, %s results as expected%s (%s)%s\n" + (if (not abortedp) + "" + "Aborted: ") + (ert-stats-total stats) + (ert-stats-completed-expected stats) + (if (zerop unexpected) + "" + (format ", %s unexpected" unexpected)) + (ert--format-time-iso8601 (ert--stats-end-time stats)) + (if (zerop expected-failures) + "" + (format "\n%s expected failures" expected-failures))) + (unless (zerop unexpected) + (message "%s unexpected results:" unexpected) + (loop for test across (ert--stats-tests stats) + for result = (ert-test-most-recent-result test) do + (when (not (ert-test-result-expected-p test result)) + (message "%9s %S" + (ert-string-for-test-result result nil) + (ert-test-name test)))) + (message "%s" ""))))) + (test-started + ) + (test-ended + (destructuring-bind (stats test result) event-args + (unless (ert-test-result-expected-p test result) + (etypecase result + (ert-test-passed + (message "Test %S passed unexpectedly" (ert-test-name test))) + (ert-test-result-with-condition + (message "Test %S backtrace:" (ert-test-name test)) + (with-temp-buffer + (ert--print-backtrace (ert-test-result-with-condition-backtrace + result)) + (goto-char (point-min)) + (while (not (eobp)) + (let ((start (point)) + (end (progn (end-of-line) (point)))) + (setq end (min end + (+ start ert-batch-backtrace-right-margin))) + (message "%s" (buffer-substring-no-properties + start end))) + (forward-line 1))) + (with-temp-buffer + (ert--insert-infos result) + (insert " ") + (let ((print-escape-newlines t) + (print-level 5) + (print-length 10)) + (let ((begin (point))) + (ert--pp-with-indentation-and-newline + (ert-test-result-with-condition-condition result)))) + (goto-char (1- (point-max))) + (assert (looking-at "\n")) + (delete-char 1) + (message "Test %S condition:" (ert-test-name test)) + (message "%s" (buffer-string)))) + (ert-test-aborted-with-non-local-exit + (message "Test %S aborted with non-local exit" + (ert-test-name test))))) + (let* ((max (prin1-to-string (length (ert--stats-tests stats)))) + (format-string (concat "%9s %" + (prin1-to-string (length max)) + "s/" max " %S"))) + (message format-string + (ert-string-for-test-result result + (ert-test-result-expected-p + test result)) + (1+ (ert--stats-test-pos stats test)) + (ert-test-name test))))))))) + +;;;###autoload +(defun ert-run-tests-batch-and-exit (&optional selector) + "Like `ert-run-tests-batch', but exits Emacs when done. + +The exit status will be 0 if all test results were as expected, 1 +on unexpected results, or 2 if the framework detected an error +outside of the tests (e.g. invalid SELECTOR or bug in the code +that runs the tests)." + (unwind-protect + (let ((stats (ert-run-tests-batch selector))) + (kill-emacs (if (zerop (ert-stats-completed-unexpected stats)) 0 1))) + (unwind-protect + (progn + (message "Error running tests") + (backtrace)) + (kill-emacs 2)))) + + +;;; Utility functions for load/unload actions. + +(defun ert--activate-font-lock-keywords () + "Activate font-lock keywords for some of ERT's symbols." + (font-lock-add-keywords + nil + '(("(\\(\\\\s *\\(\\sw+\\)?" + (1 font-lock-keyword-face nil t) + (2 font-lock-function-name-face nil t))))) + +(defun* ert--remove-from-list (list-var element &key key test) + "Remove ELEMENT from the value of LIST-VAR if present. + +This can be used as an inverse of `add-to-list'." + (unless key (setq key #'identity)) + (unless test (setq test #'equal)) + (setf (symbol-value list-var) + (ert--remove* element + (symbol-value list-var) + :key key + :test test))) + + +;;; Some basic interactive functions. + +(defun ert-read-test-name (prompt &optional default history + add-default-to-prompt) + "Read the name of a test and return it as a symbol. + +Prompt with PROMPT. If DEFAULT is a valid test name, use it as a +default. HISTORY is the history to use; see `completing-read'. +If ADD-DEFAULT-TO-PROMPT is non-nil, PROMPT will be modified to +include the default, if any. + +Signals an error if no test name was read." + (etypecase default + (string (let ((symbol (intern-soft default))) + (unless (and symbol (ert-test-boundp symbol)) + (setq default nil)))) + (symbol (setq default + (if (ert-test-boundp default) + (symbol-name default) + nil))) + (ert-test (setq default (ert-test-name default)))) + (when add-default-to-prompt + (setq prompt (if (null default) + (format "%s: " prompt) + (format "%s (default %s): " prompt default)))) + (let ((input (completing-read prompt obarray #'ert-test-boundp + t nil history default nil))) + ;; completing-read returns an empty string if default was nil and + ;; the user just hit enter. + (let ((sym (intern-soft input))) + (if (ert-test-boundp sym) + sym + (error "Input does not name a test"))))) + +(defun ert-read-test-name-at-point (prompt) + "Read the name of a test and return it as a symbol. +As a default, use the symbol at point, or the test at point if in +the ERT results buffer. Prompt with PROMPT, augmented with the +default (if any)." + (ert-read-test-name prompt (ert-test-at-point) nil t)) + +(defun ert-find-test-other-window (test-name) + "Find, in another window, the definition of TEST-NAME." + (interactive (list (ert-read-test-name-at-point "Find test definition: "))) + (find-function-do-it test-name 'ert-deftest 'switch-to-buffer-other-window)) + +(defun ert-delete-test (test-name) + "Make the test TEST-NAME unbound. + +Nothing more than an interactive interface to `ert-make-test-unbound'." + (interactive (list (ert-read-test-name-at-point "Delete test"))) + (ert-make-test-unbound test-name)) + +(defun ert-delete-all-tests () + "Make all symbols in `obarray' name no test." + (interactive) + (when (interactive-p) + (unless (y-or-n-p "Delete all tests? ") + (error "Aborted"))) + ;; We can't use `ert-select-tests' here since that gives us only + ;; test objects, and going from them back to the test name symbols + ;; can fail if the `ert-test' defstruct has been redefined. + (mapc #'ert-make-test-unbound (apropos-internal "" #'ert-test-boundp)) + t) + + +;;; Display of test progress and results. + +;; An entry in the results buffer ewoc. There is one entry per test. +(defstruct ert--ewoc-entry + (test (assert nil)) + ;; If the result of this test was expected, its ewoc entry is hidden + ;; initially. + (hidden-p (assert nil)) + ;; An ewoc entry may be collapsed to hide details such as the error + ;; condition. + ;; + ;; I'm not sure the ability to expand and collapse entries is still + ;; a useful feature. + (expanded-p t) + ;; By default, the ewoc entry presents the error condition with + ;; certain limits on how much to print (`print-level', + ;; `print-length'). The user can interactively switch to a set of + ;; higher limits. + (extended-printer-limits-p nil)) + +;; Variables local to the results buffer. + +;; The ewoc. +(defvar ert--results-ewoc) +;; The stats object. +(defvar ert--results-stats) +;; A string with one character per test. Each character represents +;; the result of the corresponding test. The string is displayed near +;; the top of the buffer and serves as a progress bar. +(defvar ert--results-progress-bar-string) +;; The position where the progress bar button begins. +(defvar ert--results-progress-bar-button-begin) +;; The test result listener that updates the buffer when tests are run. +(defvar ert--results-listener) + +(defun ert-insert-test-name-button (test-name) + "Insert a button that links to TEST-NAME." + (insert-text-button (format "%S" test-name) + :type 'ert--test-name-button + 'ert-test-name test-name)) + +(defun ert--results-format-expected-unexpected (expected unexpected) + "Return a string indicating EXPECTED expected results, UNEXPECTED unexpected." + (if (zerop unexpected) + (format "%s" expected) + (format "%s (%s unexpected)" (+ expected unexpected) unexpected))) + +(defun ert--results-update-ewoc-hf (ewoc stats) + "Update the header and footer of EWOC to show certain information from STATS. + +Also sets `ert--results-progress-bar-button-begin'." + (let ((run-count (ert-stats-completed stats)) + (results-buffer (current-buffer)) + ;; Need to save buffer-local value. + (font-lock font-lock-mode)) + (ewoc-set-hf + ewoc + ;; header + (with-temp-buffer + (insert "Selector: ") + (ert--insert-human-readable-selector (ert--stats-selector stats)) + (insert "\n") + (insert + (format (concat "Passed: %s\n" + "Failed: %s\n" + "Total: %s/%s\n\n") + (ert--results-format-expected-unexpected + (ert--stats-passed-expected stats) + (ert--stats-passed-unexpected stats)) + (ert--results-format-expected-unexpected + (ert--stats-failed-expected stats) + (ert--stats-failed-unexpected stats)) + run-count + (ert-stats-total stats))) + (insert + (format "Started at: %s\n" + (ert--format-time-iso8601 (ert--stats-start-time stats)))) + ;; FIXME: This is ugly. Need to properly define invariants of + ;; the `stats' data structure. + (let ((state (cond ((ert--stats-aborted-p stats) 'aborted) + ((ert--stats-current-test stats) 'running) + ((ert--stats-end-time stats) 'finished) + (t 'preparing)))) + (ecase state + (preparing + (insert "")) + (aborted + (cond ((ert--stats-current-test stats) + (insert "Aborted during test: ") + (ert-insert-test-name-button + (ert-test-name (ert--stats-current-test stats)))) + (t + (insert "Aborted.")))) + (running + (assert (ert--stats-current-test stats)) + (insert "Running test: ") + (ert-insert-test-name-button (ert-test-name + (ert--stats-current-test stats)))) + (finished + (assert (not (ert--stats-current-test stats))) + (insert "Finished."))) + (insert "\n") + (if (ert--stats-end-time stats) + (insert + (format "%s%s\n" + (if (ert--stats-aborted-p stats) + "Aborted at: " + "Finished at: ") + (ert--format-time-iso8601 (ert--stats-end-time stats)))) + (insert "\n")) + (insert "\n")) + (let ((progress-bar-string (with-current-buffer results-buffer + ert--results-progress-bar-string))) + (let ((progress-bar-button-begin + (insert-text-button progress-bar-string + :type 'ert--results-progress-bar-button + 'face (or (and font-lock + (ert-face-for-stats stats)) + 'button)))) + ;; The header gets copied verbatim to the results buffer, + ;; and all positions remain the same, so + ;; `progress-bar-button-begin' will be the right position + ;; even in the results buffer. + (with-current-buffer results-buffer + (set (make-local-variable 'ert--results-progress-bar-button-begin) + progress-bar-button-begin)))) + (insert "\n\n") + (buffer-string)) + ;; footer + ;; + ;; We actually want an empty footer, but that would trigger a bug + ;; in ewoc, sometimes clearing the entire buffer. (It's possible + ;; that this bug has been fixed since this has been tested; we + ;; should test it again.) + "\n"))) + + +(defvar ert-test-run-redisplay-interval-secs .1 + "How many seconds ERT should wait between redisplays while running tests. + +While running tests, ERT shows the current progress, and this variable +determines how frequently the progress display is updated.") + +(defun ert--results-update-stats-display (ewoc stats) + "Update EWOC and the mode line to show data from STATS." + ;; TODO(ohler): investigate using `make-progress-reporter'. + (ert--results-update-ewoc-hf ewoc stats) + (force-mode-line-update) + (redisplay t) + (setf (ert--stats-next-redisplay stats) + (+ (float-time) ert-test-run-redisplay-interval-secs))) + +(defun ert--results-update-stats-display-maybe (ewoc stats) + "Call `ert--results-update-stats-display' if not called recently. + +EWOC and STATS are arguments for `ert--results-update-stats-display'." + (when (>= (float-time) (ert--stats-next-redisplay stats)) + (ert--results-update-stats-display ewoc stats))) + +(defun ert--tests-running-mode-line-indicator () + "Return a string for the mode line that shows the test run progress." + (let* ((stats ert--current-run-stats) + (tests-total (ert-stats-total stats)) + (tests-completed (ert-stats-completed stats))) + (if (>= tests-completed tests-total) + (format " ERT(%s/%s,finished)" tests-completed tests-total) + (format " ERT(%s/%s):%s" + (1+ tests-completed) + tests-total + (if (null (ert--stats-current-test stats)) + "?" + (format "%S" + (ert-test-name (ert--stats-current-test stats)))))))) + +(defun ert--make-xrefs-region (begin end) + "Attach cross-references to function names between BEGIN and END. + +BEGIN and END specify a region in the current buffer." + (save-excursion + (save-restriction + (narrow-to-region begin (point)) + ;; Inhibit optimization in `debugger-make-xrefs' that would + ;; sometimes insert unrelated backtrace info into our buffer. + (let ((debugger-previous-backtrace nil)) + (debugger-make-xrefs))))) + +(defun ert--string-first-line (s) + "Return the first line of S, or S if it contains no newlines. + +The return value does not include the line terminator." + (substring s 0 (ert--string-position ?\n s))) + +(defun ert-face-for-test-result (expectedp) + "Return a face that shows whether a test result was expected or unexpected. + +If EXPECTEDP is nil, returns the face for unexpected results; if +non-nil, returns the face for expected results.." + (if expectedp 'ert-test-result-expected 'ert-test-result-unexpected)) + +(defun ert-face-for-stats (stats) + "Return a face that represents STATS." + (cond ((ert--stats-aborted-p stats) 'nil) + ((plusp (ert-stats-completed-unexpected stats)) + (ert-face-for-test-result nil)) + ((eql (ert-stats-completed-expected stats) (ert-stats-total stats)) + (ert-face-for-test-result t)) + (t 'nil))) + +(defun ert--print-test-for-ewoc (entry) + "The ewoc print function for ewoc test entries. ENTRY is the entry to print." + (let* ((test (ert--ewoc-entry-test entry)) + (stats ert--results-stats) + (result (let ((pos (ert--stats-test-pos stats test))) + (assert pos) + (aref (ert--stats-test-results stats) pos))) + (hiddenp (ert--ewoc-entry-hidden-p entry)) + (expandedp (ert--ewoc-entry-expanded-p entry)) + (extended-printer-limits-p (ert--ewoc-entry-extended-printer-limits-p + entry))) + (cond (hiddenp) + (t + (let ((expectedp (ert-test-result-expected-p test result))) + (insert-text-button (format "%c" (ert-char-for-test-result + result expectedp)) + :type 'ert--results-expand-collapse-button + 'face (or (and font-lock-mode + (ert-face-for-test-result + expectedp)) + 'button))) + (insert " ") + (ert-insert-test-name-button (ert-test-name test)) + (insert "\n") + (when (and expandedp (not (eql result 'nil))) + (when (ert-test-documentation test) + (insert " " + (propertize + (ert--string-first-line (ert-test-documentation test)) + 'font-lock-face 'font-lock-doc-face) + "\n")) + (etypecase result + (ert-test-passed + (if (ert-test-result-expected-p test result) + (insert " passed\n") + (insert " passed unexpectedly\n")) + (insert "")) + (ert-test-result-with-condition + (ert--insert-infos result) + (let ((print-escape-newlines t) + (print-level (if extended-printer-limits-p 12 6)) + (print-length (if extended-printer-limits-p 100 10))) + (insert " ") + (let ((begin (point))) + (ert--pp-with-indentation-and-newline + (ert-test-result-with-condition-condition result)) + (ert--make-xrefs-region begin (point))))) + (ert-test-aborted-with-non-local-exit + (insert " aborted\n"))) + (insert "\n"))))) + nil) + +(defun ert--results-font-lock-function (enabledp) + "Redraw the ERT results buffer after font-lock-mode was switched on or off. + +ENABLEDP is true if font-lock-mode is switched on, false +otherwise." + (ert--results-update-ewoc-hf ert--results-ewoc ert--results-stats) + (ewoc-refresh ert--results-ewoc) + (font-lock-default-function enabledp)) + +(defun ert--setup-results-buffer (stats listener buffer-name) + "Set up a test results buffer. + +STATS is the stats object; LISTENER is the results listener; +BUFFER-NAME, if non-nil, is the buffer name to use." + (unless buffer-name (setq buffer-name "*ert*")) + (let ((buffer (get-buffer-create buffer-name))) + (with-current-buffer buffer + (setq buffer-read-only t) + (let ((inhibit-read-only t)) + (buffer-disable-undo) + (erase-buffer) + (ert-results-mode) + ;; Erase buffer again in case switching out of the previous + ;; mode inserted anything. (This happens e.g. when switching + ;; from ert-results-mode to ert-results-mode when + ;; font-lock-mode turns itself off in change-major-mode-hook.) + (erase-buffer) + (set (make-local-variable 'font-lock-function) + 'ert--results-font-lock-function) + (let ((ewoc (ewoc-create 'ert--print-test-for-ewoc nil nil t))) + (set (make-local-variable 'ert--results-ewoc) ewoc) + (set (make-local-variable 'ert--results-stats) stats) + (set (make-local-variable 'ert--results-progress-bar-string) + (make-string (ert-stats-total stats) + (ert-char-for-test-result nil t))) + (set (make-local-variable 'ert--results-listener) listener) + (loop for test across (ert--stats-tests stats) do + (ewoc-enter-last ewoc + (make-ert--ewoc-entry :test test :hidden-p t))) + (ert--results-update-ewoc-hf ert--results-ewoc ert--results-stats) + (goto-char (1- (point-max))) + buffer))))) + + +(defvar ert--selector-history nil + "List of recent test selectors read from terminal.") + +;; Should OUTPUT-BUFFER-NAME and MESSAGE-FN really be arguments here? +;; They are needed only for our automated self-tests at the moment. +;; Or should there be some other mechanism? +;;;###autoload +(defun ert-run-tests-interactively (selector + &optional output-buffer-name message-fn) + "Run the tests specified by SELECTOR and display the results in a buffer. + +SELECTOR works as described in `ert-select-tests'. +OUTPUT-BUFFER-NAME and MESSAGE-FN should normally be nil; they +are used for automated self-tests and specify which buffer to use +and how to display message." + (interactive + (list (let ((default (if ert--selector-history + ;; Can't use `first' here as this form is + ;; not compiled, and `first' is not + ;; defined without cl. + (car ert--selector-history) + "t"))) + (read-from-minibuffer (if (null default) + "Run tests: " + (format "Run tests (default %s): " default)) + nil nil t 'ert--selector-history + default nil)) + nil)) + (unless message-fn (setq message-fn 'message)) + (lexical-let ((output-buffer-name output-buffer-name) + buffer + listener + (message-fn message-fn)) + (setq listener + (lambda (event-type &rest event-args) + (ecase event-type + (run-started + (destructuring-bind (stats) event-args + (setq buffer (ert--setup-results-buffer stats + listener + output-buffer-name)) + (pop-to-buffer buffer))) + (run-ended + (destructuring-bind (stats abortedp) event-args + (funcall message-fn + "%sRan %s tests, %s results were as expected%s" + (if (not abortedp) + "" + "Aborted: ") + (ert-stats-total stats) + (ert-stats-completed-expected stats) + (let ((unexpected + (ert-stats-completed-unexpected stats))) + (if (zerop unexpected) + "" + (format ", %s unexpected" unexpected)))) + (ert--results-update-stats-display (with-current-buffer buffer + ert--results-ewoc) + stats))) + (test-started + (destructuring-bind (stats test) event-args + (with-current-buffer buffer + (let* ((ewoc ert--results-ewoc) + (pos (ert--stats-test-pos stats test)) + (node (ewoc-nth ewoc pos))) + (assert node) + (setf (ert--ewoc-entry-test (ewoc-data node)) test) + (aset ert--results-progress-bar-string pos + (ert-char-for-test-result nil t)) + (ert--results-update-stats-display-maybe ewoc stats) + (ewoc-invalidate ewoc node))))) + (test-ended + (destructuring-bind (stats test result) event-args + (with-current-buffer buffer + (let* ((ewoc ert--results-ewoc) + (pos (ert--stats-test-pos stats test)) + (node (ewoc-nth ewoc pos))) + (when (ert--ewoc-entry-hidden-p (ewoc-data node)) + (setf (ert--ewoc-entry-hidden-p (ewoc-data node)) + (ert-test-result-expected-p test result))) + (aset ert--results-progress-bar-string pos + (ert-char-for-test-result result + (ert-test-result-expected-p + test result))) + (ert--results-update-stats-display-maybe ewoc stats) + (ewoc-invalidate ewoc node)))))))) + (ert-run-tests + selector + listener))) +;;;###autoload +(defalias 'ert 'ert-run-tests-interactively) + + +;;; Simple view mode for auxiliary information like stack traces or +;;; messages. Mainly binds "q" for quit. + +(define-derived-mode ert-simple-view-mode fundamental-mode "ERT-View" + "Major mode for viewing auxiliary information in ERT.") + +(loop for (key binding) in + '(("q" quit-window) + ) + do + (define-key ert-simple-view-mode-map key binding)) + + +;;; Commands and button actions for the results buffer. + +(define-derived-mode ert-results-mode fundamental-mode "ERT-Results" + "Major mode for viewing results of ERT test runs.") + +(loop for (key binding) in + '(;; Stuff that's not in the menu. + ("\t" forward-button) + ([backtab] backward-button) + ("j" ert-results-jump-between-summary-and-result) + ("q" quit-window) + ("L" ert-results-toggle-printer-limits-for-test-at-point) + ("n" ert-results-next-test) + ("p" ert-results-previous-test) + ;; Stuff that is in the menu. + ("R" ert-results-rerun-all-tests) + ("r" ert-results-rerun-test-at-point) + ("d" ert-results-rerun-test-at-point-debugging-errors) + ("." ert-results-find-test-at-point-other-window) + ("b" ert-results-pop-to-backtrace-for-test-at-point) + ("m" ert-results-pop-to-messages-for-test-at-point) + ("l" ert-results-pop-to-should-forms-for-test-at-point) + ("h" ert-results-describe-test-at-point) + ("D" ert-delete-test) + ("T" ert-results-pop-to-timings) + ) + do + (define-key ert-results-mode-map key binding)) + +(easy-menu-define ert-results-mode-menu ert-results-mode-map + "Menu for `ert-results-mode'." + '("ERT Results" + ["Re-run all tests" ert-results-rerun-all-tests] + "--" + ["Re-run test" ert-results-rerun-test-at-point] + ["Debug test" ert-results-rerun-test-at-point-debugging-errors] + ["Show test definition" ert-results-find-test-at-point-other-window] + "--" + ["Show backtrace" ert-results-pop-to-backtrace-for-test-at-point] + ["Show messages" ert-results-pop-to-messages-for-test-at-point] + ["Show `should' forms" ert-results-pop-to-should-forms-for-test-at-point] + ["Describe test" ert-results-describe-test-at-point] + "--" + ["Delete test" ert-delete-test] + "--" + ["Show execution time of each test" ert-results-pop-to-timings] + )) + +(define-button-type 'ert--results-progress-bar-button + 'action #'ert--results-progress-bar-button-action + 'help-echo "mouse-2, RET: Reveal test result") + +(define-button-type 'ert--test-name-button + 'action #'ert--test-name-button-action + 'help-echo "mouse-2, RET: Find test definition") + +(define-button-type 'ert--results-expand-collapse-button + 'action #'ert--results-expand-collapse-button-action + 'help-echo "mouse-2, RET: Expand/collapse test result") + +(defun ert--results-test-node-or-null-at-point () + "If point is on a valid ewoc node, return it; return nil otherwise. + +To be used in the ERT results buffer." + (let* ((ewoc ert--results-ewoc) + (node (ewoc-locate ewoc))) + ;; `ewoc-locate' will return an arbitrary node when point is on + ;; header or footer, or when all nodes are invisible. So we need + ;; to validate its return value here. + ;; + ;; Update: I'm seeing nil being returned in some cases now, + ;; perhaps this has been changed? + (if (and node + (>= (point) (ewoc-location node)) + (not (ert--ewoc-entry-hidden-p (ewoc-data node)))) + node + nil))) + +(defun ert--results-test-node-at-point () + "If point is on a valid ewoc node, return it; signal an error otherwise. + +To be used in the ERT results buffer." + (or (ert--results-test-node-or-null-at-point) + (error "No test at point"))) + +(defun ert-results-next-test () + "Move point to the next test. + +To be used in the ERT results buffer." + (interactive) + (ert--results-move (ewoc-locate ert--results-ewoc) 'ewoc-next + "No tests below")) + +(defun ert-results-previous-test () + "Move point to the previous test. + +To be used in the ERT results buffer." + (interactive) + (ert--results-move (ewoc-locate ert--results-ewoc) 'ewoc-prev + "No tests above")) + +(defun ert--results-move (node ewoc-fn error-message) + "Move point from NODE to the previous or next node. + +EWOC-FN specifies the direction and should be either `ewoc-prev' +or `ewoc-next'. If there are no more nodes in that direction, an +error is signalled with the message ERROR-MESSAGE." + (loop + (setq node (funcall ewoc-fn ert--results-ewoc node)) + (when (null node) + (error "%s" error-message)) + (unless (ert--ewoc-entry-hidden-p (ewoc-data node)) + (goto-char (ewoc-location node)) + (return)))) + +(defun ert--results-expand-collapse-button-action (button) + "Expand or collapse the test node BUTTON belongs to." + (let* ((ewoc ert--results-ewoc) + (node (save-excursion + (goto-char (ert--button-action-position)) + (ert--results-test-node-at-point))) + (entry (ewoc-data node))) + (setf (ert--ewoc-entry-expanded-p entry) + (not (ert--ewoc-entry-expanded-p entry))) + (ewoc-invalidate ewoc node))) + +(defun ert-results-find-test-at-point-other-window () + "Find the definition of the test at point in another window. + +To be used in the ERT results buffer." + (interactive) + (let ((name (ert-test-at-point))) + (unless name + (error "No test at point")) + (ert-find-test-other-window name))) + +(defun ert--test-name-button-action (button) + "Find the definition of the test BUTTON belongs to, in another window." + (let ((name (button-get button 'ert-test-name))) + (ert-find-test-other-window name))) + +(defun ert--ewoc-position (ewoc node) + ;; checkdoc-order: nil + "Return the position of NODE in EWOC, or nil if NODE is not in EWOC." + (loop for i from 0 + for node-here = (ewoc-nth ewoc 0) then (ewoc-next ewoc node-here) + do (when (eql node node-here) + (return i)) + finally (return nil))) + +(defun ert-results-jump-between-summary-and-result () + "Jump back and forth between the test run summary and individual test results. + +From an ewoc node, jumps to the character that represents the +same test in the progress bar, and vice versa. + +To be used in the ERT results buffer." + ;; Maybe this command isn't actually needed much, but if it is, it + ;; seems like an indication that the UI design is not optimal. If + ;; jumping back and forth between a summary at the top of the buffer + ;; and the error log in the remainder of the buffer is useful, then + ;; the summary apparently needs to be easily accessible from the + ;; error log, and perhaps it would be better to have it in a + ;; separate buffer to keep it visible. + (interactive) + (let ((ewoc ert--results-ewoc) + (progress-bar-begin ert--results-progress-bar-button-begin)) + (cond ((ert--results-test-node-or-null-at-point) + (let* ((node (ert--results-test-node-at-point)) + (pos (ert--ewoc-position ewoc node))) + (goto-char (+ progress-bar-begin pos)))) + ((and (<= progress-bar-begin (point)) + (< (point) (button-end (button-at progress-bar-begin)))) + (let* ((node (ewoc-nth ewoc (- (point) progress-bar-begin))) + (entry (ewoc-data node))) + (when (ert--ewoc-entry-hidden-p entry) + (setf (ert--ewoc-entry-hidden-p entry) nil) + (ewoc-invalidate ewoc node)) + (ewoc-goto-node ewoc node))) + (t + (goto-char progress-bar-begin))))) + +(defun ert-test-at-point () + "Return the name of the test at point as a symbol, or nil if none." + (or (and (eql major-mode 'ert-results-mode) + (let ((test (ert--results-test-at-point-no-redefinition))) + (and test (ert-test-name test)))) + (let* ((thing (thing-at-point 'symbol)) + (sym (intern-soft thing))) + (and (ert-test-boundp sym) + sym)))) + +(defun ert--results-test-at-point-no-redefinition () + "Return the test at point, or nil. + +To be used in the ERT results buffer." + (assert (eql major-mode 'ert-results-mode)) + (if (ert--results-test-node-or-null-at-point) + (let* ((node (ert--results-test-node-at-point)) + (test (ert--ewoc-entry-test (ewoc-data node)))) + test) + (let ((progress-bar-begin ert--results-progress-bar-button-begin)) + (when (and (<= progress-bar-begin (point)) + (< (point) (button-end (button-at progress-bar-begin)))) + (let* ((test-index (- (point) progress-bar-begin)) + (test (aref (ert--stats-tests ert--results-stats) + test-index))) + test))))) + +(defun ert--results-test-at-point-allow-redefinition () + "Look up the test at point, and check whether it has been redefined. + +To be used in the ERT results buffer. + +Returns a list of two elements: the test (or nil) and a symbol +specifying whether the test has been redefined. + +If a new test has been defined with the same name as the test at +point, replaces the test at point with the new test, and returns +the new test and the symbol `redefined'. + +If the test has been deleted, returns the old test and the symbol +`deleted'. + +If the test is still current, returns the test and the symbol nil. + +If there is no test at point, returns a list with two nils." + (let ((test (ert--results-test-at-point-no-redefinition))) + (cond ((null test) + `(nil nil)) + ((null (ert-test-name test)) + `(,test nil)) + (t + (let* ((name (ert-test-name test)) + (new-test (and (ert-test-boundp name) + (ert-get-test name)))) + (cond ((eql test new-test) + `(,test nil)) + ((null new-test) + `(,test deleted)) + (t + (ert--results-update-after-test-redefinition + (ert--stats-test-pos ert--results-stats test) + new-test) + `(,new-test redefined)))))))) + +(defun ert--results-update-after-test-redefinition (pos new-test) + "Update results buffer after the test at pos POS has been redefined. + +Also updates the stats object. NEW-TEST is the new test +definition." + (let* ((stats ert--results-stats) + (ewoc ert--results-ewoc) + (node (ewoc-nth ewoc pos)) + (entry (ewoc-data node))) + (ert--stats-set-test-and-result stats pos new-test nil) + (setf (ert--ewoc-entry-test entry) new-test + (aref ert--results-progress-bar-string pos) (ert-char-for-test-result + nil t)) + (ewoc-invalidate ewoc node)) + nil) + +(defun ert--button-action-position () + "The buffer position where the last button action was triggered." + (cond ((integerp last-command-event) + (point)) + ((eventp last-command-event) + (posn-point (event-start last-command-event))) + (t (assert nil)))) + +(defun ert--results-progress-bar-button-action (button) + "Jump to details for the test represented by the character clicked in BUTTON." + (goto-char (ert--button-action-position)) + (ert-results-jump-between-summary-and-result)) + +(defun ert-results-rerun-all-tests () + "Re-run all tests, using the same selector. + +To be used in the ERT results buffer." + (interactive) + (assert (eql major-mode 'ert-results-mode)) + (let ((selector (ert--stats-selector ert--results-stats))) + (ert-run-tests-interactively selector (buffer-name)))) + +(defun ert-results-rerun-test-at-point () + "Re-run the test at point. + +To be used in the ERT results buffer." + (interactive) + (destructuring-bind (test redefinition-state) + (ert--results-test-at-point-allow-redefinition) + (when (null test) + (error "No test at point")) + (let* ((stats ert--results-stats) + (progress-message (format "Running %stest %S" + (ecase redefinition-state + ((nil) "") + (redefined "new definition of ") + (deleted "deleted ")) + (ert-test-name test)))) + ;; Need to save and restore point manually here: When point is on + ;; the first visible ewoc entry while the header is updated, point + ;; moves to the top of the buffer. This is undesirable, and a + ;; simple `save-excursion' doesn't prevent it. + (let ((point (point))) + (unwind-protect + (unwind-protect + (progn + (message "%s..." progress-message) + (ert-run-or-rerun-test stats test + ert--results-listener)) + (ert--results-update-stats-display ert--results-ewoc stats) + (message "%s...%s" + progress-message + (let ((result (ert-test-most-recent-result test))) + (ert-string-for-test-result + result (ert-test-result-expected-p test result))))) + (goto-char point)))))) + +(defun ert-results-rerun-test-at-point-debugging-errors () + "Re-run the test at point with `ert-debug-on-error' bound to t. + +To be used in the ERT results buffer." + (interactive) + (let ((ert-debug-on-error t)) + (ert-results-rerun-test-at-point))) + +(defun ert-results-pop-to-backtrace-for-test-at-point () + "Display the backtrace for the test at point. + +To be used in the ERT results buffer." + (interactive) + (let* ((test (ert--results-test-at-point-no-redefinition)) + (stats ert--results-stats) + (pos (ert--stats-test-pos stats test)) + (result (aref (ert--stats-test-results stats) pos))) + (etypecase result + (ert-test-passed (error "Test passed, no backtrace available")) + (ert-test-result-with-condition + (let ((backtrace (ert-test-result-with-condition-backtrace result)) + (buffer (get-buffer-create "*ERT Backtrace*"))) + (pop-to-buffer buffer) + (setq buffer-read-only t) + (let ((inhibit-read-only t)) + (buffer-disable-undo) + (erase-buffer) + (ert-simple-view-mode) + ;; Use unibyte because `debugger-setup-buffer' also does so. + (set-buffer-multibyte nil) + (setq truncate-lines t) + (ert--print-backtrace backtrace) + (debugger-make-xrefs) + (goto-char (point-min)) + (insert "Backtrace for test `") + (ert-insert-test-name-button (ert-test-name test)) + (insert "':\n"))))))) + +(defun ert-results-pop-to-messages-for-test-at-point () + "Display the part of the *Messages* buffer generated during the test at point. + +To be used in the ERT results buffer." + (interactive) + (let* ((test (ert--results-test-at-point-no-redefinition)) + (stats ert--results-stats) + (pos (ert--stats-test-pos stats test)) + (result (aref (ert--stats-test-results stats) pos))) + (let ((buffer (get-buffer-create "*ERT Messages*"))) + (pop-to-buffer buffer) + (setq buffer-read-only t) + (let ((inhibit-read-only t)) + (buffer-disable-undo) + (erase-buffer) + (ert-simple-view-mode) + (insert (ert-test-result-messages result)) + (goto-char (point-min)) + (insert "Messages for test `") + (ert-insert-test-name-button (ert-test-name test)) + (insert "':\n"))))) + +(defun ert-results-pop-to-should-forms-for-test-at-point () + "Display the list of `should' forms executed during the test at point. + +To be used in the ERT results buffer." + (interactive) + (let* ((test (ert--results-test-at-point-no-redefinition)) + (stats ert--results-stats) + (pos (ert--stats-test-pos stats test)) + (result (aref (ert--stats-test-results stats) pos))) + (let ((buffer (get-buffer-create "*ERT list of should forms*"))) + (pop-to-buffer buffer) + (setq buffer-read-only t) + (let ((inhibit-read-only t)) + (buffer-disable-undo) + (erase-buffer) + (ert-simple-view-mode) + (if (null (ert-test-result-should-forms result)) + (insert "\n(No should forms during this test.)\n") + (loop for form-description in (ert-test-result-should-forms result) + for i from 1 do + (insert "\n") + (insert (format "%s: " i)) + (let ((begin (point))) + (ert--pp-with-indentation-and-newline form-description) + (ert--make-xrefs-region begin (point))))) + (goto-char (point-min)) + (insert "`should' forms executed during test `") + (ert-insert-test-name-button (ert-test-name test)) + (insert "':\n") + (insert "\n") + (insert (concat "(Values are shallow copies and may have " + "looked different during the test if they\n" + "have been modified destructively.)\n")) + (forward-line 1))))) + +(defun ert-results-toggle-printer-limits-for-test-at-point () + "Toggle how much of the condition to print for the test at point. + +To be used in the ERT results buffer." + (interactive) + (let* ((ewoc ert--results-ewoc) + (node (ert--results-test-node-at-point)) + (entry (ewoc-data node))) + (setf (ert--ewoc-entry-extended-printer-limits-p entry) + (not (ert--ewoc-entry-extended-printer-limits-p entry))) + (ewoc-invalidate ewoc node))) + +(defun ert-results-pop-to-timings () + "Display test timings for the last run. + +To be used in the ERT results buffer." + (interactive) + (let* ((stats ert--results-stats) + (start-times (ert--stats-test-start-times stats)) + (end-times (ert--stats-test-end-times stats)) + (buffer (get-buffer-create "*ERT timings*")) + (data (loop for test across (ert--stats-tests stats) + for start-time across (ert--stats-test-start-times stats) + for end-time across (ert--stats-test-end-times stats) + collect (list test + (float-time (subtract-time end-time + start-time)))))) + (setq data (sort data (lambda (a b) + (> (second a) (second b))))) + (pop-to-buffer buffer) + (setq buffer-read-only t) + (let ((inhibit-read-only t)) + (buffer-disable-undo) + (erase-buffer) + (ert-simple-view-mode) + (if (null data) + (insert "(No data)\n") + (insert (format "%-3s %8s %8s\n" "" "time" "cumul")) + (loop for (test time) in data + for cumul-time = time then (+ cumul-time time) + for i from 1 do + (let ((begin (point))) + (insert (format "%3s: %8.3f %8.3f " i time cumul-time)) + (ert-insert-test-name-button (ert-test-name test)) + (insert "\n")))) + (goto-char (point-min)) + (insert "Tests by run time (seconds):\n\n") + (forward-line 1)))) + +;;;###autoload +(defun ert-describe-test (test-or-test-name) + "Display the documentation for TEST-OR-TEST-NAME (a symbol or ert-test)." + (interactive (list (ert-read-test-name-at-point "Describe test"))) + (when (< emacs-major-version 24) + (error "Requires Emacs 24")) + (let (test-name + test-definition) + (etypecase test-or-test-name + (symbol (setq test-name test-or-test-name + test-definition (ert-get-test test-or-test-name))) + (ert-test (setq test-name (ert-test-name test-or-test-name) + test-definition test-or-test-name))) + (help-setup-xref (list #'ert-describe-test test-or-test-name) + (called-interactively-p 'interactive)) + (save-excursion + (with-help-window (help-buffer) + (with-current-buffer (help-buffer) + (insert (if test-name (format "%S" test-name) "")) + (insert " is a test") + (let ((file-name (and test-name + (symbol-file test-name 'ert-deftest)))) + (when file-name + (insert " defined in `" (file-name-nondirectory file-name) "'") + (save-excursion + (re-search-backward "`\\([^`']+\\)'" nil t) + (help-xref-button 1 'help-function-def test-name file-name))) + (insert ".") + (fill-region-as-paragraph (point-min) (point)) + (insert "\n\n") + (unless (and (ert-test-boundp test-name) + (eql (ert-get-test test-name) test-definition)) + (let ((begin (point))) + (insert "Note: This test has been redefined or deleted, " + "this documentation refers to an old definition.") + (fill-region-as-paragraph begin (point))) + (insert "\n\n")) + (insert (or (ert-test-documentation test-definition) + "It is not documented.") + "\n"))))))) + +(defun ert-results-describe-test-at-point () + "Display the documentation of the test at point. + +To be used in the ERT results buffer." + (interactive) + (ert-describe-test (ert--results-test-at-point-no-redefinition))) + + +;;; Actions on load/unload. + +(add-to-list 'find-function-regexp-alist '(ert-deftest . ert--find-test-regexp)) +(add-to-list 'minor-mode-alist '(ert--current-run-stats + (:eval + (ert--tests-running-mode-line-indicator)))) +(add-to-list 'emacs-lisp-mode-hook 'ert--activate-font-lock-keywords) + +(defun ert--unload-function () + "Unload function to undo the side-effects of loading ert.el." + (ert--remove-from-list 'find-function-regexp-alist 'ert-deftest :key #'car) + (ert--remove-from-list 'minor-mode-alist 'ert--current-run-stats :key #'car) + (ert--remove-from-list 'emacs-lisp-mode-hook + 'ert--activate-font-lock-keywords) + nil) + +(defvar ert-unload-hook '()) +(add-hook 'ert-unload-hook 'ert--unload-function) + + +(provide 'ert) + +;;; ert.el ends here diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/lib/hyperspec.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/lib/hyperspec.el new file mode 100644 index 0000000..45c3328 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/lib/hyperspec.el @@ -0,0 +1,2511 @@ +;;; hyperspec.el --- Browse documentation from the Common Lisp HyperSpec + +;; Copyright 1997 Naggum Software + +;; Author: Erik Naggum +;; Keywords: lisp + +;; This file is not part of GNU Emacs, but distributed under the same +;; conditions as GNU Emacs, and is useless without GNU Emacs. + +;; GNU Emacs is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; Kent Pitman and Xanalys Inc. have made the text of American National +;; Standard for Information Technology -- Programming Language -- Common +;; Lisp, ANSI X3.226-1994 available on the WWW, in the form of the Common +;; Lisp HyperSpec. This package makes it convenient to peruse this +;; documentation from within Emacs. + +;;; Code: + +(require 'cl-lib nil t) +(require 'cl-lib "lib/cl-lib") +(require 'browse-url) ;you need the Emacs 20 version +(require 'thingatpt) + +(defvar common-lisp-hyperspec-root + "http://www.lispworks.com/reference/HyperSpec/" + "The root of the Common Lisp HyperSpec URL. +If you copy the HyperSpec to your local system, set this variable to +something like \"file://usr/local/doc/HyperSpec/\".") + +;;; Added variable for CLHS symbol table. See details below. +;;; +;;; 20011201 Edi Weitz + +(defvar common-lisp-hyperspec-symbol-table nil + "The HyperSpec symbol table file. +If you copy the HyperSpec to your local system, set this variable to +the location of the symbol table which is usually \"Map_Sym.txt\" +or \"Symbol-Table.text\".") + +(defvar common-lisp-hyperspec-history nil + "History of symbols looked up in the Common Lisp HyperSpec.") + +(defvar common-lisp-hyperspec--symbols (make-hash-table :test 'equal) + "Map a symbol name to its list of relative URLs.") + +;; Lookup NAME in 'common-lisp-hyperspec--symbols´ +(defun common-lisp-hyperspec--find (name) + "Get the relative url of a Common Lisp symbol NAME." + (gethash name common-lisp-hyperspec--symbols)) + +(defun common-lisp-hyperspec--insert (name relative-url) + "Insert CL symbol NAME and RELATIVE-URL into master table." + (cl-pushnew relative-url + (gethash name common-lisp-hyperspec--symbols) + :test #'equal)) + +(defun common-lisp-hyperspec--strip-cl-package (name) + (if (string-match "^\\([^:]*\\)::?\\([^:]*\\)$" name) + (let ((package-name (match-string 1 name)) + (symbol-name (match-string 2 name))) + (if (member (downcase package-name) + '("cl" "common-lisp")) + symbol-name + name)) + name)) + +;; Choose the symbol at point or read symbol-name from the minibuffer. +(defun common-lisp-hyperspec-read-symbol-name (&optional symbol-at-point) + (let* ((symbol-at-point (or symbol-at-point (thing-at-point 'symbol))) + (stripped-symbol (and symbol-at-point + (common-lisp-hyperspec--strip-cl-package + (downcase symbol-at-point))))) + (cond ((and stripped-symbol + (common-lisp-hyperspec--find stripped-symbol)) + stripped-symbol) + (t + (completing-read "Look up symbol in Common Lisp HyperSpec: " + common-lisp-hyperspec--symbols nil t + stripped-symbol + 'common-lisp-hyperspec-history))))) + +;; FIXME: is the (sleep-for 1.5) a actually needed? +(defun common-lisp-hyperspec (symbol-name) + "View the documentation on SYMBOL-NAME from the Common Lisp HyperSpec. +If SYMBOL-NAME has more than one definition, all of them are displayed with +your favorite browser in sequence. The browser should have a \"back\" +function to view the separate definitions. + +The Common Lisp HyperSpec is the full ANSI Standard Common Lisp, provided +by Kent Pitman and Xanalys Inc. By default, the Xanalys Web site is +visited to retrieve the information. Xanalys Inc. allows you to transfer +the entire Common Lisp HyperSpec to your own site under certain conditions. +Visit http://www.lispworks.com/reference/HyperSpec/ for more information. +If you copy the HyperSpec to another location, customize the variable +`common-lisp-hyperspec-root' to point to that location." + (interactive (list (common-lisp-hyperspec-read-symbol-name))) + (let ((name (common-lisp-hyperspec--strip-cl-package + (downcase symbol-name)))) + (cl-maplist (lambda (entry) + (browse-url (concat common-lisp-hyperspec-root "Body/" + (car entry))) + (when (cdr entry) + (sleep-for 1.5))) + (or (common-lisp-hyperspec--find name) + (error "The symbol `%s' is not defined in Common Lisp" + symbol-name))))) + +;;; Added dynamic lookup of symbol in CLHS symbol table +;;; +;;; 20011202 Edi Weitz + +;;; Replaced symbol table for v 4.0 with the one for v 6.0 +;;; (which is now online at Xanalys' site) +;;; +;;; 20020213 Edi Weitz + +(defun common-lisp-hyperspec--get-one-line () + (prog1 + (cl-delete ?\n (thing-at-point 'line)) + (forward-line))) + +(defun common-lisp-hyperspec--parse-map-file (file) + (with-current-buffer (find-file-noselect file) + (goto-char (point-min)) + (let ((result '())) + (while (< (point) (point-max)) + (let* ((symbol-name (downcase (common-lisp-hyperspec--get-one-line))) + (relative-url (common-lisp-hyperspec--get-one-line)) + (file (file-name-nondirectory relative-url))) + (push (list symbol-name file) + result))) + (reverse result)))) + +(mapc (lambda (entry) + (common-lisp-hyperspec--insert (car entry) (cadr entry))) + (if common-lisp-hyperspec-symbol-table + (common-lisp-hyperspec--parse-map-file + common-lisp-hyperspec-symbol-table) + '(("&allow-other-keys" "03_da.htm") + ("&aux" "03_da.htm") + ("&body" "03_dd.htm") + ("&environment" "03_dd.htm") + ("&key" "03_da.htm") + ("&optional" "03_da.htm") + ("&rest" "03_da.htm") + ("&whole" "03_dd.htm") + ("*" "a_st.htm") + ("**" "v__stst_.htm") + ("***" "v__stst_.htm") + ("*break-on-signals*" "v_break_.htm") + ("*compile-file-pathname*" "v_cmp_fi.htm") + ("*compile-file-truename*" "v_cmp_fi.htm") + ("*compile-print*" "v_cmp_pr.htm") + ("*compile-verbose*" "v_cmp_pr.htm") + ("*debug-io*" "v_debug_.htm") + ("*debugger-hook*" "v_debugg.htm") + ("*default-pathname-defaults*" "v_defaul.htm") + ("*error-output*" "v_debug_.htm") + ("*features*" "v_featur.htm") + ("*gensym-counter*" "v_gensym.htm") + ("*load-pathname*" "v_ld_pns.htm") + ("*load-print*" "v_ld_prs.htm") + ("*load-truename*" "v_ld_pns.htm") + ("*load-verbose*" "v_ld_prs.htm") + ("*macroexpand-hook*" "v_mexp_h.htm") + ("*modules*" "v_module.htm") + ("*package*" "v_pkg.htm") + ("*print-array*" "v_pr_ar.htm") + ("*print-base*" "v_pr_bas.htm") + ("*print-case*" "v_pr_cas.htm") + ("*print-circle*" "v_pr_cir.htm") + ("*print-escape*" "v_pr_esc.htm") + ("*print-gensym*" "v_pr_gen.htm") + ("*print-length*" "v_pr_lev.htm") + ("*print-level*" "v_pr_lev.htm") + ("*print-lines*" "v_pr_lin.htm") + ("*print-miser-width*" "v_pr_mis.htm") + ("*print-pprint-dispatch*" "v_pr_ppr.htm") + ("*print-pretty*" "v_pr_pre.htm") + ("*print-radix*" "v_pr_bas.htm") + ("*print-readably*" "v_pr_rda.htm") + ("*print-right-margin*" "v_pr_rig.htm") + ("*query-io*" "v_debug_.htm") + ("*random-state*" "v_rnd_st.htm") + ("*read-base*" "v_rd_bas.htm") + ("*read-default-float-format*" "v_rd_def.htm") + ("*read-eval*" "v_rd_eva.htm") + ("*read-suppress*" "v_rd_sup.htm") + ("*readtable*" "v_rdtabl.htm") + ("*standard-input*" "v_debug_.htm") + ("*standard-output*" "v_debug_.htm") + ("*terminal-io*" "v_termin.htm") + ("*trace-output*" "v_debug_.htm") + ("+" "a_pl.htm") + ("++" "v_pl_plp.htm") + ("+++" "v_pl_plp.htm") + ("-" "a__.htm") + ("/" "a_sl.htm") + ("//" "v_sl_sls.htm") + ("///" "v_sl_sls.htm") + ("/=" "f_eq_sle.htm") + ("1+" "f_1pl_1_.htm") + ("1-" "f_1pl_1_.htm") + ("<" "f_eq_sle.htm") + ("<=" "f_eq_sle.htm") + ("=" "f_eq_sle.htm") + (">" "f_eq_sle.htm") + (">=" "f_eq_sle.htm") + ("abort" "a_abort.htm") + ("abs" "f_abs.htm") + ("acons" "f_acons.htm") + ("acos" "f_asin_.htm") + ("acosh" "f_sinh_.htm") + ("add-method" "f_add_me.htm") + ("adjoin" "f_adjoin.htm") + ("adjust-array" "f_adjust.htm") + ("adjustable-array-p" "f_adju_1.htm") + ("allocate-instance" "f_alloca.htm") + ("alpha-char-p" "f_alpha_.htm") + ("alphanumericp" "f_alphan.htm") + ("and" "a_and.htm") + ("append" "f_append.htm") + ("apply" "f_apply.htm") + ("apropos" "f_apropo.htm") + ("apropos-list" "f_apropo.htm") + ("aref" "f_aref.htm") + ("arithmetic-error" "e_arithm.htm") + ("arithmetic-error-operands" "f_arithm.htm") + ("arithmetic-error-operation" "f_arithm.htm") + ("array" "t_array.htm") + ("array-dimension" "f_ar_dim.htm") + ("array-dimension-limit" "v_ar_dim.htm") + ("array-dimensions" "f_ar_d_1.htm") + ("array-displacement" "f_ar_dis.htm") + ("array-element-type" "f_ar_ele.htm") + ("array-has-fill-pointer-p" "f_ar_has.htm") + ("array-in-bounds-p" "f_ar_in_.htm") + ("array-rank" "f_ar_ran.htm") + ("array-rank-limit" "v_ar_ran.htm") + ("array-row-major-index" "f_ar_row.htm") + ("array-total-size" "f_ar_tot.htm") + ("array-total-size-limit" "v_ar_tot.htm") + ("arrayp" "f_arrayp.htm") + ("ash" "f_ash.htm") + ("asin" "f_asin_.htm") + ("asinh" "f_sinh_.htm") + ("assert" "m_assert.htm") + ("assoc" "f_assocc.htm") + ("assoc-if" "f_assocc.htm") + ("assoc-if-not" "f_assocc.htm") + ("atan" "f_asin_.htm") + ("atanh" "f_sinh_.htm") + ("atom" "a_atom.htm") + ("base-char" "t_base_c.htm") + ("base-string" "t_base_s.htm") + ("bignum" "t_bignum.htm") + ("bit" "a_bit.htm") + ("bit-and" "f_bt_and.htm") + ("bit-andc1" "f_bt_and.htm") + ("bit-andc2" "f_bt_and.htm") + ("bit-eqv" "f_bt_and.htm") + ("bit-ior" "f_bt_and.htm") + ("bit-nand" "f_bt_and.htm") + ("bit-nor" "f_bt_and.htm") + ("bit-not" "f_bt_and.htm") + ("bit-orc1" "f_bt_and.htm") + ("bit-orc2" "f_bt_and.htm") + ("bit-vector" "t_bt_vec.htm") + ("bit-vector-p" "f_bt_vec.htm") + ("bit-xor" "f_bt_and.htm") + ("block" "s_block.htm") + ("boole" "f_boole.htm") + ("boole-1" "v_b_1_b.htm") + ("boole-2" "v_b_1_b.htm") + ("boole-and" "v_b_1_b.htm") + ("boole-andc1" "v_b_1_b.htm") + ("boole-andc2" "v_b_1_b.htm") + ("boole-c1" "v_b_1_b.htm") + ("boole-c2" "v_b_1_b.htm") + ("boole-clr" "v_b_1_b.htm") + ("boole-eqv" "v_b_1_b.htm") + ("boole-ior" "v_b_1_b.htm") + ("boole-nand" "v_b_1_b.htm") + ("boole-nor" "v_b_1_b.htm") + ("boole-orc1" "v_b_1_b.htm") + ("boole-orc2" "v_b_1_b.htm") + ("boole-set" "v_b_1_b.htm") + ("boole-xor" "v_b_1_b.htm") + ("boolean" "t_ban.htm") + ("both-case-p" "f_upper_.htm") + ("boundp" "f_boundp.htm") + ("break" "f_break.htm") + ("broadcast-stream" "t_broadc.htm") + ("broadcast-stream-streams" "f_broadc.htm") + ("built-in-class" "t_built_.htm") + ("butlast" "f_butlas.htm") + ("byte" "f_by_by.htm") + ("byte-position" "f_by_by.htm") + ("byte-size" "f_by_by.htm") + ("caaaar" "f_car_c.htm") + ("caaadr" "f_car_c.htm") + ("caaar" "f_car_c.htm") + ("caadar" "f_car_c.htm") + ("caaddr" "f_car_c.htm") + ("caadr" "f_car_c.htm") + ("caar" "f_car_c.htm") + ("cadaar" "f_car_c.htm") + ("cadadr" "f_car_c.htm") + ("cadar" "f_car_c.htm") + ("caddar" "f_car_c.htm") + ("cadddr" "f_car_c.htm") + ("caddr" "f_car_c.htm") + ("cadr" "f_car_c.htm") + ("call-arguments-limit" "v_call_a.htm") + ("call-method" "m_call_m.htm") + ("call-next-method" "f_call_n.htm") + ("car" "f_car_c.htm") + ("case" "m_case_.htm") + ("catch" "s_catch.htm") + ("ccase" "m_case_.htm") + ("cdaaar" "f_car_c.htm") + ("cdaadr" "f_car_c.htm") + ("cdaar" "f_car_c.htm") + ("cdadar" "f_car_c.htm") + ("cdaddr" "f_car_c.htm") + ("cdadr" "f_car_c.htm") + ("cdar" "f_car_c.htm") + ("cddaar" "f_car_c.htm") + ("cddadr" "f_car_c.htm") + ("cddar" "f_car_c.htm") + ("cdddar" "f_car_c.htm") + ("cddddr" "f_car_c.htm") + ("cdddr" "f_car_c.htm") + ("cddr" "f_car_c.htm") + ("cdr" "f_car_c.htm") + ("ceiling" "f_floorc.htm") + ("cell-error" "e_cell_e.htm") + ("cell-error-name" "f_cell_e.htm") + ("cerror" "f_cerror.htm") + ("change-class" "f_chg_cl.htm") + ("char" "f_char_.htm") + ("char-code" "f_char_c.htm") + ("char-code-limit" "v_char_c.htm") + ("char-downcase" "f_char_u.htm") + ("char-equal" "f_chareq.htm") + ("char-greaterp" "f_chareq.htm") + ("char-int" "f_char_i.htm") + ("char-lessp" "f_chareq.htm") + ("char-name" "f_char_n.htm") + ("char-not-equal" "f_chareq.htm") + ("char-not-greaterp" "f_chareq.htm") + ("char-not-lessp" "f_chareq.htm") + ("char-upcase" "f_char_u.htm") + ("char/=" "f_chareq.htm") + ("char<" "f_chareq.htm") + ("char<=" "f_chareq.htm") + ("char=" "f_chareq.htm") + ("char>" "f_chareq.htm") + ("char>=" "f_chareq.htm") + ("character" "a_ch.htm") + ("characterp" "f_chp.htm") + ("check-type" "m_check_.htm") + ("cis" "f_cis.htm") + ("class" "t_class.htm") + ("class-name" "f_class_.htm") + ("class-of" "f_clas_1.htm") + ("clear-input" "f_clear_.htm") + ("clear-output" "f_finish.htm") + ("close" "f_close.htm") + ("clrhash" "f_clrhas.htm") + ("code-char" "f_code_c.htm") + ("coerce" "f_coerce.htm") + ("compilation-speed" "d_optimi.htm") + ("compile" "f_cmp.htm") + ("compile-file" "f_cmp_fi.htm") + ("compile-file-pathname" "f_cmp__1.htm") + ("compiled-function" "t_cmpd_f.htm") + ("compiled-function-p" "f_cmpd_f.htm") + ("compiler-macro" "f_docume.htm") + ("compiler-macro-function" "f_cmp_ma.htm") + ("complement" "f_comple.htm") + ("complex" "a_comple.htm") + ("complexp" "f_comp_3.htm") + ("compute-applicable-methods" "f_comput.htm") + ("compute-restarts" "f_comp_1.htm") + ("concatenate" "f_concat.htm") + ("concatenated-stream" "t_concat.htm") + ("concatenated-stream-streams" "f_conc_1.htm") + ("cond" "m_cond.htm") + ("condition" "e_cnd.htm") + ("conjugate" "f_conjug.htm") + ("cons" "a_cons.htm") + ("consp" "f_consp.htm") + ("constantly" "f_cons_1.htm") + ("constantp" "f_consta.htm") + ("continue" "a_contin.htm") + ("control-error" "e_contro.htm") + ("copy-alist" "f_cp_ali.htm") + ("copy-list" "f_cp_lis.htm") + ("copy-pprint-dispatch" "f_cp_ppr.htm") + ("copy-readtable" "f_cp_rdt.htm") + ("copy-seq" "f_cp_seq.htm") + ("copy-structure" "f_cp_stu.htm") + ("copy-symbol" "f_cp_sym.htm") + ("copy-tree" "f_cp_tre.htm") + ("cos" "f_sin_c.htm") + ("cosh" "f_sinh_.htm") + ("count" "f_countc.htm") + ("count-if" "f_countc.htm") + ("count-if-not" "f_countc.htm") + ("ctypecase" "m_tpcase.htm") + ("debug" "d_optimi.htm") + ("decf" "m_incf_.htm") + ("declaim" "m_declai.htm") + ("declaration" "d_declar.htm") + ("declare" "s_declar.htm") + ("decode-float" "f_dec_fl.htm") + ("decode-universal-time" "f_dec_un.htm") + ("defclass" "m_defcla.htm") + ("defconstant" "m_defcon.htm") + ("defgeneric" "m_defgen.htm") + ("define-compiler-macro" "m_define.htm") + ("define-condition" "m_defi_5.htm") + ("define-method-combination" "m_defi_4.htm") + ("define-modify-macro" "m_defi_2.htm") + ("define-setf-expander" "m_defi_3.htm") + ("define-symbol-macro" "m_defi_1.htm") + ("defmacro" "m_defmac.htm") + ("defmethod" "m_defmet.htm") + ("defpackage" "m_defpkg.htm") + ("defparameter" "m_defpar.htm") + ("defsetf" "m_defset.htm") + ("defstruct" "m_defstr.htm") + ("deftype" "m_deftp.htm") + ("defun" "m_defun.htm") + ("defvar" "m_defpar.htm") + ("delete" "f_rm_rm.htm") + ("delete-duplicates" "f_rm_dup.htm") + ("delete-file" "f_del_fi.htm") + ("delete-if" "f_rm_rm.htm") + ("delete-if-not" "f_rm_rm.htm") + ("delete-package" "f_del_pk.htm") + ("denominator" "f_numera.htm") + ("deposit-field" "f_deposi.htm") + ("describe" "f_descri.htm") + ("describe-object" "f_desc_1.htm") + ("destructuring-bind" "m_destru.htm") + ("digit-char" "f_digit_.htm") + ("digit-char-p" "f_digi_1.htm") + ("directory" "f_dir.htm") + ("directory-namestring" "f_namest.htm") + ("disassemble" "f_disass.htm") + ("division-by-zero" "e_divisi.htm") + ("do" "m_do_do.htm") + ("do*" "m_do_do.htm") + ("do-all-symbols" "m_do_sym.htm") + ("do-external-symbols" "m_do_sym.htm") + ("do-symbols" "m_do_sym.htm") + ("documentation" "f_docume.htm") + ("dolist" "m_dolist.htm") + ("dotimes" "m_dotime.htm") + ("double-float" "t_short_.htm") + ("double-float-epsilon" "v_short_.htm") + ("double-float-negative-epsilon" "v_short_.htm") + ("dpb" "f_dpb.htm") + ("dribble" "f_dribbl.htm") + ("dynamic-extent" "d_dynami.htm") + ("ecase" "m_case_.htm") + ("echo-stream" "t_echo_s.htm") + ("echo-stream-input-stream" "f_echo_s.htm") + ("echo-stream-output-stream" "f_echo_s.htm") + ("ed" "f_ed.htm") + ("eighth" "f_firstc.htm") + ("elt" "f_elt.htm") + ("encode-universal-time" "f_encode.htm") + ("end-of-file" "e_end_of.htm") + ("endp" "f_endp.htm") + ("enough-namestring" "f_namest.htm") + ("ensure-directories-exist" "f_ensu_1.htm") + ("ensure-generic-function" "f_ensure.htm") + ("eq" "f_eq.htm") + ("eql" "a_eql.htm") + ("equal" "f_equal.htm") + ("equalp" "f_equalp.htm") + ("error" "a_error.htm") + ("etypecase" "m_tpcase.htm") + ("eval" "f_eval.htm") + ("eval-when" "s_eval_w.htm") + ("evenp" "f_evenpc.htm") + ("every" "f_everyc.htm") + ("exp" "f_exp_e.htm") + ("export" "f_export.htm") + ("expt" "f_exp_e.htm") + ("extended-char" "t_extend.htm") + ("fboundp" "f_fbound.htm") + ("fceiling" "f_floorc.htm") + ("fdefinition" "f_fdefin.htm") + ("ffloor" "f_floorc.htm") + ("fifth" "f_firstc.htm") + ("file-author" "f_file_a.htm") + ("file-error" "e_file_e.htm") + ("file-error-pathname" "f_file_e.htm") + ("file-length" "f_file_l.htm") + ("file-namestring" "f_namest.htm") + ("file-position" "f_file_p.htm") + ("file-stream" "t_file_s.htm") + ("file-string-length" "f_file_s.htm") + ("file-write-date" "f_file_w.htm") + ("fill" "f_fill.htm") + ("fill-pointer" "f_fill_p.htm") + ("find" "f_find_.htm") + ("find-all-symbols" "f_find_a.htm") + ("find-class" "f_find_c.htm") + ("find-if" "f_find_.htm") + ("find-if-not" "f_find_.htm") + ("find-method" "f_find_m.htm") + ("find-package" "f_find_p.htm") + ("find-restart" "f_find_r.htm") + ("find-symbol" "f_find_s.htm") + ("finish-output" "f_finish.htm") + ("first" "f_firstc.htm") + ("fixnum" "t_fixnum.htm") + ("flet" "s_flet_.htm") + ("float" "a_float.htm") + ("float-digits" "f_dec_fl.htm") + ("float-precision" "f_dec_fl.htm") + ("float-radix" "f_dec_fl.htm") + ("float-sign" "f_dec_fl.htm") + ("floating-point-inexact" "e_floa_1.htm") + ("floating-point-invalid-operation" "e_floati.htm") + ("floating-point-overflow" "e_floa_2.htm") + ("floating-point-underflow" "e_floa_3.htm") + ("floatp" "f_floatp.htm") + ("floor" "f_floorc.htm") + ("fmakunbound" "f_fmakun.htm") + ("force-output" "f_finish.htm") + ("format" "f_format.htm") + ("formatter" "m_format.htm") + ("fourth" "f_firstc.htm") + ("fresh-line" "f_terpri.htm") + ("fround" "f_floorc.htm") + ("ftruncate" "f_floorc.htm") + ("ftype" "d_ftype.htm") + ("funcall" "f_funcal.htm") + ("function" "a_fn.htm") + ("function-keywords" "f_fn_kwd.htm") + ("function-lambda-expression" "f_fn_lam.htm") + ("functionp" "f_fnp.htm") + ("gcd" "f_gcd.htm") + ("generic-function" "t_generi.htm") + ("gensym" "f_gensym.htm") + ("gentemp" "f_gentem.htm") + ("get" "f_get.htm") + ("get-decoded-time" "f_get_un.htm") + ("get-dispatch-macro-character" "f_set__1.htm") + ("get-internal-real-time" "f_get_in.htm") + ("get-internal-run-time" "f_get__1.htm") + ("get-macro-character" "f_set_ma.htm") + ("get-output-stream-string" "f_get_ou.htm") + ("get-properties" "f_get_pr.htm") + ("get-setf-expansion" "f_get_se.htm") + ("get-universal-time" "f_get_un.htm") + ("getf" "f_getf.htm") + ("gethash" "f_gethas.htm") + ("go" "s_go.htm") + ("graphic-char-p" "f_graphi.htm") + ("handler-bind" "m_handle.htm") + ("handler-case" "m_hand_1.htm") + ("hash-table" "t_hash_t.htm") + ("hash-table-count" "f_hash_1.htm") + ("hash-table-p" "f_hash_t.htm") + ("hash-table-rehash-size" "f_hash_2.htm") + ("hash-table-rehash-threshold" "f_hash_3.htm") + ("hash-table-size" "f_hash_4.htm") + ("hash-table-test" "f_hash_5.htm") + ("host-namestring" "f_namest.htm") + ("identity" "f_identi.htm") + ("if" "s_if.htm") + ("ignorable" "d_ignore.htm") + ("ignore" "d_ignore.htm") + ("ignore-errors" "m_ignore.htm") + ("imagpart" "f_realpa.htm") + ("import" "f_import.htm") + ("in-package" "m_in_pkg.htm") + ("incf" "m_incf_.htm") + ("initialize-instance" "f_init_i.htm") + ("inline" "d_inline.htm") + ("input-stream-p" "f_in_stm.htm") + ("inspect" "f_inspec.htm") + ("integer" "t_intege.htm") + ("integer-decode-float" "f_dec_fl.htm") + ("integer-length" "f_intege.htm") + ("integerp" "f_inte_1.htm") + ("interactive-stream-p" "f_intera.htm") + ("intern" "f_intern.htm") + ("internal-time-units-per-second" "v_intern.htm") + ("intersection" "f_isec_.htm") + ("invalid-method-error" "f_invali.htm") + ("invoke-debugger" "f_invoke.htm") + ("invoke-restart" "f_invo_1.htm") + ("invoke-restart-interactively" "f_invo_2.htm") + ("isqrt" "f_sqrt_.htm") + ("keyword" "t_kwd.htm") + ("keywordp" "f_kwdp.htm") + ("labels" "s_flet_.htm") + ("lambda" "a_lambda.htm") + ("lambda-list-keywords" "v_lambda.htm") + ("lambda-parameters-limit" "v_lamb_1.htm") + ("last" "f_last.htm") + ("lcm" "f_lcm.htm") + ("ldb" "f_ldb.htm") + ("ldb-test" "f_ldb_te.htm") + ("ldiff" "f_ldiffc.htm") + ("least-negative-double-float" "v_most_1.htm") + ("least-negative-long-float" "v_most_1.htm") + ("least-negative-normalized-double-float" "v_most_1.htm") + ("least-negative-normalized-long-float" "v_most_1.htm") + ("least-negative-normalized-short-float" "v_most_1.htm") + ("least-negative-normalized-single-float" "v_most_1.htm") + ("least-negative-short-float" "v_most_1.htm") + ("least-negative-single-float" "v_most_1.htm") + ("least-positive-double-float" "v_most_1.htm") + ("least-positive-long-float" "v_most_1.htm") + ("least-positive-normalized-double-float" "v_most_1.htm") + ("least-positive-normalized-long-float" "v_most_1.htm") + ("least-positive-normalized-short-float" "v_most_1.htm") + ("least-positive-normalized-single-float" "v_most_1.htm") + ("least-positive-short-float" "v_most_1.htm") + ("least-positive-single-float" "v_most_1.htm") + ("length" "f_length.htm") + ("let" "s_let_l.htm") + ("let*" "s_let_l.htm") + ("lisp-implementation-type" "f_lisp_i.htm") + ("lisp-implementation-version" "f_lisp_i.htm") + ("list" "a_list.htm") + ("list*" "f_list_.htm") + ("list-all-packages" "f_list_a.htm") + ("list-length" "f_list_l.htm") + ("listen" "f_listen.htm") + ("listp" "f_listp.htm") + ("load" "f_load.htm") + ("load-logical-pathname-translations" "f_ld_log.htm") + ("load-time-value" "s_ld_tim.htm") + ("locally" "s_locall.htm") + ("log" "f_log.htm") + ("logand" "f_logand.htm") + ("logandc1" "f_logand.htm") + ("logandc2" "f_logand.htm") + ("logbitp" "f_logbtp.htm") + ("logcount" "f_logcou.htm") + ("logeqv" "f_logand.htm") + ("logical-pathname" "a_logica.htm") + ("logical-pathname-translations" "f_logica.htm") + ("logior" "f_logand.htm") + ("lognand" "f_logand.htm") + ("lognor" "f_logand.htm") + ("lognot" "f_logand.htm") + ("logorc1" "f_logand.htm") + ("logorc2" "f_logand.htm") + ("logtest" "f_logtes.htm") + ("logxor" "f_logand.htm") + ("long-float" "t_short_.htm") + ("long-float-epsilon" "v_short_.htm") + ("long-float-negative-epsilon" "v_short_.htm") + ("long-site-name" "f_short_.htm") + ("loop" "m_loop.htm") + ("loop-finish" "m_loop_f.htm") + ("lower-case-p" "f_upper_.htm") + ("machine-instance" "f_mach_i.htm") + ("machine-type" "f_mach_t.htm") + ("machine-version" "f_mach_v.htm") + ("macro-function" "f_macro_.htm") + ("macroexpand" "f_mexp_.htm") + ("macroexpand-1" "f_mexp_.htm") + ("macrolet" "s_flet_.htm") + ("make-array" "f_mk_ar.htm") + ("make-broadcast-stream" "f_mk_bro.htm") + ("make-concatenated-stream" "f_mk_con.htm") + ("make-condition" "f_mk_cnd.htm") + ("make-dispatch-macro-character" "f_mk_dis.htm") + ("make-echo-stream" "f_mk_ech.htm") + ("make-hash-table" "f_mk_has.htm") + ("make-instance" "f_mk_ins.htm") + ("make-instances-obsolete" "f_mk_i_1.htm") + ("make-list" "f_mk_lis.htm") + ("make-load-form" "f_mk_ld_.htm") + ("make-load-form-saving-slots" "f_mk_l_1.htm") + ("make-method" "m_call_m.htm") + ("make-package" "f_mk_pkg.htm") + ("make-pathname" "f_mk_pn.htm") + ("make-random-state" "f_mk_rnd.htm") + ("make-sequence" "f_mk_seq.htm") + ("make-string" "f_mk_stg.htm") + ("make-string-input-stream" "f_mk_s_1.htm") + ("make-string-output-stream" "f_mk_s_2.htm") + ("make-symbol" "f_mk_sym.htm") + ("make-synonym-stream" "f_mk_syn.htm") + ("make-two-way-stream" "f_mk_two.htm") + ("makunbound" "f_makunb.htm") + ("map" "f_map.htm") + ("map-into" "f_map_in.htm") + ("mapc" "f_mapc_.htm") + ("mapcan" "f_mapc_.htm") + ("mapcar" "f_mapc_.htm") + ("mapcon" "f_mapc_.htm") + ("maphash" "f_maphas.htm") + ("mapl" "f_mapc_.htm") + ("maplist" "f_mapc_.htm") + ("mask-field" "f_mask_f.htm") + ("max" "f_max_m.htm") + ("member" "a_member.htm") + ("member-if" "f_mem_m.htm") + ("member-if-not" "f_mem_m.htm") + ("merge" "f_merge.htm") + ("merge-pathnames" "f_merge_.htm") + ("method" "t_method.htm") + ("method-combination" "a_method.htm") + ("method-combination-error" "f_meth_1.htm") + ("method-qualifiers" "f_method.htm") + ("min" "f_max_m.htm") + ("minusp" "f_minusp.htm") + ("mismatch" "f_mismat.htm") + ("mod" "a_mod.htm") + ("most-negative-double-float" "v_most_1.htm") + ("most-negative-fixnum" "v_most_p.htm") + ("most-negative-long-float" "v_most_1.htm") + ("most-negative-short-float" "v_most_1.htm") + ("most-negative-single-float" "v_most_1.htm") + ("most-positive-double-float" "v_most_1.htm") + ("most-positive-fixnum" "v_most_p.htm") + ("most-positive-long-float" "v_most_1.htm") + ("most-positive-short-float" "v_most_1.htm") + ("most-positive-single-float" "v_most_1.htm") + ("muffle-warning" "a_muffle.htm") + ("multiple-value-bind" "m_multip.htm") + ("multiple-value-call" "s_multip.htm") + ("multiple-value-list" "m_mult_1.htm") + ("multiple-value-prog1" "s_mult_1.htm") + ("multiple-value-setq" "m_mult_2.htm") + ("multiple-values-limit" "v_multip.htm") + ("name-char" "f_name_c.htm") + ("namestring" "f_namest.htm") + ("nbutlast" "f_butlas.htm") + ("nconc" "f_nconc.htm") + ("next-method-p" "f_next_m.htm") + ("nil" "a_nil.htm") + ("nintersection" "f_isec_.htm") + ("ninth" "f_firstc.htm") + ("no-applicable-method" "f_no_app.htm") + ("no-next-method" "f_no_nex.htm") + ("not" "a_not.htm") + ("notany" "f_everyc.htm") + ("notevery" "f_everyc.htm") + ("notinline" "d_inline.htm") + ("nreconc" "f_revapp.htm") + ("nreverse" "f_revers.htm") + ("nset-difference" "f_set_di.htm") + ("nset-exclusive-or" "f_set_ex.htm") + ("nstring-capitalize" "f_stg_up.htm") + ("nstring-downcase" "f_stg_up.htm") + ("nstring-upcase" "f_stg_up.htm") + ("nsublis" "f_sublis.htm") + ("nsubst" "f_substc.htm") + ("nsubst-if" "f_substc.htm") + ("nsubst-if-not" "f_substc.htm") + ("nsubstitute" "f_sbs_s.htm") + ("nsubstitute-if" "f_sbs_s.htm") + ("nsubstitute-if-not" "f_sbs_s.htm") + ("nth" "f_nth.htm") + ("nth-value" "m_nth_va.htm") + ("nthcdr" "f_nthcdr.htm") + ("null" "a_null.htm") + ("number" "t_number.htm") + ("numberp" "f_nump.htm") + ("numerator" "f_numera.htm") + ("nunion" "f_unionc.htm") + ("oddp" "f_evenpc.htm") + ("open" "f_open.htm") + ("open-stream-p" "f_open_s.htm") + ("optimize" "d_optimi.htm") + ("or" "a_or.htm") + ("otherwise" "m_case_.htm") + ("output-stream-p" "f_in_stm.htm") + ("package" "t_pkg.htm") + ("package-error" "e_pkg_er.htm") + ("package-error-package" "f_pkg_er.htm") + ("package-name" "f_pkg_na.htm") + ("package-nicknames" "f_pkg_ni.htm") + ("package-shadowing-symbols" "f_pkg_sh.htm") + ("package-use-list" "f_pkg_us.htm") + ("package-used-by-list" "f_pkg__1.htm") + ("packagep" "f_pkgp.htm") + ("pairlis" "f_pairli.htm") + ("parse-error" "e_parse_.htm") + ("parse-integer" "f_parse_.htm") + ("parse-namestring" "f_pars_1.htm") + ("pathname" "a_pn.htm") + ("pathname-device" "f_pn_hos.htm") + ("pathname-directory" "f_pn_hos.htm") + ("pathname-host" "f_pn_hos.htm") + ("pathname-match-p" "f_pn_mat.htm") + ("pathname-name" "f_pn_hos.htm") + ("pathname-type" "f_pn_hos.htm") + ("pathname-version" "f_pn_hos.htm") + ("pathnamep" "f_pnp.htm") + ("peek-char" "f_peek_c.htm") + ("phase" "f_phase.htm") + ("pi" "v_pi.htm") + ("plusp" "f_minusp.htm") + ("pop" "m_pop.htm") + ("position" "f_pos_p.htm") + ("position-if" "f_pos_p.htm") + ("position-if-not" "f_pos_p.htm") + ("pprint" "f_wr_pr.htm") + ("pprint-dispatch" "f_ppr_di.htm") + ("pprint-exit-if-list-exhausted" "m_ppr_ex.htm") + ("pprint-fill" "f_ppr_fi.htm") + ("pprint-indent" "f_ppr_in.htm") + ("pprint-linear" "f_ppr_fi.htm") + ("pprint-logical-block" "m_ppr_lo.htm") + ("pprint-newline" "f_ppr_nl.htm") + ("pprint-pop" "m_ppr_po.htm") + ("pprint-tab" "f_ppr_ta.htm") + ("pprint-tabular" "f_ppr_fi.htm") + ("prin1" "f_wr_pr.htm") + ("prin1-to-string" "f_wr_to_.htm") + ("princ" "f_wr_pr.htm") + ("princ-to-string" "f_wr_to_.htm") + ("print" "f_wr_pr.htm") + ("print-not-readable" "e_pr_not.htm") + ("print-not-readable-object" "f_pr_not.htm") + ("print-object" "f_pr_obj.htm") + ("print-unreadable-object" "m_pr_unr.htm") + ("probe-file" "f_probe_.htm") + ("proclaim" "f_procla.htm") + ("prog" "m_prog_.htm") + ("prog*" "m_prog_.htm") + ("prog1" "m_prog1c.htm") + ("prog2" "m_prog1c.htm") + ("progn" "s_progn.htm") + ("program-error" "e_progra.htm") + ("progv" "s_progv.htm") + ("provide" "f_provid.htm") + ("psetf" "m_setf_.htm") + ("psetq" "m_psetq.htm") + ("push" "m_push.htm") + ("pushnew" "m_pshnew.htm") + ("quote" "s_quote.htm") + ("random" "f_random.htm") + ("random-state" "t_rnd_st.htm") + ("random-state-p" "f_rnd_st.htm") + ("rassoc" "f_rassoc.htm") + ("rassoc-if" "f_rassoc.htm") + ("rassoc-if-not" "f_rassoc.htm") + ("ratio" "t_ratio.htm") + ("rational" "a_ration.htm") + ("rationalize" "f_ration.htm") + ("rationalp" "f_rati_1.htm") + ("read" "f_rd_rd.htm") + ("read-byte" "f_rd_by.htm") + ("read-char" "f_rd_cha.htm") + ("read-char-no-hang" "f_rd_c_1.htm") + ("read-delimited-list" "f_rd_del.htm") + ("read-from-string" "f_rd_fro.htm") + ("read-line" "f_rd_lin.htm") + ("read-preserving-whitespace" "f_rd_rd.htm") + ("read-sequence" "f_rd_seq.htm") + ("reader-error" "e_rder_e.htm") + ("readtable" "t_rdtabl.htm") + ("readtable-case" "f_rdtabl.htm") + ("readtablep" "f_rdta_1.htm") + ("real" "t_real.htm") + ("realp" "f_realp.htm") + ("realpart" "f_realpa.htm") + ("reduce" "f_reduce.htm") + ("reinitialize-instance" "f_reinit.htm") + ("rem" "f_mod_r.htm") + ("remf" "m_remf.htm") + ("remhash" "f_remhas.htm") + ("remove" "f_rm_rm.htm") + ("remove-duplicates" "f_rm_dup.htm") + ("remove-if" "f_rm_rm.htm") + ("remove-if-not" "f_rm_rm.htm") + ("remove-method" "f_rm_met.htm") + ("remprop" "f_rempro.htm") + ("rename-file" "f_rn_fil.htm") + ("rename-package" "f_rn_pkg.htm") + ("replace" "f_replac.htm") + ("require" "f_provid.htm") + ("rest" "f_rest.htm") + ("restart" "t_rst.htm") + ("restart-bind" "m_rst_bi.htm") + ("restart-case" "m_rst_ca.htm") + ("restart-name" "f_rst_na.htm") + ("return" "m_return.htm") + ("return-from" "s_ret_fr.htm") + ("revappend" "f_revapp.htm") + ("reverse" "f_revers.htm") + ("room" "f_room.htm") + ("rotatef" "m_rotate.htm") + ("round" "f_floorc.htm") + ("row-major-aref" "f_row_ma.htm") + ("rplaca" "f_rplaca.htm") + ("rplacd" "f_rplaca.htm") + ("safety" "d_optimi.htm") + ("satisfies" "t_satisf.htm") + ("sbit" "f_bt_sb.htm") + ("scale-float" "f_dec_fl.htm") + ("schar" "f_char_.htm") + ("search" "f_search.htm") + ("second" "f_firstc.htm") + ("sequence" "t_seq.htm") + ("serious-condition" "e_seriou.htm") + ("set" "f_set.htm") + ("set-difference" "f_set_di.htm") + ("set-dispatch-macro-character" "f_set__1.htm") + ("set-exclusive-or" "f_set_ex.htm") + ("set-macro-character" "f_set_ma.htm") + ("set-pprint-dispatch" "f_set_pp.htm") + ("set-syntax-from-char" "f_set_sy.htm") + ("setf" "a_setf.htm") + ("setq" "s_setq.htm") + ("seventh" "f_firstc.htm") + ("shadow" "f_shadow.htm") + ("shadowing-import" "f_shdw_i.htm") + ("shared-initialize" "f_shared.htm") + ("shiftf" "m_shiftf.htm") + ("short-float" "t_short_.htm") + ("short-float-epsilon" "v_short_.htm") + ("short-float-negative-epsilon" "v_short_.htm") + ("short-site-name" "f_short_.htm") + ("signal" "f_signal.htm") + ("signed-byte" "t_sgn_by.htm") + ("signum" "f_signum.htm") + ("simple-array" "t_smp_ar.htm") + ("simple-base-string" "t_smp_ba.htm") + ("simple-bit-vector" "t_smp_bt.htm") + ("simple-bit-vector-p" "f_smp_bt.htm") + ("simple-condition" "e_smp_cn.htm") + ("simple-condition-format-arguments" "f_smp_cn.htm") + ("simple-condition-format-control" "f_smp_cn.htm") + ("simple-error" "e_smp_er.htm") + ("simple-string" "t_smp_st.htm") + ("simple-string-p" "f_smp_st.htm") + ("simple-type-error" "e_smp_tp.htm") + ("simple-vector" "t_smp_ve.htm") + ("simple-vector-p" "f_smp_ve.htm") + ("simple-warning" "e_smp_wa.htm") + ("sin" "f_sin_c.htm") + ("single-float" "t_short_.htm") + ("single-float-epsilon" "v_short_.htm") + ("single-float-negative-epsilon" "v_short_.htm") + ("sinh" "f_sinh_.htm") + ("sixth" "f_firstc.htm") + ("sleep" "f_sleep.htm") + ("slot-boundp" "f_slt_bo.htm") + ("slot-exists-p" "f_slt_ex.htm") + ("slot-makunbound" "f_slt_ma.htm") + ("slot-missing" "f_slt_mi.htm") + ("slot-unbound" "f_slt_un.htm") + ("slot-value" "f_slt_va.htm") + ("software-type" "f_sw_tpc.htm") + ("software-version" "f_sw_tpc.htm") + ("some" "f_everyc.htm") + ("sort" "f_sort_.htm") + ("space" "d_optimi.htm") + ("special" "d_specia.htm") + ("special-operator-p" "f_specia.htm") + ("speed" "d_optimi.htm") + ("sqrt" "f_sqrt_.htm") + ("stable-sort" "f_sort_.htm") + ("standard" "07_ffb.htm") + ("standard-char" "t_std_ch.htm") + ("standard-char-p" "f_std_ch.htm") + ("standard-class" "t_std_cl.htm") + ("standard-generic-function" "t_std_ge.htm") + ("standard-method" "t_std_me.htm") + ("standard-object" "t_std_ob.htm") + ("step" "m_step.htm") + ("storage-condition" "e_storag.htm") + ("store-value" "a_store_.htm") + ("stream" "t_stream.htm") + ("stream-element-type" "f_stm_el.htm") + ("stream-error" "e_stm_er.htm") + ("stream-error-stream" "f_stm_er.htm") + ("stream-external-format" "f_stm_ex.htm") + ("streamp" "f_stmp.htm") + ("string" "a_string.htm") + ("string-capitalize" "f_stg_up.htm") + ("string-downcase" "f_stg_up.htm") + ("string-equal" "f_stgeq_.htm") + ("string-greaterp" "f_stgeq_.htm") + ("string-left-trim" "f_stg_tr.htm") + ("string-lessp" "f_stgeq_.htm") + ("string-not-equal" "f_stgeq_.htm") + ("string-not-greaterp" "f_stgeq_.htm") + ("string-not-lessp" "f_stgeq_.htm") + ("string-right-trim" "f_stg_tr.htm") + ("string-stream" "t_stg_st.htm") + ("string-trim" "f_stg_tr.htm") + ("string-upcase" "f_stg_up.htm") + ("string/=" "f_stgeq_.htm") + ("string<" "f_stgeq_.htm") + ("string<=" "f_stgeq_.htm") + ("string=" "f_stgeq_.htm") + ("string>" "f_stgeq_.htm") + ("string>=" "f_stgeq_.htm") + ("stringp" "f_stgp.htm") + ("structure" "f_docume.htm") + ("structure-class" "t_stu_cl.htm") + ("structure-object" "t_stu_ob.htm") + ("style-warning" "e_style_.htm") + ("sublis" "f_sublis.htm") + ("subseq" "f_subseq.htm") + ("subsetp" "f_subset.htm") + ("subst" "f_substc.htm") + ("subst-if" "f_substc.htm") + ("subst-if-not" "f_substc.htm") + ("substitute" "f_sbs_s.htm") + ("substitute-if" "f_sbs_s.htm") + ("substitute-if-not" "f_sbs_s.htm") + ("subtypep" "f_subtpp.htm") + ("svref" "f_svref.htm") + ("sxhash" "f_sxhash.htm") + ("symbol" "t_symbol.htm") + ("symbol-function" "f_symb_1.htm") + ("symbol-macrolet" "s_symbol.htm") + ("symbol-name" "f_symb_2.htm") + ("symbol-package" "f_symb_3.htm") + ("symbol-plist" "f_symb_4.htm") + ("symbol-value" "f_symb_5.htm") + ("symbolp" "f_symbol.htm") + ("synonym-stream" "t_syn_st.htm") + ("synonym-stream-symbol" "f_syn_st.htm") + ("t" "a_t.htm") + ("tagbody" "s_tagbod.htm") + ("tailp" "f_ldiffc.htm") + ("tan" "f_sin_c.htm") + ("tanh" "f_sinh_.htm") + ("tenth" "f_firstc.htm") + ("terpri" "f_terpri.htm") + ("the" "s_the.htm") + ("third" "f_firstc.htm") + ("throw" "s_throw.htm") + ("time" "m_time.htm") + ("trace" "m_tracec.htm") + ("translate-logical-pathname" "f_tr_log.htm") + ("translate-pathname" "f_tr_pn.htm") + ("tree-equal" "f_tree_e.htm") + ("truename" "f_tn.htm") + ("truncate" "f_floorc.htm") + ("two-way-stream" "t_two_wa.htm") + ("two-way-stream-input-stream" "f_two_wa.htm") + ("two-way-stream-output-stream" "f_two_wa.htm") + ("type" "a_type.htm") + ("type-error" "e_tp_err.htm") + ("type-error-datum" "f_tp_err.htm") + ("type-error-expected-type" "f_tp_err.htm") + ("type-of" "f_tp_of.htm") + ("typecase" "m_tpcase.htm") + ("typep" "f_typep.htm") + ("unbound-slot" "e_unboun.htm") + ("unbound-slot-instance" "f_unboun.htm") + ("unbound-variable" "e_unbo_1.htm") + ("undefined-function" "e_undefi.htm") + ("unexport" "f_unexpo.htm") + ("unintern" "f_uninte.htm") + ("union" "f_unionc.htm") + ("unless" "m_when_.htm") + ("unread-char" "f_unrd_c.htm") + ("unsigned-byte" "t_unsgn_.htm") + ("untrace" "m_tracec.htm") + ("unuse-package" "f_unuse_.htm") + ("unwind-protect" "s_unwind.htm") + ("update-instance-for-different-class" "f_update.htm") + ("update-instance-for-redefined-class" "f_upda_1.htm") + ("upgraded-array-element-type" "f_upgr_1.htm") + ("upgraded-complex-part-type" "f_upgrad.htm") + ("upper-case-p" "f_upper_.htm") + ("use-package" "f_use_pk.htm") + ("use-value" "a_use_va.htm") + ("user-homedir-pathname" "f_user_h.htm") + ("values" "a_values.htm") + ("values-list" "f_vals_l.htm") + ("variable" "f_docume.htm") + ("vector" "a_vector.htm") + ("vector-pop" "f_vec_po.htm") + ("vector-push" "f_vec_ps.htm") + ("vector-push-extend" "f_vec_ps.htm") + ("vectorp" "f_vecp.htm") + ("warn" "f_warn.htm") + ("warning" "e_warnin.htm") + ("when" "m_when_.htm") + ("wild-pathname-p" "f_wild_p.htm") + ("with-accessors" "m_w_acce.htm") + ("with-compilation-unit" "m_w_comp.htm") + ("with-condition-restarts" "m_w_cnd_.htm") + ("with-hash-table-iterator" "m_w_hash.htm") + ("with-input-from-string" "m_w_in_f.htm") + ("with-open-file" "m_w_open.htm") + ("with-open-stream" "m_w_op_1.htm") + ("with-output-to-string" "m_w_out_.htm") + ("with-package-iterator" "m_w_pkg_.htm") + ("with-simple-restart" "m_w_smp_.htm") + ("with-slots" "m_w_slts.htm") + ("with-standard-io-syntax" "m_w_std_.htm") + ("write" "f_wr_pr.htm") + ("write-byte" "f_wr_by.htm") + ("write-char" "f_wr_cha.htm") + ("write-line" "f_wr_stg.htm") + ("write-sequence" "f_wr_seq.htm") + ("write-string" "f_wr_stg.htm") + ("write-to-string" "f_wr_to_.htm") + ("y-or-n-p" "f_y_or_n.htm") + ("yes-or-no-p" "f_y_or_n.htm") + ("zerop" "f_zerop.htm")))) + +;;; Added entries for reader macros. +;;; +;;; 20090302 Tobias C Rittweiler, and Stas Boukarev + +(defvar common-lisp-hyperspec--reader-macros (make-hash-table :test #'equal)) + +;;; Data/Map_Sym.txt in does not contain entries for the reader +;;; macros. So we have to enumerate these explicitly. +(mapc (lambda (entry) + (puthash (car entry) (cadr entry) + common-lisp-hyperspec--reader-macros)) + '(("#" "02_dh.htm") + ("##" "02_dhp.htm") + ("#'" "02_dhb.htm") + ("#(" "02_dhc.htm") + ("#*" "02_dhd.htm") + ("#:" "02_dhe.htm") + ("#." "02_dhf.htm") + ("#=" "02_dho.htm") + ("#+" "02_dhq.htm") + ("#-" "02_dhr.htm") + ("#<" "02_dht.htm") + ("#A" "02_dhl.htm") + ("#B" "02_dhg.htm") + ("#C" "02_dhk.htm") + ("#O" "02_dhh.htm") + ("#P" "02_dhn.htm") + ("#R" "02_dhj.htm") + ("#S" "02_dhm.htm") + ("#X" "02_dhi.htm") + ("#\\" "02_dha.htm") + ("#|" "02_dhs.htm") + ("\"" "02_de.htm") + ("'" "02_dc.htm") + ("`" "02_df.htm") + ("," "02_dg.htm") + ("(" "02_da.htm") + (")" "02_db.htm") + (";" "02_dd.htm"))) + +(defun common-lisp-hyperspec-lookup-reader-macro (macro) + "Browse the CLHS entry for the reader-macro MACRO." + (interactive + (list + (let ((completion-ignore-case t)) + (completing-read "Look up reader-macro: " + common-lisp-hyperspec--reader-macros nil t + (common-lisp-hyperspec-reader-macro-at-point))))) + (browse-url + (concat common-lisp-hyperspec-root "Body/" + (gethash macro common-lisp-hyperspec--reader-macros)))) + +(defun common-lisp-hyperspec-reader-macro-at-point () + (let ((regexp "\\(#.?\\)\\|\\([\"',`';()]\\)")) + (when (looking-back regexp nil t) + (match-string-no-properties 0)))) + +;;; FORMAT character lookup by Frode Vatvedt Fjeld 20030902 +;;; +;;; adjusted for ILISP by Nikodemus Siivola 20030903 + +(defvar common-lisp-hyperspec-format-history nil + "History of format characters looked up in the Common Lisp HyperSpec.") + +(defun common-lisp-hyperspec-section-6.0 (indices) + (let ((string (format "%sBody/%s_" + common-lisp-hyperspec-root + (let ((base (pop indices))) + (if (< base 10) + (format "0%s" base) + base))))) + (concat string + (mapconcat (lambda (n) + (make-string 1 (+ ?a (- n 1)))) + indices + "") + ".htm"))) + +(defun common-lisp-hyperspec-section-4.0 (indices) + (let ((string (format "%sBody/sec_" + common-lisp-hyperspec-root))) + (concat string + (mapconcat (lambda (n) + (format "%d" n)) + indices + "-") + ".html"))) + +(defvar common-lisp-hyperspec-section-fun 'common-lisp-hyperspec-section-6.0) + +(defun common-lisp-hyperspec-section (indices) + (funcall common-lisp-hyperspec-section-fun indices)) + +(defvar common-lisp-hyperspec--format-characters + (make-hash-table :test 'equal)) + +(defun common-lisp-hyperspec--read-format-character () + (let ((char-at-point + (ignore-errors (char-to-string (char-after (point)))))) + (if (and char-at-point + (gethash (upcase char-at-point) + common-lisp-hyperspec--format-characters)) + char-at-point + (completing-read + "Look up format control character in Common Lisp HyperSpec: " + common-lisp-hyperspec--format-characters nil t nil + 'common-lisp-hyperspec-format-history)))) + +(defun common-lisp-hyperspec-format (character-name) + (interactive (list (common-lisp-hyperspec--read-format-character))) + (cl-maplist (lambda (entry) + (browse-url (common-lisp-hyperspec-section (car entry)))) + (or (gethash character-name + common-lisp-hyperspec--format-characters) + (error "The symbol `%s' is not defined in Common Lisp" + character-name)))) + +;;; Previously there were entries for "C" and "C: Character", +;;; which unpleasingly crowded the completion buffer, so I made +;;; it show one entry ("C - Character") only. +;;; +;;; 20100131 Tobias C Rittweiler + +(defun common-lisp-hyperspec--insert-format-directive (char section + &optional summary) + (let* ((designator (if summary (format "%s - %s" char summary) char))) + (cl-pushnew section (gethash designator + common-lisp-hyperspec--format-characters) + :test #'equal))) + +(mapc (lambda (entry) + (cl-destructuring-bind (char section &optional summary) entry + (common-lisp-hyperspec--insert-format-directive char section summary) + (when (and (= 1 (length char)) + (not (string-equal char (upcase char)))) + (common-lisp-hyperspec--insert-format-directive + (upcase char) section summary)))) + '(("c" (22 3 1 1) "Character") + ("%" (22 3 1 2) "Newline") + ("&" (22 3 1 3) "Fresh-line") + ("|" (22 3 1 4) "Page") + ("~" (22 3 1 5) "Tilde") + ("r" (22 3 2 1) "Radix") + ("d" (22 3 2 2) "Decimal") + ("b" (22 3 2 3) "Binary") + ("o" (22 3 2 4) "Octal") + ("x" (22 3 2 5) "Hexadecimal") + ("f" (22 3 3 1) "Fixed-Format Floating-Point") + ("e" (22 3 3 2) "Exponential Floating-Point") + ("g" (22 3 3 3) "General Floating-Point") + ("$" (22 3 3 4) "Monetary Floating-Point") + ("a" (22 3 4 1) "Aesthetic") + ("s" (22 3 4 2) "Standard") + ("w" (22 3 4 3) "Write") + ("_" (22 3 5 1) "Conditional Newline") + ("<" (22 3 5 2) "Logical Block") + ("i" (22 3 5 3) "Indent") + ("/" (22 3 5 4) "Call Function") + ("t" (22 3 6 1) "Tabulate") + ("<" (22 3 6 2) "Justification") + (">" (22 3 6 3) "End of Justification") + ("*" (22 3 7 1) "Go-To") + ("[" (22 3 7 2) "Conditional Expression") + ("]" (22 3 7 3) "End of Conditional Expression") + ("{" (22 3 7 4) "Iteration") + ("}" (22 3 7 5) "End of Iteration") + ("?" (22 3 7 6) "Recursive Processing") + ("(" (22 3 8 1) "Case Conversion") + (")" (22 3 8 2) "End of Case Conversion") + ("p" (22 3 8 3) "Plural") + (";" (22 3 9 1) "Clause Separator") + ("^" (22 3 9 2) "Escape Upward") + ("Newline: Ignored Newline" (22 3 9 3)) + ("Nesting of FORMAT Operations" (22 3 10 1)) + ("Missing and Additional FORMAT Arguments" (22 3 10 2)) + ("Additional FORMAT Parameters" (22 3 10 3)))) + + +;;;; Glossary + +(defvar common-lisp-hyperspec-glossary-function 'common-lisp-glossary-6.0 + "Function that creates a URL for a glossary term.") + +(define-obsolete-variable-alias 'common-lisp-glossary-fun + 'common-lisp-hyperspec-glossary-function) + +(defvar common-lisp-hyperspec--glossary-terms (make-hash-table :test #'equal) + "Collection of glossary terms and relative URLs.") + +;;; Functions + +;;; The functions below are used to collect glossary terms and page anchors +;;; from CLHS. They are commented out because they are not needed unless the +;;; list of terms/anchors need to be updated. + +;; (defun common-lisp-hyperspec-glossary-pages () +;; "List of CLHS glossary pages." +;; (mapcar (lambda (end) +;; (format "%sBody/26_glo_%s.htm" +;; common-lisp-hyperspec-root +;; end)) +;; (cons "9" (mapcar #'char-to-string +;; (number-sequence ?a ?z))))) + +;; (defun common-lisp-hyperspec-glossary-download () +;; "Download CLHS glossary pages to temporary files and return a +;; list of file names." +;; (mapcar (lambda (url) +;; (url-file-local-copy url)) +;; (common-lisp-hyperspec-glossary-pages))) + +;; (defun common-lisp-hyperspec-glossary-entries (file) +;; "Given a CLHS glossary file FILE, return a list of +;; term-anchor pairs. + +;; Term is the glossary term and anchor is the term's anchor on the +;; page." +;; (let (entries) +;; (save-excursion +;; (set-buffer (find-file-noselect file)) +;; (goto-char (point-min)) +;; (while (search-forward-regexp "\\(.*?\\)" nil t) +;; (setq entries (cons (list (match-string-no-properties 2) +;; (match-string-no-properties 1)) +;; entries)))) +;; (sort entries (lambda (a b) +;; (string< (car a) (car b)))))) + +;; ;; Add glossary terms by downloading and parsing glossary pages from CLHS +;; (mapc (lambda (entry) +;; (puthash (car entry) (cadr entry) +;; common-lisp-hyperspec--glossary-terms)) +;; (cl-reduce (lambda (a b) +;; (append a b)) +;; (mapcar #'common-lisp-hyperspec-glossary-entries +;; (common-lisp-hyperspec-glossary-download)))) + +;; Add glossary entries to the master hash table +(mapc (lambda (entry) + (puthash (car entry) (cadr entry) + common-lisp-hyperspec--glossary-terms)) + '(("()" "OPCP") + ("absolute" "absolute") + ("access" "access") + ("accessibility" "accessibility") + ("accessible" "accessible") + ("accessor" "accessor") + ("active" "active") + ("actual adjustability" "actual_adjustability") + ("actual argument" "actual_argument") + ("actual array element type" "actual_array_element_type") + ("actual complex part type" "actual_complex_part_type") + ("actual parameter" "actual_parameter") + ("actually adjustable" "actually_adjustable") + ("adjustability" "adjustability") + ("adjustable" "adjustable") + ("after method" "after_method") + ("alist" "alist") + ("alphabetic" "alphabetic") + ("alphanumeric" "alphanumeric") + ("ampersand" "ampersand") + ("anonymous" "anonymous") + ("apparently uninterned" "apparently_uninterned") + ("applicable" "applicable") + ("applicable handler" "applicable_handler") + ("applicable method" "applicable_method") + ("applicable restart" "applicable_restart") + ("apply" "apply") + ("argument" "argument") + ("argument evaluation order" "argument_evaluation_order") + ("argument precedence order" "argument_precedence_order") + ("around method" "around_method") + ("array" "array") + ("array element type" "array_element_type") + ("array total size" "array_total_size") + ("assign" "assign") + ("association list" "association_list") + ("asterisk" "asterisk") + ("at-sign" "at-sign") + ("atom" "atom") + ("atomic" "atomic") + ("atomic type specifier" "atomic_type_specifier") + ("attribute" "attribute") + ("aux variable" "aux_variable") + ("auxiliary method" "auxiliary_method") + ("backquote" "backquote") + ("backslash" "backslash") + ("base character" "base_character") + ("base string" "base_string") + ("before method" "before_method") + ("bidirectional" "bidirectional") + ("binary" "binary") + ("bind" "bind") + ("binding" "binding") + ("bit" "bit") + ("bit array" "bit_array") + ("bit vector" "bit_vector") + ("bit-wise logical operation specifier" "bit-wise_logical_operation_specifier") + ("block" "block") + ("block tag" "block_tag") + ("boa lambda list" "boa_lambda_list") + ("body parameter" "body_parameter") + ("boolean" "boolean") + ("boolean equivalent" "boolean_equivalent") + ("bound" "bound") + ("bound declaration" "bound_declaration") + ("bounded" "bounded") + ("bounding index" "bounding_index") + ("bounding index designator" "bounding_index_designator") + ("break loop" "break_loop") + ("broadcast stream" "broadcast_stream") + ("built-in class" "built-in_class") + ("built-in type" "built-in_type") + ("byte" "byte") + ("byte specifier" "byte_specifier") + ("cadr" "cadr") + ("call" "call") + ("captured initialization form" "captured_initialization_form") + ("car" "car") + ("case" "case") + ("case sensitivity mode" "case_sensitivity_mode") + ("catch" "catch") + ("catch tag" "catch_tag") + ("cddr" "cddr") + ("cdr" "cdr") + ("cell" "cell") + ("character" "character") + ("character code" "character_code") + ("character designator" "character_designator") + ("circular" "circular") + ("circular list" "circular_list") + ("class" "class") + ("class designator" "class_designator") + ("class precedence list" "class_precedence_list") + ("close" "close") + ("closed" "closed") + ("closure" "closure") + ("coalesce" "coalesce") + ("code" "code") + ("coerce" "coerce") + ("colon" "colon") + ("comma" "comma") + ("compilation" "compilation") + ("compilation environment" "compilation_environment") + ("compilation unit" "compilation_unit") + ("compile" "compile") + ("compile time" "compile_time") + ("compile-time definition" "compile-time_definition") + ("compiled code" "compiled_code") + ("compiled file" "compiled_file") + ("compiled function" "compiled_function") + ("compiler" "compiler") + ("compiler macro" "compiler_macro") + ("compiler macro expansion" "compiler_macro_expansion") + ("compiler macro form" "compiler_macro_form") + ("compiler macro function" "compiler_macro_function") + ("complex" "complex") + ("complex float" "complex_float") + ("complex part type" "complex_part_type") + ("complex rational" "complex_rational") + ("complex single float" "complex_single_float") + ("composite stream" "composite_stream") + ("compound form" "compound_form") + ("compound type specifier" "compound_type_specifier") + ("concatenated stream" "concatenated_stream") + ("condition" "condition") + ("condition designator" "condition_designator") + ("condition handler" "condition_handler") + ("condition reporter" "condition_reporter") + ("conditional newline" "conditional_newline") + ("conformance" "conformance") + ("conforming code" "conforming_code") + ("conforming implementation" "conforming_implementation") + ("conforming processor" "conforming_processor") + ("conforming program" "conforming_program") + ("congruent" "congruent") + ("cons" "cons") + ("constant" "constant") + ("constant form" "constant_form") + ("constant object" "constant_object") + ("constant variable" "constant_variable") + ("constituent" "constituent") + ("constituent trait" "constituent_trait") + ("constructed stream" "constructed_stream") + ("contagion" "contagion") + ("continuable" "continuable") + ("control form" "control_form") + ("copy" "copy") + ("correctable" "correctable") + ("current input base" "current_input_base") + ("current logical block" "current_logical_block") + ("current output base" "current_output_base") + ("current package" "current_package") + ("current pprint dispatch table" "current_pprint_dispatch_table") + ("current random state" "current_random_state") + ("current readtable" "current_readtable") + ("data type" "data_type") + ("debug I/O" "debug_iSLo") + ("debugger" "debugger") + ("declaration" "declaration") + ("declaration identifier" "declaration_identifier") + ("declaration specifier" "declaration_specifier") + ("declare" "declare") + ("decline" "decline") + ("decoded time" "decoded_time") + ("default method" "default_method") + ("defaulted initialization argument list" "defaulted_initialization_argument_list") + ("define-method-combination arguments lambda list" "define-method-combination_arguments_lambda_list") + ("define-modify-macro lambda list" "define-modify-macro_lambda_list") + ("defined name" "defined_name") + ("defining form" "defining_form") + ("defsetf lambda list" "defsetf_lambda_list") + ("deftype lambda list" "deftype_lambda_list") + ("denormalized" "denormalized") + ("derived type" "derived_type") + ("derived type specifier" "derived_type_specifier") + ("designator" "designator") + ("destructive" "destructive") + ("destructuring lambda list" "destructuring_lambda_list") + ("different" "different") + ("digit" "digit") + ("dimension" "dimension") + ("direct instance" "direct_instance") + ("direct subclass" "direct_subclass") + ("direct superclass" "direct_superclass") + ("disestablish" "disestablish") + ("disjoint" "disjoint") + ("dispatching macro character" "dispatching_macro_character") + ("displaced array" "displaced_array") + ("distinct" "distinct") + ("documentation string" "documentation_string") + ("dot" "dot") + ("dotted list" "dotted_list") + ("dotted pair" "dotted_pair") + ("double float" "double_float") + ("double-quote" "double-quote") + ("dynamic binding" "dynamic_binding") + ("dynamic environment" "dynamic_environment") + ("dynamic extent" "dynamic_extent") + ("dynamic scope" "dynamic_scope") + ("dynamic variable" "dynamic_variable") + ("echo stream" "echo_stream") + ("effective method" "effective_method") + ("element" "element") + ("element type" "element_type") + ("em" "em") + ("empty list" "empty_list") + ("empty type" "empty_type") + ("end of file" "end_of_file") + ("environment" "environment") + ("environment object" "environment_object") + ("environment parameter" "environment_parameter") + ("error" "error") + ("error output" "error_output") + ("escape" "escape") + ("establish" "establish") + ("evaluate" "evaluate") + ("evaluation" "evaluation") + ("evaluation environment" "evaluation_environment") + ("execute" "execute") + ("execution time" "execution_time") + ("exhaustive partition" "exhaustive_partition") + ("exhaustive union" "exhaustive_union") + ("exit point" "exit_point") + ("explicit return" "explicit_return") + ("explicit use" "explicit_use") + ("exponent marker" "exponent_marker") + ("export" "export") + ("exported" "exported") + ("expressed adjustability" "expressed_adjustability") + ("expressed array element type" "expressed_array_element_type") + ("expressed complex part type" "expressed_complex_part_type") + ("expression" "expression") + ("expressly adjustable" "expressly_adjustable") + ("extended character" "extended_character") + ("extended function designator" "extended_function_designator") + ("extended lambda list" "extended_lambda_list") + ("extension" "extension") + ("extent" "extent") + ("external file format" "external_file_format") + ("external file format designator" "external_file_format_designator") + ("external symbol" "external_symbol") + ("externalizable object" "externalizable_object") + ("false" "false") + ("fbound" "fbound") + ("feature" "feature") + ("feature expression" "feature_expression") + ("features list" "features_list") + ("file" "file") + ("file compiler" "file_compiler") + ("file position" "file_position") + ("file position designator" "file_position_designator") + ("file stream" "file_stream") + ("file system" "file_system") + ("filename" "filename") + ("fill pointer" "fill_pointer") + ("finite" "finite") + ("fixnum" "fixnum") + ("float" "float") + ("for-value" "for-value") + ("form" "form") + ("formal argument" "formal_argument") + ("formal parameter" "formal_parameter") + ("format" "format") + ("format argument" "format_argument") + ("format control" "format_control") + ("format directive" "format_directive") + ("format string" "format_string") + ("free declaration" "free_declaration") + ("fresh" "fresh") + ("freshline" "freshline") + ("funbound" "funbound") + ("function" "function") + ("function block name" "function_block_name") + ("function cell" "function_cell") + ("function designator" "function_designator") + ("function form" "function_form") + ("function name" "function_name") + ("functional evaluation" "functional_evaluation") + ("functional value" "functional_value") + ("further compilation" "further_compilation") + ("general" "general") + ("generalized boolean" "generalized_boolean") + ("generalized instance" "generalized_instance") + ("generalized reference" "generalized_reference") + ("generalized synonym stream" "generalized_synonym_stream") + ("generic function" "generic_function") + ("generic function lambda list" "generic_function_lambda_list") + ("gensym" "gensym") + ("global declaration" "global_declaration") + ("global environment" "global_environment") + ("global variable" "global_variable") + ("glyph" "glyph") + ("go" "go") + ("go point" "go_point") + ("go tag" "go_tag") + ("graphic" "graphic") + ("handle" "handle") + ("handler" "handler") + ("hash table" "hash_table") + ("home package" "home_package") + ("I/O customization variable" "iSLo_customization_variable") + ("identical" "identical") + ("identifier" "identifier") + ("immutable" "immutable") + ("implementation" "implementation") + ("implementation limit" "implementation_limit") + ("implementation-defined" "implementation-defined") + ("implementation-dependent" "implementation-dependent") + ("implementation-independent" "implementation-independent") + ("implicit block" "implicit_block") + ("implicit compilation" "implicit_compilation") + ("implicit progn" "implicit_progn") + ("implicit tagbody" "implicit_tagbody") + ("import" "import") + ("improper list" "improper_list") + ("inaccessible" "inaccessible") + ("indefinite extent" "indefinite_extent") + ("indefinite scope" "indefinite_scope") + ("indicator" "indicator") + ("indirect instance" "indirect_instance") + ("inherit" "inherit") + ("initial pprint dispatch table" "initial_pprint_dispatch_table") + ("initial readtable" "initial_readtable") + ("initialization argument list" "initialization_argument_list") + ("initialization form" "initialization_form") + ("input" "input") + ("instance" "instance") + ("integer" "integer") + ("interactive stream" "interactive_stream") + ("intern" "intern") + ("internal symbol" "internal_symbol") + ("internal time" "internal_time") + ("internal time unit" "internal_time_unit") + ("interned" "interned") + ("interpreted function" "interpreted_function") + ("interpreted implementation" "interpreted_implementation") + ("interval designator" "interval_designator") + ("invalid" "invalid") + ("iteration form" "iteration_form") + ("iteration variable" "iteration_variable") + ("key" "key") + ("keyword" "keyword") + ("keyword parameter" "keyword_parameter") + ("keyword/value pair" "keywordSLvalue_pair") + ("Lisp image" "lisp_image") + ("Lisp printer" "lisp_printer") + ("Lisp read-eval-print loop" "lisp_read-eval-print_loop") + ("Lisp reader" "lisp_reader") + ("lambda combination" "lambda_combination") + ("lambda expression" "lambda_expression") + ("lambda form" "lambda_form") + ("lambda list" "lambda_list") + ("lambda list keyword" "lambda_list_keyword") + ("lambda variable" "lambda_variable") + ("leaf" "leaf") + ("leap seconds" "leap_seconds") + ("left-parenthesis" "left-parenthesis") + ("length" "length") + ("lexical binding" "lexical_binding") + ("lexical closure" "lexical_closure") + ("lexical environment" "lexical_environment") + ("lexical scope" "lexical_scope") + ("lexical variable" "lexical_variable") + ("list" "list") + ("list designator" "list_designator") + ("list structure" "list_structure") + ("literal" "literal") + ("load" "load") + ("load time" "load_time") + ("load time value" "load_time_value") + ("loader" "loader") + ("local declaration" "local_declaration") + ("local precedence order" "local_precedence_order") + ("local slot" "local_slot") + ("logical block" "logical_block") + ("logical host" "logical_host") + ("logical host designator" "logical_host_designator") + ("logical pathname" "logical_pathname") + ("long float" "long_float") + ("loop keyword" "loop_keyword") + ("lowercase" "lowercase") + ("Metaobject Protocol" "metaobject_protocol") + ("macro" "macro") + ("macro character" "macro_character") + ("macro expansion" "macro_expansion") + ("macro form" "macro_form") + ("macro function" "macro_function") + ("macro lambda list" "macro_lambda_list") + ("macro name" "macro_name") + ("macroexpand hook" "macroexpand_hook") + ("mapping" "mapping") + ("metaclass" "metaclass") + ("method" "method") + ("method combination" "method_combination") + ("method-defining form" "method-defining_form") + ("method-defining operator" "method-defining_operator") + ("minimal compilation" "minimal_compilation") + ("modified lambda list" "modified_lambda_list") + ("most recent" "most_recent") + ("multiple escape" "multiple_escape") + ("multiple values" "multiple_values") + ("name" "name") + ("named constant" "named_constant") + ("namespace" "namespace") + ("namestring" "namestring") + ("newline" "newline") + ("next method" "next_method") + ("nickname" "nickname") + ("nil" "nil") + ("non-atomic" "non-atomic") + ("non-constant variable" "non-constant_variable") + ("non-correctable" "non-correctable") + ("non-empty" "non-empty") + ("non-generic function" "non-generic_function") + ("non-graphic" "non-graphic") + ("non-list" "non-list") + ("non-local exit" "non-local_exit") + ("non-nil" "non-nil") + ("non-null lexical environment" "non-null_lexical_environment") + ("non-simple" "non-simple") + ("non-terminating" "non-terminating") + ("non-top-level form" "non-top-level_form") + ("normal return" "normal_return") + ("normalized" "normalized") + ("null" "null") + ("null lexical environment" "null_lexical_environment") + ("number" "number") + ("numeric" "numeric") + ("object" "object") + ("object-traversing" "object-traversing") + ("open" "open") + ("operator" "operator") + ("optimize quality" "optimize_quality") + ("optional parameter" "optional_parameter") + ("ordinary function" "ordinary_function") + ("ordinary lambda list" "ordinary_lambda_list") + ("otherwise inaccessible part" "otherwise_inaccessible_part") + ("output" "output") + ("package" "package") + ("package cell" "package_cell") + ("package designator" "package_designator") + ("package marker" "package_marker") + ("package prefix" "package_prefix") + ("package registry" "package_registry") + ("pairwise" "pairwise") + ("parallel" "parallel") + ("parameter" "parameter") + ("parameter specializer" "parameter_specializer") + ("parameter specializer name" "parameter_specializer_name") + ("pathname" "pathname") + ("pathname designator" "pathname_designator") + ("physical pathname" "physical_pathname") + ("place" "place") + ("plist" "plist") + ("portable" "portable") + ("potential copy" "potential_copy") + ("potential number" "potential_number") + ("pprint dispatch table" "pprint_dispatch_table") + ("predicate" "predicate") + ("present" "present") + ("pretty print" "pretty_print") + ("pretty printer" "pretty_printer") + ("pretty printing stream" "pretty_printing_stream") + ("primary method" "primary_method") + ("primary value" "primary_value") + ("principal" "principal") + ("print name" "print_name") + ("printer control variable" "printer_control_variable") + ("printer escaping" "printer_escaping") + ("printing" "printing") + ("process" "process") + ("processor" "processor") + ("proclaim" "proclaim") + ("proclamation" "proclamation") + ("prog tag" "prog_tag") + ("program" "program") + ("programmer" "programmer") + ("programmer code" "programmer_code") + ("proper list" "proper_list") + ("proper name" "proper_name") + ("proper sequence" "proper_sequence") + ("proper subtype" "proper_subtype") + ("property" "property") + ("property indicator" "property_indicator") + ("property list" "property_list") + ("property value" "property_value") + ("purports to conform" "purports_to_conform") + ("qualified method" "qualified_method") + ("qualifier" "qualifier") + ("query I/O" "query_iSLo") + ("quoted object" "quoted_object") + ("radix" "radix") + ("random state" "random_state") + ("rank" "rank") + ("ratio" "ratio") + ("ratio marker" "ratio_marker") + ("rational" "rational") + ("read" "read") + ("readably" "readably") + ("reader" "reader") + ("reader macro" "reader_macro") + ("reader macro function" "reader_macro_function") + ("readtable" "readtable") + ("readtable case" "readtable_case") + ("readtable designator" "readtable_designator") + ("recognizable subtype" "recognizable_subtype") + ("reference" "reference") + ("registered package" "registered_package") + ("relative" "relative") + ("repertoire" "repertoire") + ("report" "report") + ("report message" "report_message") + ("required parameter" "required_parameter") + ("rest list" "rest_list") + ("rest parameter" "rest_parameter") + ("restart" "restart") + ("restart designator" "restart_designator") + ("restart function" "restart_function") + ("return" "return") + ("return value" "return_value") + ("right-parenthesis" "right-parenthesis") + ("run time" "run_time") + ("run-time compiler" "run-time_compiler") + ("run-time definition" "run-time_definition") + ("run-time environment" "run-time_environment") + ("safe" "safe") + ("safe call" "safe_call") + ("same" "same") + ("satisfy the test" "satisfy_the_test") + ("scope" "scope") + ("script" "script") + ("secondary value" "secondary_value") + ("section" "section") + ("self-evaluating object" "self-evaluating_object") + ("semi-standard" "semi-standard") + ("semicolon" "semicolon") + ("sequence" "sequence") + ("sequence function" "sequence_function") + ("sequential" "sequential") + ("sequentially" "sequentially") + ("serious condition" "serious_condition") + ("session" "session") + ("set" "set") + ("setf expander" "setf_expander") + ("setf expansion" "setf_expansion") + ("setf function" "setf_function") + ("setf function name" "setf_function_name") + ("shadow" "shadow") + ("shadowing symbol" "shadowing_symbol") + ("shadowing symbols list" "shadowing_symbols_list") + ("shared slot" "shared_slot") + ("sharpsign" "sharpsign") + ("short float" "short_float") + ("sign" "sign") + ("signal" "signal") + ("signature" "signature") + ("similar" "similar") + ("similarity" "similarity") + ("simple" "simple") + ("simple array" "simple_array") + ("simple bit array" "simple_bit_array") + ("simple bit vector" "simple_bit_vector") + ("simple condition" "simple_condition") + ("simple general vector" "simple_general_vector") + ("simple string" "simple_string") + ("simple vector" "simple_vector") + ("single escape" "single_escape") + ("single float" "single_float") + ("single-quote" "single-quote") + ("singleton" "singleton") + ("situation" "situation") + ("slash" "slash") + ("slot" "slot") + ("slot specifier" "slot_specifier") + ("source code" "source_code") + ("source file" "source_file") + ("space" "space") + ("special form" "special_form") + ("special operator" "special_operator") + ("special variable" "special_variable") + ("specialize" "specialize") + ("specialized" "specialized") + ("specialized lambda list" "specialized_lambda_list") + ("spreadable argument list designator" "spreadable_argument_list_designator") + ("stack allocate" "stack_allocate") + ("stack-allocated" "stack-allocated") + ("standard character" "standard_character") + ("standard class" "standard_class") + ("standard generic function" "standard_generic_function") + ("standard input" "standard_input") + ("standard method combination" "standard_method_combination") + ("standard object" "standard_object") + ("standard output" "standard_output") + ("standard pprint dispatch table" "standard_pprint_dispatch_table") + ("standard readtable" "standard_readtable") + ("standard syntax" "standard_syntax") + ("standardized" "standardized") + ("startup environment" "startup_environment") + ("step" "step") + ("stream" "stream") + ("stream associated with a file" "stream_associated_with_a_file") + ("stream designator" "stream_designator") + ("stream element type" "stream_element_type") + ("stream variable" "stream_variable") + ("stream variable designator" "stream_variable_designator") + ("string" "string") + ("string designator" "string_designator") + ("string equal" "string_equal") + ("string stream" "string_stream") + ("structure" "structure") + ("structure class" "structure_class") + ("structure name" "structure_name") + ("style warning" "style_warning") + ("subclass" "subclass") + ("subexpression" "subexpression") + ("subform" "subform") + ("subrepertoire" "subrepertoire") + ("subtype" "subtype") + ("superclass" "superclass") + ("supertype" "supertype") + ("supplied-p parameter" "supplied-p_parameter") + ("symbol" "symbol") + ("symbol macro" "symbol_macro") + ("synonym stream" "synonym_stream") + ("synonym stream symbol" "synonym_stream_symbol") + ("syntax type" "syntax_type") + ("system class" "system_class") + ("system code" "system_code") + ("t" "t") + ("tag" "tag") + ("tail" "tail") + ("target" "target") + ("terminal I/O" "terminal_iSLo") + ("terminating" "terminating") + ("tertiary value" "tertiary_value") + ("throw" "throw") + ("tilde" "tilde") + ("time" "time") + ("time zone" "time_zone") + ("token" "token") + ("top level form" "top_level_form") + ("trace output" "trace_output") + ("tree" "tree") + ("tree structure" "tree_structure") + ("true" "true") + ("truename" "truename") + ("two-way stream" "two-way_stream") + ("type" "type") + ("type declaration" "type_declaration") + ("type equivalent" "type_equivalent") + ("type expand" "type_expand") + ("type specifier" "type_specifier") + ("unbound" "unbound") + ("unbound variable" "unbound_variable") + ("undefined function" "undefined_function") + ("unintern" "unintern") + ("uninterned" "uninterned") + ("universal time" "universal_time") + ("unqualified method" "unqualified_method") + ("unregistered package" "unregistered_package") + ("unsafe" "unsafe") + ("unsafe call" "unsafe_call") + ("upgrade" "upgrade") + ("upgraded array element type" "upgraded_array_element_type") + ("upgraded complex part type" "upgraded_complex_part_type") + ("uppercase" "uppercase") + ("use" "use") + ("use list" "use_list") + ("user" "user") + ("valid array dimension" "valid_array_dimension") + ("valid array index" "valid_array_index") + ("valid array row-major index" "valid_array_row-major_index") + ("valid fill pointer" "valid_fill_pointer") + ("valid logical pathname host" "valid_logical_pathname_host") + ("valid pathname device" "valid_pathname_device") + ("valid pathname directory" "valid_pathname_directory") + ("valid pathname host" "valid_pathname_host") + ("valid pathname name" "valid_pathname_name") + ("valid pathname type" "valid_pathname_type") + ("valid pathname version" "valid_pathname_version") + ("valid physical pathname host" "valid_physical_pathname_host") + ("valid sequence index" "valid_sequence_index") + ("value" "value") + ("value cell" "value_cell") + ("variable" "variable") + ("vector" "vector") + ("vertical-bar" "vertical-bar") + ("whitespace" "whitespace") + ("wild" "wild") + ("write" "write") + ("writer" "writer") + ("yield" "yield"))) + +(defun common-lisp-hyperspec-glossary-term (term) + "View the definition of TERM on the Common Lisp Hyperspec." + (interactive + (list + (completing-read "Look up glossary term: " + common-lisp-hyperspec--glossary-terms nil t))) + (browse-url (funcall common-lisp-hyperspec-glossary-function term))) + +(defun common-lisp-glossary-6.0 (term) + "Get a URL for a glossary term TERM." + (let ((anchor (gethash term common-lisp-hyperspec--glossary-terms))) + (if (not anchor) + (message "Unknown glossary term: %s" term) + (format "%sBody/26_glo_%s.htm#%s" + common-lisp-hyperspec-root + (let ((char (string-to-char term))) + (if (and (<= ?a char) + (<= char ?z)) + (make-string 1 char) + "9")) + anchor)))) + +;; Tianxiang Xiong 20151229 +;; Is this function necessary? The link does created does not work. +(defun common-lisp-glossary-4.0 (string) + (format "%sBody/glo_%s.html#%s" + common-lisp-hyperspec-root + (let ((char (string-to-char string))) + (if (and (<= ?a char) + (<= char ?z)) + (make-string 1 char) + "9")) + (subst-char-in-string ?\ ?_ string))) + + +;;;; Issuex + +;; FIXME: the issuex stuff is not used +(defvar common-lisp-hyperspec-issuex-table nil + "The HyperSpec IssueX table file. If you copy the HyperSpec to your +local system, set this variable to the location of the Issue +cross-references table which is usually \"Map_IssX.txt\" or +\"Issue-Cross-Refs.text\".") + +(defvar common-lisp-hyperspec--issuex-symbols + (make-hash-table :test 'equal)) + +(mapc + (lambda (entry) + (puthash (car entry) (cadr entry) common-lisp-hyperspec--issuex-symbols)) + (if common-lisp-hyperspec-issuex-table + (common-lisp-hyperspec--parse-map-file + common-lisp-hyperspec-issuex-table) + '(("&environment-binding-order:first" "iss001.htm") + ("access-error-name" "iss002.htm") + ("adjust-array-displacement" "iss003.htm") + ("adjust-array-fill-pointer" "iss004.htm") + ("adjust-array-not-adjustable:implicit-copy" "iss005.htm") + ("allocate-instance:add" "iss006.htm") + ("allow-local-inline:inline-notinline" "iss007.htm") + ("allow-other-keys-nil:permit" "iss008.htm") + ("aref-1d" "iss009.htm") + ("argument-mismatch-error-again:consistent" "iss010.htm") + ("argument-mismatch-error-moon:fix" "iss011.htm") + ("argument-mismatch-error:more-clarifications" "iss012.htm") + ("arguments-underspecified:specify" "iss013.htm") + ("array-dimension-limit-implications:all-fixnum" "iss014.htm") + ("array-type-element-type-semantics:unify-upgrading" "iss015.htm") + ("assert-error-type:error" "iss016.htm") + ("assoc-rassoc-if-key" "iss017.htm") + ("assoc-rassoc-if-key:yes" "iss018.htm") + ("boa-aux-initialization:error-on-read" "iss019.htm") + ("break-on-warnings-obsolete:remove" "iss020.htm") + ("broadcast-stream-return-values:clarify-minimally" "iss021.htm") + ("butlast-negative:should-signal" "iss022.htm") + ("change-class-initargs:permit" "iss023.htm") + ("char-name-case:x3j13-mar-91" "iss024.htm") + ("character-loose-ends:fix" "iss025.htm") + ("character-proposal:2" "iss026.htm") + ("character-proposal:2-1-1" "iss027.htm") + ("character-proposal:2-1-2" "iss028.htm") + ("character-proposal:2-2-1" "iss029.htm") + ("character-proposal:2-3-1" "iss030.htm") + ("character-proposal:2-3-2" "iss031.htm") + ("character-proposal:2-3-3" "iss032.htm") + ("character-proposal:2-3-4" "iss033.htm") + ("character-proposal:2-3-5" "iss034.htm") + ("character-proposal:2-3-6" "iss035.htm") + ("character-proposal:2-4-1" "iss036.htm") + ("character-proposal:2-4-2" "iss037.htm") + ("character-proposal:2-4-3" "iss038.htm") + ("character-proposal:2-5-2" "iss039.htm") + ("character-proposal:2-5-6" "iss040.htm") + ("character-proposal:2-5-7" "iss041.htm") + ("character-proposal:2-6-1" "iss042.htm") + ("character-proposal:2-6-2" "iss043.htm") + ("character-proposal:2-6-3" "iss044.htm") + ("character-proposal:2-6-5" "iss045.htm") + ("character-vs-char:less-inconsistent-short" "iss046.htm") + ("class-object-specializer:affirm" "iss047.htm") + ("clos-conditions-again:allow-subset" "iss048.htm") + ("clos-conditions:integrate" "iss049.htm") + ("clos-error-checking-order:no-applicable-method-first" "iss050.htm") + ("clos-macro-compilation:minimal" "iss051.htm") + ("close-constructed-stream:argument-stream-only" "iss052.htm") + ("closed-stream-operations:allow-inquiry" "iss053.htm") + ("coercing-setf-name-to-function:all-function-names" "iss054.htm") + ("colon-number" "iss055.htm") + ("common-features:specify" "iss056.htm") + ("common-type:remove" "iss057.htm") + ("compile-argument-problems-again:fix" "iss058.htm") + ("compile-file-handling-of-top-level-forms:clarify" "iss059.htm") + ("compile-file-output-file-defaults:input-file" "iss060.htm") + ("compile-file-package" "iss061.htm") + ("compile-file-pathname-arguments:make-consistent" "iss062.htm") + ("compile-file-symbol-handling:new-require-consistency" "iss063.htm") + ("compiled-function-requirements:tighten" "iss064.htm") + ("compiler-diagnostics:use-handler" "iss065.htm") + ("compiler-let-confusion:eliminate" "iss066.htm") + ("compiler-verbosity:like-load" "iss067.htm") + ("compiler-warning-stream" "iss068.htm") + ("complex-atan-branch-cut:tweak" "iss069.htm") + ("complex-atanh-bogus-formula:tweak-more" "iss070.htm") + ("complex-rational-result:extend" "iss071.htm") + ("compute-applicable-methods:generic" "iss072.htm") + ("concatenate-sequence:signal-error" "iss073.htm") + ("condition-accessors-setfable:no" "iss074.htm") + ("condition-restarts:buggy" "iss075.htm") + ("condition-restarts:permit-association" "iss076.htm") + ("condition-slots:hidden" "iss077.htm") + ("cons-type-specifier:add" "iss078.htm") + ("constant-circular-compilation:yes" "iss079.htm") + ("constant-collapsing:generalize" "iss080.htm") + ("constant-compilable-types:specify" "iss081.htm") + ("constant-function-compilation:no" "iss082.htm") + ("constant-modification:disallow" "iss083.htm") + ("constantp-definition:intentional" "iss084.htm") + ("constantp-environment:add-arg" "iss085.htm") + ("contagion-on-numerical-comparisons:transitive" "iss086.htm") + ("copy-symbol-copy-plist:copy-list" "iss087.htm") + ("copy-symbol-print-name:equal" "iss088.htm") + ("data-io:add-support" "iss089.htm") + ("data-types-hierarchy-underspecified" "iss090.htm") + ("debugger-hook-vs-break:clarify" "iss091.htm") + ("declaration-scope:no-hoisting" "iss092.htm") + ("declare-array-type-element-references:restrictive" "iss093.htm") + ("declare-function-ambiguity:delete-ftype-abbreviation" "iss094.htm") + ("declare-macros:flush" "iss095.htm") + ("declare-type-free:lexical" "iss096.htm") + ("decls-and-doc" "iss097.htm") + ("decode-universal-time-daylight:like-encode" "iss098.htm") + ("defconstant-special:no" "iss099.htm") + ("defgeneric-declare:allow-multiple" "iss100.htm") + ("define-compiler-macro:x3j13-nov89" "iss101.htm") + ("define-condition-syntax:\ +incompatibly-more-like-defclass+emphasize-read-only" "iss102.htm") + ("define-method-combination-behavior:clarify" "iss103.htm") + ("defining-macros-non-top-level:allow" "iss104.htm") + ("defmacro-block-scope:excludes-bindings" "iss105.htm") + ("defmacro-lambda-list:tighten-description" "iss106.htm") + ("defmethod-declaration-scope:corresponds-to-bindings" "iss107.htm") + ("defpackage:addition" "iss108.htm") + ("defstruct-constructor-key-mixture:allow-key" "iss109.htm") + ("defstruct-constructor-options:explicit" "iss110.htm") + ("defstruct-constructor-slot-variables:not-bound" "iss111.htm") + ("defstruct-copier-argument-type:restrict" "iss112.htm") + ("defstruct-copier:argument-type" "iss113.htm") + ("defstruct-default-value-evaluation:iff-needed" "iss114.htm") + ("defstruct-include-deftype:explicitly-undefined" "iss115.htm") + ("defstruct-print-function-again:x3j13-mar-93" "iss116.htm") + ("defstruct-print-function-inheritance:yes" "iss117.htm") + ("defstruct-redefinition:error" "iss118.htm") + ("defstruct-slots-constraints-name:duplicates-error" "iss119.htm") + ("defstruct-slots-constraints-number" "iss120.htm") + ("deftype-destructuring:yes" "iss121.htm") + ("deftype-key:allow" "iss122.htm") + ("defvar-documentation:unevaluated" "iss123.htm") + ("defvar-init-time:not-delayed" "iss124.htm") + ("defvar-initialization:conservative" "iss125.htm") + ("deprecation-position:limited" "iss126.htm") + ("describe-interactive:no" "iss127.htm") + ("describe-underspecified:describe-object" "iss128.htm") + ("destructive-operations:specify" "iss129.htm") + ("destructuring-bind:new-macro" "iss130.htm") + ("disassemble-side-effect:do-not-install" "iss131.htm") + ("displaced-array-predicate:add" "iss132.htm") + ("do-symbols-block-scope:entire-form" "iss133.htm") + ("do-symbols-duplicates" "iss134.htm") + ("documentation-function-bugs:fix" "iss135.htm") + ("documentation-function-tangled:require-argument" "iss136.htm") + ("dotimes-ignore:x3j13-mar91" "iss137.htm") + ("dotted-list-arguments:clarify" "iss138.htm") + ("dotted-macro-forms:allow" "iss139.htm") + ("dribble-technique" "iss140.htm") + ("dynamic-extent-function:extend" "iss141.htm") + ("dynamic-extent:new-declaration" "iss142.htm") + ("equal-structure:maybe-status-quo" "iss143.htm") + ("error-terminology-warning:might" "iss144.htm") + ("eval-other:self-evaluate" "iss145.htm") + ("eval-top-level:load-like-compile-file" "iss146.htm") + ("eval-when-non-top-level:generalize-eval-new-keywords" "iss147.htm") + ("eval-when-obsolete-keywords:x3j13-mar-1993" "iss148.htm") + ("evalhook-step-confusion:fix" "iss149.htm") + ("evalhook-step-confusion:x3j13-nov-89" "iss150.htm") + ("exit-extent-and-condition-system:like-dynamic-bindings" "iss151.htm") + ("exit-extent:minimal" "iss152.htm") + ("expt-ratio:p.211" "iss153.htm") + ("extensions-position:documentation" "iss154.htm") + ("external-format-for-every-file-connection:minimum" "iss155.htm") + ("extra-return-values:no" "iss156.htm") + ("file-open-error:signal-file-error" "iss157.htm") + ("fixnum-non-portable:tighten-definition" "iss158.htm") + ("flet-declarations" "iss159.htm") + ("flet-declarations:allow" "iss160.htm") + ("flet-implicit-block:yes" "iss161.htm") + ("float-underflow:add-variables" "iss162.htm") + ("floating-point-condition-names:x3j13-nov-89" "iss163.htm") + ("format-atsign-colon" "iss164.htm") + ("format-colon-uparrow-scope" "iss165.htm") + ("format-comma-interval" "iss166.htm") + ("format-e-exponent-sign:force-sign" "iss167.htm") + ("format-op-c" "iss168.htm") + ("format-pretty-print:yes" "iss169.htm") + ("format-string-arguments:specify" "iss170.htm") + ("function-call-evaluation-order:more-unspecified" "iss171.htm") + ("function-composition:jan89-x3j13" "iss172.htm") + ("function-definition:jan89-x3j13" "iss173.htm") + ("function-name:large" "iss174.htm") + ("function-type" "iss175.htm") + ("function-type-argument-type-semantics:restrictive" "iss176.htm") + ("function-type-key-name:specify-keyword" "iss177.htm") + ("function-type-rest-list-element:use-actual-argument-type" "iss178.htm") + ("function-type:x3j13-march-88" "iss179.htm") + ("generalize-pretty-printer:unify" "iss180.htm") + ("generic-flet-poorly-designed:delete" "iss181.htm") + ("gensym-name-stickiness:like-teflon" "iss182.htm") + ("gentemp-bad-idea:deprecate" "iss183.htm") + ("get-macro-character-readtable:nil-standard" "iss184.htm") + ("get-setf-method-environment:add-arg" "iss185.htm") + ("hash-table-access:x3j13-mar-89" "iss186.htm") + ("hash-table-key-modification:specify" "iss187.htm") + ("hash-table-package-generators:add-with-wrapper" "iss188.htm") + ("hash-table-rehash-size-integer" "iss189.htm") + ("hash-table-size:intended-entries" "iss190.htm") + ("hash-table-tests:add-equalp" "iss191.htm") + ("ieee-atan-branch-cut:split" "iss192.htm") + ("ignore-use-terminology:value-only" "iss193.htm") + ("import-setf-symbol-package" "iss194.htm") + ("in-package-functionality:mar89-x3j13" "iss195.htm") + ("in-syntax:minimal" "iss196.htm") + ("initialization-function-keyword-checking" "iss197.htm") + ("iso-compatibility:add-substrate" "iss198.htm") + ("jun90-trivial-issues:11" "iss199.htm") + ("jun90-trivial-issues:14" "iss200.htm") + ("jun90-trivial-issues:24" "iss201.htm") + ("jun90-trivial-issues:25" "iss202.htm") + ("jun90-trivial-issues:27" "iss203.htm") + ("jun90-trivial-issues:3" "iss204.htm") + ("jun90-trivial-issues:4" "iss205.htm") + ("jun90-trivial-issues:5" "iss206.htm") + ("jun90-trivial-issues:9" "iss207.htm") + ("keyword-argument-name-package:any" "iss208.htm") + ("last-n" "iss209.htm") + ("lcm-no-arguments:1" "iss210.htm") + ("lexical-construct-global-definition:undefined" "iss211.htm") + ("lisp-package-name:common-lisp" "iss212.htm") + ("lisp-symbol-redefinition-again:more-fixes" "iss213.htm") + ("lisp-symbol-redefinition:mar89-x3j13" "iss214.htm") + ("load-objects:make-load-form" "iss215.htm") + ("load-time-eval:r**2-new-special-form" "iss216.htm") + ("load-time-eval:r**3-new-special-form" "iss217.htm") + ("load-truename:new-pathname-variables" "iss218.htm") + ("locally-top-level:special-form" "iss219.htm") + ("loop-and-discrepancy:no-reiteration" "iss220.htm") + ("loop-for-as-on-typo:fix-typo" "iss221.htm") + ("loop-initform-environment:partial-interleaving-vague" "iss222.htm") + ("loop-miscellaneous-repairs:fix" "iss223.htm") + ("loop-named-block-nil:override" "iss224.htm") + ("loop-present-symbols-typo:flush-wrong-words" "iss225.htm") + ("loop-syntax-overhaul:repair" "iss226.htm") + ("macro-as-function:disallow" "iss227.htm") + ("macro-declarations:make-explicit" "iss228.htm") + ("macro-environment-extent:dynamic" "iss229.htm") + ("macro-function-environment" "iss230.htm") + ("macro-function-environment:yes" "iss231.htm") + ("macro-subforms-top-level-p:add-constraints" "iss232.htm") + ("macroexpand-hook-default:explicitly-vague" "iss233.htm") + ("macroexpand-hook-initial-value:implementation-dependent" "iss234.htm") + ("macroexpand-return-value:true" "iss235.htm") + ("make-load-form-confusion:rewrite" "iss236.htm") + ("make-load-form-saving-slots:no-initforms" "iss237.htm") + ("make-package-use-default:implementation-dependent" "iss238.htm") + ("map-into:add-function" "iss239.htm") + ("mapping-destructive-interaction:explicitly-vague" "iss240.htm") + ("metaclass-of-system-class:unspecified" "iss241.htm") + ("method-combination-arguments:clarify" "iss242.htm") + ("method-initform:forbid-call-next-method" "iss243.htm") + ("muffle-warning-condition-argument" "iss244.htm") + ("multiple-value-setq-order:like-setf-of-values" "iss245.htm") + ("multiple-values-limit-on-variables:undefined" "iss246.htm") + ("nintersection-destruction" "iss247.htm") + ("nintersection-destruction:revert" "iss248.htm") + ("not-and-null-return-value:x3j13-mar-93" "iss249.htm") + ("nth-value:add" "iss250.htm") + ("optimize-debug-info:new-quality" "iss251.htm") + ("package-clutter:reduce" "iss252.htm") + ("package-deletion:new-function" "iss253.htm") + ("package-function-consistency:more-permissive" "iss254.htm") + ("parse-error-stream:split-types" "iss255.htm") + ("pathname-component-case:keyword-argument" "iss256.htm") + ("pathname-component-value:specify" "iss257.htm") + ("pathname-host-parsing:recognize-logical-host-names" "iss258.htm") + ("pathname-logical:add" "iss259.htm") + ("pathname-print-read:sharpsign-p" "iss260.htm") + ("pathname-stream" "iss261.htm") + ("pathname-stream:files-or-synonym" "iss262.htm") + ("pathname-subdirectory-list:new-representation" "iss263.htm") + ("pathname-symbol" "iss264.htm") + ("pathname-syntax-error-time:explicitly-vague" "iss265.htm") + ("pathname-unspecific-component:new-token" "iss266.htm") + ("pathname-wild:new-functions" "iss267.htm") + ("peek-char-read-char-echo:first-read-char" "iss268.htm") + ("plist-duplicates:allow" "iss269.htm") + ("pretty-print-interface" "iss270.htm") + ("princ-readably:x3j13-dec-91" "iss271.htm") + ("print-case-behavior:clarify" "iss272.htm") + ("print-case-print-escape-interaction:vertical-bar-rule-no-upcase" + "iss273.htm") + ("print-circle-shared:respect-print-circle" "iss274.htm") + ("print-circle-structure:user-functions-work" "iss275.htm") + ("print-readably-behavior:clarify" "iss276.htm") + ("printer-whitespace:just-one-space" "iss277.htm") + ("proclaim-etc-in-compile-file:new-macro" "iss278.htm") + ("push-evaluation-order:first-item" "iss279.htm") + ("push-evaluation-order:item-first" "iss280.htm") + ("pushnew-store-required:unspecified" "iss281.htm") + ("quote-semantics:no-copying" "iss282.htm") + ("range-of-count-keyword:nil-or-integer" "iss283.htm") + ("range-of-start-and-end-parameters:integer-and-integer-nil" "iss284.htm") + ("read-and-write-bytes:new-functions" "iss285.htm") + ("read-case-sensitivity:readtable-keywords" "iss286.htm") + ("read-modify-write-evaluation-order:delayed-access-stores" "iss287.htm") + ("read-suppress-confusing:generalize" "iss288.htm") + ("reader-error:new-type" "iss289.htm") + ("real-number-type:x3j13-mar-89" "iss290.htm") + ("recursive-deftype:explicitly-vague" "iss291.htm") + ("reduce-argument-extraction" "iss292.htm") + ("remf-destruction-unspecified:x3j13-mar-89" "iss293.htm") + ("require-pathname-defaults-again:x3j13-dec-91" "iss294.htm") + ("require-pathname-defaults-yet-again:restore-argument" "iss295.htm") + ("require-pathname-defaults:eliminate" "iss296.htm") + ("rest-list-allocation:may-share" "iss297.htm") + ("result-lists-shared:specify" "iss298.htm") + ("return-values-unspecified:specify" "iss299.htm") + ("room-default-argument:new-value" "iss300.htm") + ("self-modifying-code:forbid" "iss301.htm") + ("sequence-type-length:must-match" "iss302.htm") + ("setf-apply-expansion:ignore-expander" "iss303.htm") + ("setf-find-class:allow-nil" "iss304.htm") + ("setf-functions-again:minimal-changes" "iss305.htm") + ("setf-get-default:evaluated-but-ignored" "iss306.htm") + ("setf-macro-expansion:last" "iss307.htm") + ("setf-method-vs-setf-method:rename-old-terms" "iss308.htm") + ("setf-multiple-store-variables:allow" "iss309.htm") + ("setf-of-apply:only-aref-and-friends" "iss310.htm") + ("setf-of-values:add" "iss311.htm") + ("setf-sub-methods:delayed-access-stores" "iss312.htm") + ("shadow-already-present" "iss313.htm") + ("shadow-already-present:works" "iss314.htm") + ("sharp-comma-confusion:remove" "iss315.htm") + ("sharp-o-foobar:consequences-undefined" "iss316.htm") + ("sharp-star-delimiter:normal-delimiter" "iss317.htm") + ("sharpsign-plus-minus-package:keyword" "iss318.htm") + ("slot-missing-values:specify" "iss319.htm") + ("slot-value-metaclasses:less-minimal" "iss320.htm") + ("special-form-p-misnomer:rename" "iss321.htm") + ("special-type-shadowing:clarify" "iss322.htm") + ("standard-input-initial-binding:defined-contracts" "iss323.htm") + ("standard-repertoire-gratuitous:rename" "iss324.htm") + ("step-environment:current" "iss325.htm") + ("step-minimal:permit-progn" "iss326.htm") + ("stream-access:add-types-accessors" "iss327.htm") + ("stream-capabilities:interactive-stream-p" "iss328.htm") + ("string-coercion:make-consistent" "iss329.htm") + ("string-output-stream-bashing:undefined" "iss330.htm") + ("structure-read-print-syntax:keywords" "iss331.htm") + ("subseq-out-of-bounds" "iss332.htm") + ("subseq-out-of-bounds:is-an-error" "iss333.htm") + ("subsetting-position:none" "iss334.htm") + ("subtypep-environment:add-arg" "iss335.htm") + ("subtypep-too-vague:clarify-more" "iss336.htm") + ("sxhash-definition:similar-for-sxhash" "iss337.htm") + ("symbol-macrolet-declare:allow" "iss338.htm") + ("symbol-macrolet-semantics:special-form" "iss339.htm") + ("symbol-macrolet-type-declaration:no" "iss340.htm") + ("symbol-macros-and-proclaimed-specials:signals-an-error" "iss341.htm") + ("symbol-print-escape-behavior:clarify" "iss342.htm") + ("syntactic-environment-access:retracted-mar91" "iss343.htm") + ("tagbody-tag-expansion:no" "iss344.htm") + ("tailp-nil:t" "iss345.htm") + ("test-not-if-not:flush-all" "iss346.htm") + ("the-ambiguity:for-declaration" "iss347.htm") + ("the-values:return-number-received" "iss348.htm") + ("time-zone-non-integer:allow" "iss349.htm") + ("type-declaration-abbreviation:allow-all" "iss350.htm") + ("type-of-and-predefined-classes:type-of-handles-floats" "iss351.htm") + ("type-of-and-predefined-classes:unify-and-extend" "iss352.htm") + ("type-of-underconstrained:add-constraints" "iss353.htm") + ("type-specifier-abbreviation:x3j13-jun90-guess" "iss354.htm") + ("undefined-variables-and-functions:compromise" "iss355.htm") + ("uninitialized-elements:consequences-undefined" "iss356.htm") + ("unread-char-after-peek-char:dont-allow" "iss357.htm") + ("unsolicited-messages:not-to-system-user-streams" "iss358.htm") + ("variable-list-asymmetry:symmetrize" "iss359.htm") + ("with-added-methods:delete" "iss360.htm") + ("with-compilation-unit:new-macro" "iss361.htm") + ("with-open-file-does-not-exist:stream-is-nil" "iss362.htm") + ("with-open-file-setq:explicitly-vague" "iss363.htm") + ("with-open-file-stream-extent:dynamic-extent" "iss364.htm") + ("with-output-to-string-append-style:vector-push-extend" "iss365.htm") + ("with-standard-io-syntax-readtable:x3j13-mar-91" "iss366.htm")))) + +(defun common-lisp-issuex (issue-name) + (let ((entry (gethash (downcase issue-name) + common-lisp-hyperspec--issuex-symbols))) + (concat common-lisp-hyperspec-root "Issues/" entry))) + +(defun common-lisp-special-operator (name) + (format "%sBody/s_%s.htm" common-lisp-hyperspec-root name)) + +;;; Added the following just to provide a common entry point according +;;; to the various 'hyperspec' implementations. +;;; +;;; 19990820 Marco Antoniotti + +(defalias 'hyperspec-lookup 'common-lisp-hyperspec) +(defalias 'hyperspec-lookup-reader-macro + 'common-lisp-hyperspec-lookup-reader-macro) +(defalias 'hyperspec-lookup-format 'common-lisp-hyperspec-format) + +(provide 'hyperspec) + +;;; hyperspec.el ends here diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/lib/macrostep.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/lib/macrostep.el new file mode 100644 index 0000000..b301497 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/lib/macrostep.el @@ -0,0 +1,1122 @@ +;;; macrostep.el --- interactive macro expander + +;; Copyright (C) 2012-2015 Jon Oddie + +;; Author: joddie +;; Maintainer: joddie +;; Created: 16 January 2012 +;; Updated: 07 December 2015 +;; Version: 0.9 +;; Keywords: lisp, languages, macro, debugging +;; Url: https://github.com/joddie/macrostep +;; Package-Requires: ((cl-lib "0.5")) + +;; This file is NOT part of GNU Emacs. + +;; This program is free software: you can redistribute it and/or +;; modify it under the terms of the GNU General Public License as +;; published by the Free Software Foundation, either version 3 of the +;; License, or (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see `http://www.gnu.org/licenses/'. + +;;; Commentary: + +;; `macrostep' is an Emacs minor mode for interactively stepping through +;; the expansion of macros in Emacs Lisp source code. It lets you see +;; exactly what happens at each step of the expansion process by +;; pretty-printing the expanded forms inline in the source buffer, which is +;; temporarily read-only while macro expansions are visible. You can +;; expand and collapse macro forms one step at a time, and evaluate or +;; instrument the expansions for debugging with Edebug as normal (but see +;; "Bugs and known limitations", below). Single-stepping through the +;; expansion is particularly useful for debugging macros that expand into +;; another macro form. These can be difficult to debug with Emacs' +;; built-in `macroexpand', which continues expansion until the top-level +;; form is no longer a macro call. + +;; Both globally-visible macros as defined by `defmacro' and local macros +;; bound by `(cl-)macrolet' or another macro-defining form can be expanded. +;; Within macro expansions, calls to macros and compiler macros are +;; fontified specially: macro forms using `macrostep-macro-face', and +;; functions with compiler macros using `macrostep-compiler-macro-face'. +;; Uninterned symbols (gensyms) are fontified based on which step in the +;; expansion created them, to distinguish them both from normal symbols and +;; from other gensyms with the same print name. + +;; As of version 0.9, it is also possible to extend `macrostep' to work +;; with other languages with macro systems in addition to Emacs Lisp. An +;; extension for Common Lisp (via SLIME) is in the works; contributions for +;; other languages are welcome. See "Extending macrostep" below for +;; details. + + +;; 1 Key-bindings and usage +;; ======================== + +;; The standard keybindings in `macrostep-mode' are the following: + +;; e, =, RET : expand the macro form following point one step +;; c, u, DEL : collapse the form following point +;; q, C-c C-c: collapse all expanded forms and exit macrostep-mode +;; n, TAB : jump to the next macro form in the expansion +;; p, M-TAB : jump to the previous macro form in the expansion + +;; It's not very useful to enable and disable macrostep-mode directly. +;; Instead, bind `macrostep-expand' to a key in `emacs-lisp-mode-map', +;; for example C-c e: + +;; ,---- +;; | (define-key emacs-lisp-mode-map (kbd "C-c e") 'macrostep-expand) +;; `---- + +;; You can then enter macrostep-mode and expand a macro form completely +;; by typing `C-c e e e ...' as many times as necessary. + +;; Exit macrostep-mode by typing `q' or `C-c C-c', or by successively +;; typing `c' to collapse all surrounding expansions. + + +;; 2 Customization options +;; ======================= + +;; Type `M-x customize-group RET macrostep RET' to customize options and +;; faces. + +;; To display macro expansions in a separate window, instead of inline in +;; the source buffer, customize `macrostep-expand-in-separate-buffer' to +;; `t'. The default is `nil'. Whichever default behavior is selected, +;; the alternative behavior can be obtained temporarily by giving a +;; prefix argument to `macrostep-expand'. + +;; To have `macrostep' ignore compiler macros, customize +;; `macrostep-expand-compiler-macros' to `nil'. The default is `t'. + +;; Customize the faces `macrostep-macro-face', +;; `macrostep-compiler-macro-face', and `macrostep-gensym-1' through +;; `macrostep-gensym-5' to alter the appearance of macro expansions. + + +;; 3 Locally-bound macros +;; ====================== + +;; As of version 0.9, `macrostep' can expand calls to a locally-bound +;; macro, whether defined by a surrounding `(cl-)macrolet' form, or by +;; another macro-defining macro. In other words, it is possible to +;; expand the inner `local-macro' forms in both the following examples, +;; whether `local-macro' is defined by an enclosing `cl-macrolet' -- + +;; ,---- +;; | (cl-macrolet ((local-macro (&rest args) +;; | `(expansion of ,args))) +;; | (local-macro (do-something))) +;; `---- + +;; -- or by a macro which expands into `cl-macrolet', provided that its +;; definition of macro is evaluated prior to calling `macrostep-expand': + +;; ,---- +;; | (defmacro with-local-macro (&rest body) +;; | `(cl-macrolet ((local-macro (&rest args) +;; | `(expansion of ,args))) +;; | ,@body)) +;; | +;; | (with-local-macro +;; | (local-macro (do something (else))) +;; `---- + +;; See the `with-js' macro in Emacs's `js.el' for a real example of the +;; latter kind of macro. + +;; Expansion of locally-bound macros is implemented by instrumenting +;; Emacs Lisp's macro-expander to capture the environment at point. A +;; similar trick is used to detect macro- and compiler-macro calls within +;; expanded text so that they can be fontified accurately. + + +;; 4 Expanding sub-forms +;; ===================== + +;; By moving point around in the macro expansion using +;; `macrostep-next-macro' and `macrostep-prev-macro' (bound to the `n' +;; and `p' keys), it is possible to expand other macro calls within the +;; expansion before expanding the outermost form. This can sometimes be +;; useful, although it does not correspond to the real order of macro +;; expansion in Emacs Lisp, which proceeds by fully expanding the outer +;; form to a non-macro form before expanding sub-forms. + +;; The main reason to expand sub-forms out of order is to help with +;; debugging macros which programmatically expand their arguments in +;; order to rewrite them. Expanding the arguments of such a macro lets +;; you visualise what the macro definition would compute via +;; `macroexpand-all'. + + +;; 5 Extending macrostep for other languages +;; ========================================= + +;; Since version 0.9, it is possible to extend macrostep to work with +;; other languages besides Emacs Lisp. In typical Emacs fashion, this is +;; implemented by setting buffer-local variables to different function +;; values. Six buffer-local variables define the language-specific part +;; of the implementation: + +;; - `macrostep-sexp-bounds-function' +;; - `macrostep-sexp-at-point-function' +;; - `macrostep-environment-at-point-function' +;; - `macrostep-expand-1-function' +;; - `macrostep-print-function' +;; - `macrostep-macro-form-p-function' + +;; Typically, an implementation for another language would set these +;; variables in a major-mode hook. See the docstrings of each variable +;; for details on how each one is called and what it should return. At a +;; minimum, another language implementation needs to provide +;; `macrostep-sexp-at-point-function', `macrostep-expand-1-function', and +;; `macrostep-print-function'. Lisp-like languages may be able to reuse +;; the default `macrostep-sexp-bounds-function' if they provide another +;; implementation of `macrostep-macro-form-p-function'. Languages which +;; do not implement locally-defined macros can set +;; `macrostep-environment-at-point-function' to `ignore'. + +;; Note that the core `macrostep' machinery only interprets the return +;; value of `macrostep-sexp-bounds-function', so implementations for +;; other languages can use any internal representations of code and +;; environments which is convenient. Although the terminology is +;; Lisp-specific, there is no reason that implementations could not be +;; provided for non-Lisp languages with macro systems, provided there is +;; some way of identifying macro calls and calling the compiler / +;; preprocessor to obtain their expansions. + + +;; 6 Bugs and known limitations +;; ============================ + +;; You can evaluate and edebug macro-expanded forms and step through the +;; macro-expanded version, but the form that `eval-defun' and friends +;; read from the buffer won't have the uninterned symbols of the real +;; macro expansion. This will probably work OK with CL-style gensyms, +;; but may cause problems with `make-symbol' symbols if they have the +;; same print name as another symbol in the expansion. It's possible that +;; using `print-circle' and `print-gensym' could get around this. + +;; Please send other bug reports and feature requests to the author. + + +;; 7 Acknowledgements +;; ================== + +;; Thanks to: +;; - John Wiegley for fixing a bug with the face definitions under Emacs +;; 24 & for plugging macrostep in his [EmacsConf presentation]! +;; - George Kettleborough for bug reports, and patches to highlight the +;; expanded region and properly handle backquotes. +;; - Nic Ferrier for suggesting support for local definitions within +;; macrolet forms +;; - Luís Oliveira for suggesting and implementing SLIME support + +;; `macrostep' was originally inspired by J. V. Toups's 'Deep Emacs Lisp' +;; articles ([part 1], [part 2], [screencast]). + +;; [EmacsConf presentation] http://youtu.be/RvPFZL6NJNQ + +;; [part 1] +;; http://dorophone.blogspot.co.uk/2011/04/deep-emacs-part-1.html + +;; [part 2] +;; http://dorophone.blogspot.co.uk/2011/04/deep-emacs-lisp-part-2.html + +;; [screencast] +;; http://dorophone.blogspot.co.uk/2011/05/monadic-parser-combinators-in-elisp.html + + +;; 8 Changelog +;; =========== + +;; - v0.9, 2015-10-01: +;; - separate into Elisp-specific and generic components +;; - highlight and expand compiler macros +;; - improve local macro expansion and macro form identification by +;; instrumenting `macroexpand(-all)' +;; - v0.8, 2014-05-29: fix a bug with printing the first element of lists +;; - v0.7, 2014-05-11: expand locally-defined macros within +;; `(cl-)macrolet' forms +;; - v0.6, 2013-05-04: better handling of quote and backquote +;; - v0.5, 2013-04-16: highlight region, maintain cleaner buffer state +;; - v0.4, 2013-04-07: only enter macrostep-mode on successful +;; macro-expansion +;; - v0.3, 2012-10-30: print dotted lists correctly. autoload +;; definitions. + +;;; Code: + +(require 'pp) +(require 'ring) +(eval-and-compile + (require 'cl-lib nil t) + (require 'cl-lib "lib/cl-lib")) + + +;;; Constants and dynamically bound variables +(defvar macrostep-overlays nil + "List of all macro stepper overlays in the current buffer.") +(make-variable-buffer-local 'macrostep-overlays) + +(defvar macrostep-gensym-depth nil + "Number of macro expansion levels that have introduced gensyms so far.") +(make-variable-buffer-local 'macrostep-gensym-depth) + +(defvar macrostep-gensyms-this-level nil + "t if gensyms have been encountered during current level of macro expansion.") +(make-variable-buffer-local 'macrostep-gensyms-this-level) + +(defvar macrostep-saved-undo-list nil + "Saved value of buffer-undo-list upon entering macrostep mode.") +(make-variable-buffer-local 'macrostep-saved-undo-list) + +(defvar macrostep-saved-read-only nil + "Saved value of buffer-read-only upon entering macrostep mode.") +(make-variable-buffer-local 'macrostep-saved-read-only) + +(defvar macrostep-expansion-buffer nil + "Non-nil if the current buffer is a macro-expansion buffer.") +(make-variable-buffer-local 'macrostep-expansion-buffer) + +(defvar macrostep-outer-environment nil + "Outermost macro-expansion environment to use in a dedicated macro-expansion buffers. + +This variable is used to save information about any enclosing +`cl-macrolet' context when a macro form is expanded in a separate +buffer.") +(make-variable-buffer-local 'macrostep-outer-environment) + +;;; Customization options and faces +(defgroup macrostep nil + "Interactive macro stepper for Emacs Lisp." + :group 'lisp + :link '(emacs-commentary-link :tag "commentary" "macrostep.el") + :link '(emacs-library-link :tag "lisp file" "macrostep.el") + :link '(url-link :tag "web page" "https://github.com/joddie/macrostep")) + +(defface macrostep-gensym-1 + '((((min-colors 16581375)) :foreground "#8080c0" :box t :bold t) + (((min-colors 8)) :background "cyan") + (t :inverse-video t)) + "Face for gensyms created in the first level of macro expansion." + :group 'macrostep) + +(defface macrostep-gensym-2 + '((((min-colors 16581375)) :foreground "#8fbc8f" :box t :bold t) + (((min-colors 8)) :background "#00cd00") + (t :inverse-video t)) + "Face for gensyms created in the second level of macro expansion." + :group 'macrostep) + +(defface macrostep-gensym-3 + '((((min-colors 16581375)) :foreground "#daa520" :box t :bold t) + (((min-colors 8)) :background "yellow") + (t :inverse-video t)) + "Face for gensyms created in the third level of macro expansion." + :group 'macrostep) + +(defface macrostep-gensym-4 + '((((min-colors 16581375)) :foreground "#cd5c5c" :box t :bold t) + (((min-colors 8)) :background "red") + (t :inverse-video t)) + "Face for gensyms created in the fourth level of macro expansion." + :group 'macrostep) + +(defface macrostep-gensym-5 + '((((min-colors 16581375)) :foreground "#da70d6" :box t :bold t) + (((min-colors 8)) :background "magenta") + (t :inverse-video t)) + "Face for gensyms created in the fifth level of macro expansion." + :group 'macrostep) + +(defface macrostep-expansion-highlight-face + '((((min-colors 16581375) (background light)) :background "#eee8d5") + (((min-colors 16581375) (background dark)) :background "#222222")) + "Face for macro-expansion highlight." + :group 'macrostep) + +(defface macrostep-macro-face + '((t :underline t)) + "Face for macros in macro-expanded code." + :group 'macrostep) + +(defface macrostep-compiler-macro-face + '((t :slant italic)) + "Face for compiler macros in macro-expanded code." + :group 'macrostep) + +(defcustom macrostep-expand-in-separate-buffer nil + "When non-nil, show expansions in a separate buffer instead of inline." + :group 'macrostep + :type 'boolean) + +(defcustom macrostep-expand-compiler-macros t + "When non-nil, expand compiler macros as well as `defmacro' and `macrolet' macros." + :group 'macrostep + :type 'boolean) + +;; Need the following for making the ring of faces +(defun macrostep-make-ring (&rest items) + "Make a ring containing all of ITEMS with no empty slots." + (let ((ring (make-ring (length items)))) + (mapc (lambda (item) (ring-insert ring item)) (reverse items)) + ring)) + +(defvar macrostep-gensym-faces + (macrostep-make-ring + 'macrostep-gensym-1 'macrostep-gensym-2 'macrostep-gensym-3 + 'macrostep-gensym-4 'macrostep-gensym-5) + "Ring of all macrostepper faces for fontifying gensyms.") + +;; Other modes can enable macrostep by redefining these functions to +;; language-specific versions. +(defvar macrostep-sexp-bounds-function + #'macrostep-sexp-bounds + "Function to return the bounds of the macro form nearest point. + +It will be called with no arguments and should return a cons of +buffer positions, (START . END). It should use `save-excursion' +to avoid changing the position of point. + +The default value, `macrostep-sexp-bounds', implements this for +Emacs Lisp, and may be suitable for other Lisp-like languages.") +(make-variable-buffer-local 'macrostep-sexp-bounds-function) + +(defvar macrostep-sexp-at-point-function + #'macrostep-sexp-at-point + "Function to return the macro form at point for expansion. + +It will be called with two arguments, the values of START and END +returned by `macrostep-sexp-bounds-function', and with point +positioned at START. It should return a value suitable for +passing as the first argument to `macrostep-expand-1-function'. + +The default value, `macrostep-sexp-at-point', implements this for +Emacs Lisp, and may be suitable for other Lisp-like languages.") +(make-variable-buffer-local 'macrostep-sexp-at-point-function) + +(defvar macrostep-environment-at-point-function + #'macrostep-environment-at-point + "Function to return the local macro-expansion environment at point. + +It will be called with no arguments, and should return a value +suitable for passing as the second argument to +`macrostep-expand-1-function'. + +The default value, `macrostep-environment-at-point', is specific +to Emacs Lisp. For languages which do not implement local +macro-expansion environments, this should be set to `ignore' +or `(lambda () nil)'.") +(make-variable-buffer-local 'macrostep-environment-at-point-function) + +(defvar macrostep-expand-1-function + #'macrostep-expand-1 + "Function to perform one step of macro-expansion. + +It will be called with two arguments, FORM and ENVIRONMENT, the +return values of `macrostep-sexp-at-point-function' and +`macrostep-environment-at-point-function' respectively. It +should return the result of expanding FORM by one step as a value +which is suitable for passing as the argument to +`macrostep-print-function'. + +The default value, `macrostep-expand-1', is specific to Emacs Lisp.") +(make-variable-buffer-local 'macrostep-expand-1-function) + +(defvar macrostep-print-function + #'macrostep-pp + "Function to pretty-print macro expansions. + +It will be called with two arguments, FORM and ENVIRONMENT, the +return values of `macrostep-sexp-at-point-function' and +`macrostep-environment-at-point-function' respectively. It +should insert a pretty-printed representation at point in the +current buffer, leaving point just after the inserted +representation, without altering any other text in the current +buffer. + +The default value, `macrostep-pp', is specific to Emacs Lisp.") +(make-variable-buffer-local 'macrostep-print-function) + +(defvar macrostep-macro-form-p-function + #'macrostep-macro-form-p + "Function to check whether a form is a macro call. + +It will be called with two arguments, FORM and ENVIRONMENT -- the +return values of `macrostep-sexp-at-point-function' and +`macrostep-environment-at-point-function' respectively -- and +should return non-nil if FORM would undergo macro-expansion in +ENVIRONMENT. + +This is called only from `macrostep-sexp-bounds', so it need not +be provided if a different value is used for +`macrostep-sexp-bounds-function'. + +The default value, `macrostep-macro-form-p', is specific to Emacs Lisp.") +(make-variable-buffer-local 'macrostep-macro-form-p-function) + + +;;; Define keymap and minor mode +(defvar macrostep-keymap + (let ((map (make-sparse-keymap))) + (define-key map (kbd "RET") 'macrostep-expand) + (define-key map "=" 'macrostep-expand) + (define-key map "e" 'macrostep-expand) + + (define-key map (kbd "DEL") 'macrostep-collapse) + (define-key map "u" 'macrostep-collapse) + (define-key map "c" 'macrostep-collapse) + + (define-key map (kbd "TAB") 'macrostep-next-macro) + (define-key map "n" 'macrostep-next-macro) + (define-key map (kbd "M-TAB") 'macrostep-prev-macro) + (define-key map "p" 'macrostep-prev-macro) + + (define-key map "q" 'macrostep-collapse-all) + (define-key map (kbd "C-c C-c") 'macrostep-collapse-all) + map) + "Keymap for `macrostep-mode'.") + +;;;###autoload +(define-minor-mode macrostep-mode + "Minor mode for inline expansion of macros in Emacs Lisp source buffers. + +\\Progressively expand macro forms with \\[macrostep-expand], collapse them with \\[macrostep-collapse], +and move back and forth with \\[macrostep-next-macro] and \\[macrostep-prev-macro]. +Use \\[macrostep-collapse-all] or collapse all visible expansions to +quit and return to normal editing. + +\\{macrostep-keymap}" + nil " Macro-Stepper" + :keymap macrostep-keymap + :group macrostep + (if macrostep-mode + (progn + ;; Disable recording of undo information + (setq macrostep-saved-undo-list buffer-undo-list + buffer-undo-list t) + ;; Remember whether buffer was read-only + (setq macrostep-saved-read-only buffer-read-only + buffer-read-only t) + ;; Set up post-command hook to bail out on leaving read-only + (add-hook 'post-command-hook 'macrostep-command-hook nil t) + (message + (substitute-command-keys + "\\Entering macro stepper mode. Use \\[macrostep-expand] to expand, \\[macrostep-collapse] to collapse, \\[macrostep-collapse-all] to exit."))) + + ;; Exiting mode + (if macrostep-expansion-buffer + ;; Kill dedicated expansion buffers + (quit-window t) + ;; Collapse any remaining overlays + (when macrostep-overlays (macrostep-collapse-all)) + ;; Restore undo info & read-only state + (setq buffer-undo-list macrostep-saved-undo-list + buffer-read-only macrostep-saved-read-only + macrostep-saved-undo-list nil) + ;; Remove our post-command hook + (remove-hook 'post-command-hook 'macrostep-command-hook t)))) + +;; Post-command hook: bail out of macrostep-mode if the user types C-x +;; C-q to make the buffer writable again. +(defun macrostep-command-hook () + (if (not buffer-read-only) + (macrostep-mode 0))) + + +;;; Interactive functions +;;;###autoload +(defun macrostep-expand (&optional toggle-separate-buffer) + "Expand the macro form following point by one step. + +Enters `macrostep-mode' if it is not already active, making the +buffer temporarily read-only. If macrostep-mode is active and the +form following point is not a macro form, search forward in the +buffer and expand the next macro form found, if any. + +With a prefix argument, the expansion is displayed in a separate +buffer instead of inline in the current buffer. Setting +`macrostep-expand-in-separate-buffer' to non-nil swaps these two +behaviors." + (interactive "P") + (cl-destructuring-bind (start . end) + (funcall macrostep-sexp-bounds-function) + (goto-char start) + (let* ((sexp (funcall macrostep-sexp-at-point-function start end)) + (end (copy-marker end)) + (text (buffer-substring start end)) + (env (funcall macrostep-environment-at-point-function)) + (expansion (funcall macrostep-expand-1-function sexp env))) + + ;; Create a dedicated macro-expansion buffer and copy the text to + ;; be expanded into it, if required + (let ((separate-buffer-p + (if toggle-separate-buffer + (not macrostep-expand-in-separate-buffer) + macrostep-expand-in-separate-buffer))) + (when (and separate-buffer-p (not macrostep-expansion-buffer)) + (let ((mode major-mode) + (buffer + (get-buffer-create (generate-new-buffer-name "*macro expansion*")))) + (set-buffer buffer) + (funcall mode) + (setq macrostep-expansion-buffer t) + (setq macrostep-outer-environment env) + (save-excursion + (setq start (point)) + (insert text) + (setq end (point-marker))) + (pop-to-buffer buffer)))) + + (unless macrostep-mode (macrostep-mode t)) + (let ((existing-overlay (macrostep-overlay-at-point)) + (macrostep-gensym-depth macrostep-gensym-depth) + (macrostep-gensyms-this-level nil) + priority) + (if existing-overlay + (progn ; Expanding part of a previous macro-expansion + (setq priority (1+ (overlay-get existing-overlay 'priority))) + (setq macrostep-gensym-depth + (overlay-get existing-overlay 'macrostep-gensym-depth))) + ;; Expanding source buffer text + (setq priority 1) + (setq macrostep-gensym-depth -1)) + + (with-silent-modifications + (atomic-change-group + (let ((inhibit-read-only t)) + (save-excursion + ;; Insert expansion + (funcall macrostep-print-function expansion env) + ;; Delete the original form + (macrostep-collapse-overlays-in (point) end) + (delete-region (point) end) + ;; Create a new overlay + (let ((overlay + (make-overlay start + (if (looking-at "\n") + (1+ (point)) + (point))))) + (unless macrostep-expansion-buffer + ;; Highlight the overlay in original source buffers only + (overlay-put overlay 'face 'macrostep-expansion-highlight-face)) + (overlay-put overlay 'priority priority) + (overlay-put overlay 'macrostep-original-text text) + (overlay-put overlay 'macrostep-gensym-depth macrostep-gensym-depth) + (push overlay macrostep-overlays)))))))))) + +(defun macrostep-collapse () + "Collapse the innermost macro expansion near point to its source text. + +If no more macro expansions are visible after this, exit +`macrostep-mode'." + (interactive) + (let ((overlay (macrostep-overlay-at-point))) + (when (not overlay) (error "No macro expansion at point")) + (let ((inhibit-read-only t)) + (with-silent-modifications + (atomic-change-group + (macrostep-collapse-overlay overlay))))) + (if (not macrostep-overlays) + (macrostep-mode 0))) + +(defun macrostep-collapse-all () + "Collapse all visible macro expansions and exit `macrostep-mode'." + (interactive) + (let ((inhibit-read-only t)) + (with-silent-modifications + (dolist (overlay macrostep-overlays) + (let ((outermost (= (overlay-get overlay 'priority) 1))) + ;; We only need restore the original text for the outermost + ;; overlays + (macrostep-collapse-overlay overlay (not outermost)))))) + (setq macrostep-overlays nil) + (macrostep-mode 0)) + +(defun macrostep-next-macro () + "Move point forward to the next macro form in macro-expanded text." + (interactive) + (let* ((start + (if (get-text-property (point) 'macrostep-macro-start) + (1+ (point)) + (point))) + (next (next-single-property-change start 'macrostep-macro-start))) + (if next + (goto-char next) + (error "No more macro forms found")))) + +(defun macrostep-prev-macro () + "Move point back to the previous macro form in macro-expanded text." + (interactive) + (let (prev) + (save-excursion + (while + (progn + (setq prev + (previous-single-property-change (point) 'macrostep-macro-start)) + (if (or (not prev) + (get-text-property (1- prev) 'macrostep-macro-start)) + nil + (prog1 t (goto-char prev)))))) + (if prev + (goto-char (1- prev)) + (error "No previous macro form found")))) + + +;;; Utility functions (not language-specific) + +(defun macrostep-overlay-at-point () + "Return the innermost macro stepper overlay at point." + (let ((result + (get-char-property-and-overlay (point) 'macrostep-original-text))) + (cdr result))) + +(defun macrostep-collapse-overlay (overlay &optional no-restore-p) + "Collapse a macro-expansion overlay and restore the unexpanded source text. + +As a minor optimization, does not restore the original source +text if NO-RESTORE-P is non-nil. This is safe to do when +collapsing all the sub-expansions of an outer overlay, since the +outer overlay will restore the original source itself. + +Also removes the overlay from `macrostep-overlays'." + (with-current-buffer (overlay-buffer overlay) + ;; If we're cleaning up we don't need to bother restoring text + ;; or checking for inner overlays to delete + (unless no-restore-p + (let* ((start (overlay-start overlay)) + (end (overlay-end overlay)) + (text (overlay-get overlay 'macrostep-original-text)) + (sexp-end + (copy-marker + (if (equal (char-before end) ?\n) (1- end) end)))) + (macrostep-collapse-overlays-in start end) + (goto-char (overlay-start overlay)) + (save-excursion + (insert text) + (delete-region (point) sexp-end)))) + ;; Remove overlay from the list and delete it + (setq macrostep-overlays + (delq overlay macrostep-overlays)) + (delete-overlay overlay))) + +(defun macrostep-collapse-overlays-in (start end) + "Collapse all macrostepper overlays that are strictly between START and END. + +Will not collapse overlays that begin at START and end at END." + (dolist (ol (overlays-in start end)) + (if (and (> (overlay-start ol) start) + (< (overlay-end ol) end) + (overlay-get ol 'macrostep-original-text)) + (macrostep-collapse-overlay ol t)))) + + +;;; Emacs Lisp implementation + +(defun macrostep-sexp-bounds () + "Find the bounds of the macro form nearest point. + +If point is not before an open-paren, moves up to the nearest +enclosing list. If the form at point is not a macro call, +attempts to move forward to the next macro form as determined by +`macrostep-macro-form-p-function'. + +Returns a cons of buffer positions, (START . END)." + (save-excursion + (if (not (looking-at "[(`]")) + (backward-up-list 1)) + (if (equal (char-before) ?`) + (backward-char)) + (let ((sexp (funcall macrostep-sexp-at-point-function)) + (env (funcall macrostep-environment-at-point-function))) + ;; If this isn't a macro form, try to find the next one in the buffer + (unless (funcall macrostep-macro-form-p-function sexp env) + (condition-case nil + (macrostep-next-macro) + (error + (if (consp sexp) + (error "(%s ...) is not a macro form" (car sexp)) + (error "Text at point is not a macro form.")))))) + (cons (point) (scan-sexps (point) 1)))) + +(defun macrostep-sexp-at-point (&rest ignore) + "Return the sexp near point for purposes of macro-stepper expansion. + +If the sexp near point is part of a macro expansion, returns the +saved text of the macro expansion, and does not read from the +buffer. This preserves uninterned symbols in the macro +expansion, so that they can be fontified consistently. (See +`macrostep-print-sexp'.)" + (or (get-text-property (point) 'macrostep-expanded-text) + (sexp-at-point))) + +(defun macrostep-macro-form-p (form environment) + "Return non-nil if FORM would be evaluated via macro expansion. + +If FORM is an invocation of a macro defined by `defmacro' or an +enclosing `cl-macrolet' form, return the symbol `macro'. + +If `macrostep-expand-compiler-macros' is non-nil and FORM is a +call to a function with a compiler macro, return the symbol +`compiler-macro'. + +Otherwise, return nil." + (car (macrostep--macro-form-info form environment t))) + +(defun macrostep--macro-form-info (form environment &optional inhibit-autoload) + "Return information about macro definitions that apply to FORM. + +If no macros are involved in the evaluation of FORM within +ENVIRONMENT, returns nil. Otherwise, returns a cons (TYPE +. DEFINITION). + +If FORM would be evaluated by a macro defined by `defmacro', +`cl-macrolet', etc., TYPE is the symbol `macro' and DEFINITION is +the macro definition, as a function. + +If `macrostep-expand-compiler-macros' is non-nil and FORM would +be compiled using a compiler macro, TYPE is the symbol +`compmiler-macro' and DEFINITION is the function that implements +the compiler macro. + +If FORM is an invocation of an autoloaded macro, the behavior +depends on the value of INHIBIT-AUTOLOAD. If INHIBIT-AUTOLOAD is +nil, the file containing the macro definition will be loaded +using `load-library' and the macro definition returned as normal. +If INHIBIT-AUTOLOAD is non-nil, no files will be loaded, and the +value of DEFINITION in the result will be nil." + (if (not (and (consp form) + (symbolp (car form)))) + `(nil . nil) + (let* ((head (car form)) + (local-definition (assoc-default head environment #'eq))) + (if local-definition + `(macro . ,local-definition) + (let ((compiler-macro-definition + (and macrostep-expand-compiler-macros + (or (get head 'compiler-macro) + (get head 'cl-compiler-macro))))) + (if (and compiler-macro-definition + (not (eq form + (apply compiler-macro-definition form (cdr form))))) + `(compiler-macro . ,compiler-macro-definition) + (condition-case nil + (let ((fun (indirect-function head))) + (cl-case (car-safe fun) + ((macro) + `(macro . ,(cdr fun))) + ((autoload) + (when (eq (nth 4 fun) 'macro) + (if inhibit-autoload + `(macro . nil) + (load-library (nth 1 fun)) + (macrostep--macro-form-info form nil)))) + (t + `(nil . nil)))) + (void-function nil)))))))) + +(defun macrostep-expand-1 (form environment) + "Return result of macro-expanding the top level of FORM by exactly one step. +Unlike `macroexpand', this function does not continue macro +expansion until a non-macro-call results." + (cl-destructuring-bind (type . definition) + (macrostep--macro-form-info form environment) + (cl-ecase type + ((nil) + form) + ((macro) + (apply definition (cdr form))) + ((compiler-macro) + (let ((expansion + (apply definition form (cdr form)))) + (if (equal form expansion) + (error "Form left unchanged by compiler macro") + expansion)))))) + +(put 'macrostep-grab-environment-failed 'error-conditions + '(macrostep-grab-environment-failed error)) + +(defun macrostep-environment-at-point () + "Return the local macro-expansion environment at point, if any. + +The local environment includes macros declared by any `macrolet' +or `cl-macrolet' forms surrounding point, as well as by any macro +forms which expand into a `macrolet'. + +The return value is an alist of elements (NAME . FUNCTION), where +NAME is the symbol locally bound to the macro and FUNCTION is the +lambda expression that returns its expansion." + ;; If point is on a macro form within an expansion inserted by + ;; `macrostep-print-sexp', a local environment may have been + ;; previously saved as a text property. + (let ((saved-environment + (get-text-property (point) 'macrostep-environment))) + (if saved-environment + saved-environment + ;; Otherwise, we (ab)use the macro-expander to return the + ;; environment at point. If point is not at an evaluated + ;; position in the containing form, + ;; `macrostep-environment-at-point-1' will raise an error, and + ;; we back up progressively through the containing forms until + ;; it succeeds. + (save-excursion + (catch 'done + (while t + (condition-case nil + (throw 'done (macrostep-environment-at-point-1)) + (macrostep-grab-environment-failed + (condition-case nil + (backward-sexp) + (scan-error (backward-up-list))))))))))) + +(defun macrostep-environment-at-point-1 () + "Attempt to extract the macro environment that would be active at point. + +If point is not at an evaluated position within the containing +form, raise an error." + ;; Macro environments are extracted using Emacs Lisp's builtin + ;; macro-expansion machinery. The form containing point is copied + ;; to a temporary buffer, and a call to + ;; `--macrostep-grab-environment--' is inserted at point. This + ;; altered form is then fully macro-expanded, in an environment + ;; where `--macrostep-grab-environment--' is defined as a macro + ;; which throws the environment to a uniquely-generated tag. + (let* ((point-at-top-level + (save-excursion + (while (ignore-errors (backward-up-list) t)) + (point))) + (enclosing-form + (buffer-substring point-at-top-level + (scan-sexps point-at-top-level 1))) + (position (- (point) point-at-top-level)) + (tag (make-symbol "macrostep-grab-environment-tag")) + (grab-environment '--macrostep-grab-environment--)) + (if (= position 0) + nil + (with-temp-buffer + (emacs-lisp-mode) + (insert enclosing-form) + (goto-char (+ (point-min) position)) + (prin1 `(,grab-environment) (current-buffer)) + (let ((form (read (copy-marker (point-min))))) + (catch tag + (cl-letf (((symbol-function #'message) (symbol-function #'format))) + (with-no-warnings + (ignore-errors + (macroexpand-all + `(cl-macrolet ((,grab-environment (&environment env) + (throw ',tag env))) + ,form))))) + (signal 'macrostep-grab-environment-failed nil))))))) + +(defun macrostep-collect-macro-forms (form &optional environment) + "Identify sub-forms of FORM which undergo macro-expansion. + +FORM is an Emacs Lisp form. ENVIRONMENT is a local environment of +macro definitions. + +The return value is a list of two elements, (MACRO-FORM-ALIST +COMPILER-MACRO-FORMS). + +MACRO-FORM-ALIST is an alist of elements of the form (SUBFORM +. ENVIRONMENT), where SUBFORM is a form which undergoes +macro-expansion in the course of expanding FORM, and ENVIRONMENT +is the local macro environment in force when it is expanded. + +COMPILER-MACRO-FORMS is a list of subforms which would be +compiled using a compiler macro. Since there is no standard way +to provide a local compiler-macro definition in Emacs Lisp, no +corresponding local environments are collected for these. + +Forms and environments are extracted from FORM by instrumenting +Emacs's builtin `macroexpand' function and calling +`macroexpand-all'." + (let ((real-macroexpand (indirect-function #'macroexpand)) + (macro-form-alist '()) + (compiler-macro-forms '())) + (cl-letf + (((symbol-function #'macroexpand) + (lambda (form environment &rest args) + (let ((expansion + (apply real-macroexpand form environment args))) + (cond ((not (eq expansion form)) + (setq macro-form-alist + (cons (cons form environment) + macro-form-alist))) + ((and (consp form) + (symbolp (car form)) + macrostep-expand-compiler-macros + (not (eq form + (cl-compiler-macroexpand form)))) + (setq compiler-macro-forms + (cons form compiler-macro-forms)))) + expansion)))) + (ignore-errors + (macroexpand-all form environment))) + (list macro-form-alist compiler-macro-forms))) + +(defvar macrostep-collected-macro-form-alist nil + "An alist of macro forms and environments. +Controls the printing of sub-forms in `macrostep-print-sexp'.") + +(defvar macrostep-collected-compiler-macro-forms nil + "A list of compiler-macro forms to be highlighted in `macrostep-print-sexp'.") + +(defun macrostep-pp (sexp environment) + "Pretty-print SEXP, fontifying macro forms and uninterned symbols." + (cl-destructuring-bind + (macrostep-collected-macro-form-alist + macrostep-collected-compiler-macro-forms) + (macrostep-collect-macro-forms sexp environment) + (let ((print-quoted t)) + (macrostep-print-sexp sexp) + ;; Point is now after the expanded form; pretty-print it + (save-restriction + (narrow-to-region (scan-sexps (point) -1) (point)) + (save-excursion + (pp-buffer) + ;; Remove the extra newline inserted by pp-buffer + (goto-char (point-max)) + (delete-region + (point) + (save-excursion (skip-chars-backward " \t\n") (point)))) + ;; Indent the newly-inserted form in context + (widen) + (save-excursion + (backward-sexp) + (indent-sexp)))))) + +;; This must be defined before `macrostep-print-sexp': +(defmacro macrostep-propertize (form &rest plist) + "Evaluate FORM, applying syntax properties in PLIST to any inserted text." + (declare (indent 1) + (debug (&rest form))) + (let ((start (make-symbol "start"))) + `(let ((,start (point))) + (prog1 + ,form + ,@(cl-loop for (key value) on plist by #'cddr + collect `(put-text-property ,start (point) + ,key ,value)))))) + +(defun macrostep-print-sexp (sexp) + "Insert SEXP like `print', fontifying macro forms and uninterned symbols. + +Fontifies uninterned symbols and macro forms using +`font-lock-face' property, and saves the actual text of SEXP's +sub-forms as the `macrostep-expanded-text' text property so that +any uninterned symbols can be reused in macro expansions of the +sub-forms. See also `macrostep-sexp-at-point'. + +Macro and compiler-macro forms within SEXP are identified by +comparison with the `macrostep-collected-macro-form-alist' and +`macrostep-collected-compiler-macro-forms' variables, which +should be dynamically let-bound around calls to this function." + (cond + ((symbolp sexp) + ;; Fontify gensyms + (if (not (eq sexp (intern-soft (symbol-name sexp)))) + (macrostep-propertize + (prin1 sexp (current-buffer)) + 'font-lock-face (macrostep-get-gensym-face sexp)) + ;; Print other symbols as normal + (prin1 sexp (current-buffer)))) + + ((listp sexp) + ;; Print quoted and quasiquoted forms nicely. + (let ((head (car sexp))) + (cond ((and (eq head 'quote) ; quote + (= (length sexp) 2)) + (insert "'") + (macrostep-print-sexp (cadr sexp))) + + ((and (eq head '\`) ; backquote + (= (length sexp) 2)) + (if (assq sexp macrostep-collected-macro-form-alist) + (macrostep-propertize + (insert "`") + 'macrostep-expanded-text sexp + 'macrostep-macro-start t + 'font-lock-face 'macrostep-macro-face) + (insert "`")) + (macrostep-print-sexp (cadr sexp))) + + ((and (memq head '(\, \,@)) ; unquote + (= (length sexp) 2)) + (princ head (current-buffer)) + (macrostep-print-sexp (cadr sexp))) + + (t ; other list form + (cl-destructuring-bind (macro? . environment) + (or (assq sexp macrostep-collected-macro-form-alist) + '(nil . nil)) + (let + ((compiler-macro? + (memq sexp macrostep-collected-compiler-macro-forms))) + (if (or macro? compiler-macro?) + (progn + ;; Save the real expansion as a text property on the + ;; opening paren + (macrostep-propertize + (insert "(") + 'macrostep-macro-start t + 'macrostep-expanded-text sexp + 'macrostep-environment environment) + ;; Fontify the head of the macro + (macrostep-propertize + (macrostep-print-sexp head) + 'font-lock-face + (if macro? + 'macrostep-macro-face + 'macrostep-compiler-macro-face))) + ;; Not a macro form + (insert "(") + (macrostep-print-sexp head)))) + + ;; Print remaining list elements + (setq sexp (cdr sexp)) + (when sexp (insert " ")) + (while sexp + (if (listp sexp) + (progn + (macrostep-print-sexp (car sexp)) + (when (cdr sexp) (insert " ")) + (setq sexp (cdr sexp))) + ;; Print tail of dotted list + (insert ". ") + (macrostep-print-sexp sexp) + (setq sexp nil))) + (insert ")"))))) + + ;; Print everything except symbols and lists as normal + (t (prin1 sexp (current-buffer))))) + +(defun macrostep-get-gensym-face (symbol) + "Return the face to use in fontifying SYMBOL in printed macro expansions. + +All symbols introduced in the same level of macro expansion are +fontified using the same face (modulo the number of faces; see +`macrostep-gensym-faces')." + (or (get symbol 'macrostep-gensym-face) + (progn + (if (not macrostep-gensyms-this-level) + (setq macrostep-gensym-depth (1+ macrostep-gensym-depth) + macrostep-gensyms-this-level t)) + (let ((face (ring-ref macrostep-gensym-faces macrostep-gensym-depth))) + (put symbol 'macrostep-gensym-face face) + face)))) + + +(provide 'macrostep) + +;;; macrostep.el ends here diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/metering.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/metering.lisp new file mode 100644 index 0000000..b87d280 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/metering.lisp @@ -0,0 +1,1213 @@ +;;; -*- Mode: LISP; Package: monitor; Syntax: Common-lisp; Base: 10.; -*- +;;; Tue Jan 25 18:32:28 1994 by Mark Kantrowitz + +;;; **************************************************************** +;;; Metering System ************************************************ +;;; **************************************************************** +;;; +;;; The Metering System is a portable Common Lisp code profiling tool. +;;; It gathers timing and consing statistics for specified functions +;;; while a program is running. +;;; +;;; The Metering System is a combination of +;;; o the Monitor package written by Chris McConnell +;;; o the Profile package written by Skef Wholey and Rob MacLachlan +;;; The two systems were merged and extended by Mark Kantrowitz. +;;; +;;; Address: Carnegie Mellon University +;;; School of Computer Science +;;; Pittsburgh, PA 15213 +;;; +;;; This code is in the public domain and is distributed without warranty +;;; of any kind. +;;; +;;; This copy is from SLIME, http://www.common-lisp.net/project/slime/ +;;; +;;; + +;;; ******************************** +;;; Change Log ********************* +;;; ******************************** +;;; +;;; 26-JUN-90 mk Merged functionality of Monitor and Profile packages. +;;; 26-JUN-90 mk Now handles both inclusive and exclusive statistics +;;; with respect to nested calls. (Allows it to subtract +;;; total monitoring overhead for each function, not just +;;; the time spent monitoring the function itself.) +;;; 26-JUN-90 mk The table is now saved so that one may manipulate +;;; the data (sorting it, etc.) even after the original +;;; source of the data has been cleared. +;;; 25-SEP-90 mk Added get-cons functions for Lucid 3.0, MACL 1.3.2 +;;; required-arguments functions for Lucid 3.0, +;;; Franz Allegro CL, and MACL 1.3.2. +;;; 25-JAN-91 mk Now uses fdefinition if available. +;;; 25-JAN-91 mk Replaced (and :allegro (not :coral)) with :excl. +;;; Much better solution for the fact that both call +;;; themselves :allegro. +;;; 5-JUL-91 mk Fixed warning to occur only when file is loaded +;;; uncompiled. +;;; 5-JUL-91 mk When many unmonitored functions, print out number +;;; instead of whole list. +;;; 24-MAR-92 mk Updated for CLtL2 compatibility. space measuring +;;; doesn't work in MCL, but fixed so that timing +;;; statistics do. +;;; 26-MAR-92 mk Updated for Lispworks. Replaced :ccl with +;;; (and :ccl (not :lispworks)). +;;; 27-MAR-92 mk Added get-cons for Allegro-V4.0. +;;; 01-JAN-93 mk v2.0 Support for MCL 2.0, CMU CL 16d, Allegro V3.1/4.0/4.1, +;;; Lucid 4.0, ibcl +;;; 25-JAN-94 mk v2.1 Patches for CLISP from Bruno Haible. +;;; 01-APR-05 lgorrie Removed support for all Lisps except CLISP and OpenMCL. +;;; Purely to cut down on stale code (e.g. #+cltl2) in this +;;; version that is bundled with SLIME. +;;; 22-Aug-08 stas Define TIME-TYPE for Clozure CL. +;;; 07-Aug-12 heller Break lines at 80 columns +;;; + +;;; ******************************** +;;; To Do ************************** +;;; ******************************** +;;; +;;; - Need get-cons for Allegro, AKCL. +;;; - Speed up monitoring code. Replace use of hash tables with an embedded +;;; offset in an array so that it will be faster than using gethash. +;;; (i.e., svref/closure reference is usually faster than gethash). +;;; - Beware of (get-internal-run-time) overflowing. Yikes! +;;; - Check robustness with respect to profiled functions. +;;; - Check logic of computing inclusive and exclusive time and consing. +;;; Especially wrt incf/setf comment below. Should be incf, so we +;;; sum recursive calls. +;;; - Add option to record caller statistics -- this would list who +;;; called which functions and how often. +;;; - switches to turn timing/CONSING statistics collection on/off. + + +;;; ******************************** +;;; Notes ************************** +;;; ******************************** +;;; +;;; METERING has been tested (successfully) in the following lisps: +;;; CMU Common Lisp (16d, Python Compiler 1.0 ) :new-compiler +;;; CMU Common Lisp (M2.9 15-Aug-90, Compiler M1.8 15-Aug-90) +;;; Macintosh Allegro Common Lisp (1.3.2) +;;; Macintosh Common Lisp (2.0) +;;; ExCL (Franz Allegro CL 3.1.12 [DEC 3100] 11/19/90) :allegro-v3.1 +;;; ExCL (Franz Allegro CL 4.0.1 [Sun4] 2/8/91) :allegro-v4.0 +;;; ExCL (Franz Allegro CL 4.1 [SPARC R1] 8/28/92 14:06) :allegro-v4.1 +;;; ExCL (Franz ACL 5.0.1 [Linux/X86] 6/29/99 16:11) :allegro-v5.0.1 +;;; Lucid CL (Version 2.1 6-DEC-87) +;;; Lucid Common Lisp (3.0) +;;; Lucid Common Lisp (4.0.1 HP-700 12-Aug-91) +;;; AKCL (1.86, June 30, 1987 or later) +;;; Ibuki Common Lisp (Version 2, release 01.027) +;;; CLISP (January 1994) +;;; +;;; METERING needs to be tested in the following lisps: +;;; Symbolics Common Lisp (8.0) +;;; KCL (June 3, 1987 or later) +;;; TI (Release 4.1 or later) +;;; Golden Common Lisp (3.1 IBM-PC) +;;; VAXLisp (2.0, 3.1) +;;; Procyon Common Lisp + + +;;; **************************************************************** +;;; Documentation ************************************************** +;;; **************************************************************** +;;; +;;; This system runs in any valid Common Lisp. Four small +;;; implementation-dependent changes can be made to improve performance +;;; and prettiness. In the section labelled "Implementation Dependent +;;; Changes" below, you should tailor the functions REQUIRED-ARGUMENTS, +;;; GET-CONS, GET-TIME, and TIME-UNITS-PER-SECOND to your implementation +;;; for the best results. If GET-CONS is not specified for your +;;; implementation, no consing information will be reported. The other +;;; functions will default to working forms, albeit inefficient, in +;;; non-CMU implementations. If you tailor these functions for a particular +;;; version of Common Lisp, we'd appreciate receiving the code. +;;; + +;;; **************************************************************** +;;; Usage Notes **************************************************** +;;; **************************************************************** +;;; +;;; SUGGESTED USAGE: +;;; +;;; Start by monitoring big pieces of the program, then carefully choose +;;; which functions close to, but not in, the inner loop are to be +;;; monitored next. Don't monitor functions that are called by other +;;; monitored functions: you will only confuse yourself. +;;; +;;; If the per-call time reported is less than 1/10th of a second, then +;;; consider the clock resolution and profiling overhead before you believe +;;; the time. It may be that you will need to run your program many times +;;; in order to average out to a higher resolution. +;;; +;;; The easiest way to use this package is to load it and execute either +;;; (swank-monitor:with-monitoring (names*) () +;;; your-forms*) +;;; or +;;; (swank-monitor:monitor-form your-form) +;;; The former allows you to specify which functions will be monitored; the +;;; latter monitors all functions in the current package. Both automatically +;;; produce a table of statistics. Other variants can be constructed from +;;; the monitoring primitives, which are described below, along with a +;;; fuller description of these two macros. +;;; +;;; For best results, compile this file before using. +;;; +;;; +;;; CLOCK RESOLUTION: +;;; +;;; Unless you are very lucky, the length of your machine's clock "tick" is +;;; probably much longer than the time it takes a simple function to run. +;;; For example, on the IBM RT, the clock resolution is 1/50th of a second. +;;; This means that if a function is only called a few times, then only the +;;; first couple of decimal places are really meaningful. +;;; +;;; +;;; MONITORING OVERHEAD: +;;; +;;; The added monitoring code takes time to run every time that the monitored +;;; function is called, which can disrupt the attempt to collect timing +;;; information. In order to avoid serious inflation of the times for functions +;;; that take little time to run, an estimate of the overhead due to monitoring +;;; is subtracted from the times reported for each function. +;;; +;;; Although this correction works fairly well, it is not totally accurate, +;;; resulting in times that become increasingly meaningless for functions +;;; with short runtimes. For example, subtracting the estimated overhead +;;; may result in negative times for some functions. This is only a concern +;;; when the estimated profiling overhead is many times larger than +;;; reported total CPU time. +;;; +;;; If you monitor functions that are called by monitored functions, in +;;; :inclusive mode the monitoring overhead for the inner function is +;;; subtracted from the CPU time for the outer function. [We do this by +;;; counting for each function not only the number of calls to *this* +;;; function, but also the number of monitored calls while it was running.] +;;; In :exclusive mode this is not necessary, since we subtract the +;;; monitoring time of inner functions, overhead & all. +;;; +;;; Otherwise, the estimated monitoring overhead is not represented in the +;;; reported total CPU time. The sum of total CPU time and the estimated +;;; monitoring overhead should be close to the total CPU time for the +;;; entire monitoring run (as determined by TIME). +;;; +;;; A timing overhead factor is computed at load time. This will be incorrect +;;; if the monitoring code is run in a different environment than this file +;;; was loaded in. For example, saving a core image on a high performance +;;; machine and running it on a low performance one will result in the use +;;; of an erroneously small overhead factor. +;;; +;;; +;;; If your times vary widely, possible causes are: +;;; - Garbage collection. Try turning it off, then running your code. +;;; Be warned that monitoring code will probably cons when it does +;;; (get-internal-run-time). +;;; - Swapping. If you have enough memory, execute your form once +;;; before monitoring so that it will be swapped into memory. Otherwise, +;;; get a bigger machine! +;;; - Resolution of internal-time-units-per-second. If this value is +;;; too low, then the timings become wild. You can try executing more +;;; of whatever your test is, but that will only work if some of your +;;; paths do not match the timer resolution. +;;; internal-time-units-per-second is so coarse -- on a Symbolics it is +;;; 977, in MACL it is 60. +;;; +;;; + +;;; **************************************************************** +;;; Interface ****************************************************** +;;; **************************************************************** +;;; +;;; WITH-MONITORING (&rest functions) [Macro] +;;; (&optional (nested :exclusive) +;;; (threshold 0.01) +;;; (key :percent-time)) +;;; &body body +;;; The named functions will be set up for monitoring, the body forms executed, +;;; a table of results printed, and the functions unmonitored. The nested, +;;; threshold, and key arguments are passed to report-monitoring below. +;;; +;;; MONITOR-FORM form [Macro] +;;; &optional (nested :exclusive) +;;; (threshold 0.01) +;;; (key :percent-time) +;;; All functions in the current package are set up for monitoring while +;;; the form is executed, and automatically unmonitored after a table of +;;; results has been printed. The nested, threshold, and key arguments +;;; are passed to report-monitoring below. +;;; +;;; *MONITORED-FUNCTIONS* [Variable] +;;; This holds a list of all functions that are currently being monitored. +;;; +;;; MONITOR &rest names [Macro] +;;; The named functions will be set up for monitoring by augmenting +;;; their function definitions with code that gathers statistical information +;;; about code performance. As with the TRACE macro, the function names are +;;; not evaluated. Calls the function SWANK-MONITOR::MONITORING-ENCAPSULATE on each +;;; function name. If no names are specified, returns a list of all +;;; monitored functions. +;;; +;;; If name is not a symbol, it is evaled to return the appropriate +;;; closure. This allows you to monitor closures stored anywhere like +;;; in a variable, array or structure. Most other monitoring packages +;;; can't handle this. +;;; +;;; MONITOR-ALL &optional (package *package*) [Function] +;;; Monitors all functions in the specified package, which defaults to +;;; the current package. +;;; +;;; UNMONITOR &rest names [Macro] +;;; Removes monitoring code from the named functions. If no names are +;;; specified, all currently monitored functions are unmonitored. +;;; +;;; RESET-MONITORING-INFO name [Function] +;;; Resets the monitoring statistics for the specified function. +;;; +;;; RESET-ALL-MONITORING [Function] +;;; Resets the monitoring statistics for all monitored functions. +;;; +;;; MONITORED name [Function] +;;; Predicate to test whether a function is monitored. +;;; +;;; REPORT-MONITORING &optional names [Function] +;;; (nested :exclusive) +;;; (threshold 0.01) +;;; (key :percent-time) +;;; Creates a table of monitoring information for the specified list +;;; of names, and displays the table using display-monitoring-results. +;;; If names is :all or nil, uses all currently monitored functions. +;;; Takes the following arguments: +;;; - NESTED specifies whether nested calls of monitored functions +;;; are included in the times for monitored functions. +;;; o If :inclusive, the per-function information is for the entire +;;; duration of the monitored function, including any calls to +;;; other monitored functions. If functions A and B are monitored, +;;; and A calls B, then the accumulated time and consing for A will +;;; include the time and consing of B. Note: if a function calls +;;; itself recursively, the time spent in the inner call(s) may +;;; be counted several times. +;;; o If :exclusive, the information excludes time attributed to +;;; calls to other monitored functions. This is the default. +;;; - THRESHOLD specifies that only functions which have been executed +;;; more than threshold percent of the time will be reported. Defaults +;;; to 1%. If a threshold of 0 is specified, all functions are listed, +;;; even those with 0 or negative running times (see note on overhead). +;;; - KEY specifies that the table be sorted by one of the following +;;; sort keys: +;;; :function alphabetically by function name +;;; :percent-time by percent of total execution time +;;; :percent-cons by percent of total consing +;;; :calls by number of times the function was called +;;; :time-per-call by average execution time per function +;;; :cons-per-call by average consing per function +;;; :time same as :percent-time +;;; :cons same as :percent-cons +;;; +;;; REPORT &key (names :all) [Function] +;;; (nested :exclusive) +;;; (threshold 0.01) +;;; (sort-key :percent-time) +;;; (ignore-no-calls nil) +;;; +;;; Same as REPORT-MONITORING but we use a nicer keyword interface. +;;; +;;; DISPLAY-MONITORING-RESULTS &optional (threshold 0.01) [Function] +;;; (key :percent-time) +;;; Prints a table showing for each named function: +;;; - the total CPU time used in that function for all calls +;;; - the total number of bytes consed in that function for all calls +;;; - the total number of calls +;;; - the average amount of CPU time per call +;;; - the average amount of consing per call +;;; - the percent of total execution time spent executing that function +;;; - the percent of total consing spent consing in that function +;;; Summary totals of the CPU time, consing, and calls columns are printed. +;;; An estimate of the monitoring overhead is also printed. May be run +;;; even after unmonitoring all the functions, to play with the data. +;;; +;;; SAMPLE TABLE: +#| + Cons + % % Per Total Total +Function Time Cons Calls Sec/Call Call Time Cons +---------------------------------------------------------------------- +FIND-ROLE: 0.58 0.00 136 0.003521 0 0.478863 0 +GROUP-ROLE: 0.35 0.00 365 0.000802 0 0.292760 0 +GROUP-PROJECTOR: 0.05 0.00 102 0.000408 0 0.041648 0 +FEATURE-P: 0.02 0.00 570 0.000028 0 0.015680 0 +---------------------------------------------------------------------- +TOTAL: 1173 0.828950 0 +Estimated total monitoring overhead: 0.88 seconds +|# + +;;; **************************************************************** +;;; METERING ******************************************************* +;;; **************************************************************** + +;;; ******************************** +;;; Warn people using the wrong Lisp +;;; ******************************** + +#-(or clisp openmcl) +(warn "metering.lisp does not support your Lisp implementation!") + +;;; ******************************** +;;; Packages *********************** +;;; ******************************** + +;;; For CLtL2 compatible lisps + +(defpackage "SWANK-MONITOR" (:use "COMMON-LISP") + (:export "*MONITORED-FUNCTIONS*" + "MONITOR" "MONITOR-ALL" "UNMONITOR" "MONITOR-FORM" + "WITH-MONITORING" + "RESET-MONITORING-INFO" "RESET-ALL-MONITORING" + "MONITORED" + "REPORT-MONITORING" + "DISPLAY-MONITORING-RESULTS" + "MONITORING-ENCAPSULATE" "MONITORING-UNENCAPSULATE" + "REPORT")) +(in-package "SWANK-MONITOR") + +;;; Warn user if they're loading the source instead of compiling it first. +(eval-when (eval) + (warn "This file should be compiled before loading for best results.")) + +;;; ******************************** +;;; Version ************************ +;;; ******************************** + +(defparameter *metering-version* "v2.1 25-JAN-94" + "Current version number/date for Metering.") + + +;;; **************************************************************** +;;; Implementation Dependent Definitions *************************** +;;; **************************************************************** + +;;; ******************************** +;;; Timing Functions *************** +;;; ******************************** +;;; The get-time function is called to find the total number of ticks since +;;; the beginning of time. time-units-per-second allows us to convert units +;;; to seconds. + +#-(or clisp openmcl) +(eval-when (compile eval) + (warn + "You may want to supply implementation-specific get-time functions.")) + +(defconstant time-units-per-second internal-time-units-per-second) + +#+openmcl +(progn + (deftype time-type () 'unsigned-byte) + (deftype consing-type () 'unsigned-byte)) + +(defmacro get-time () + `(the time-type (get-internal-run-time))) + +;;; NOTE: In Macintosh Common Lisp, CCL::GCTIME returns the number of +;;; milliseconds spent during GC. We could subtract this from +;;; the value returned by get-internal-run-time to eliminate +;;; the effect of GC on the timing values, but we prefer to let +;;; the user run without GC on. If the application is so big that +;;; it requires GC to complete, then the GC times are part of the +;;; cost of doing business, and will average out in the long run. +;;; If it seems really important to a user that GC times not be +;;; counted, then uncomment the following three lines and read-time +;;; conditionalize the definition of get-time above with #-:openmcl. +;#+openmcl +;(defmacro get-time () +; `(the time-type (- (get-internal-run-time) (ccl:gctime)))) + +;;; ******************************** +;;; Consing Functions ************** +;;; ******************************** +;;; The get-cons macro is called to find the total number of bytes +;;; consed since the beginning of time. + +#+clisp +(defun get-cons () + (multiple-value-bind (real1 real2 run1 run2 gc1 gc2 space1 space2 gccount) + (sys::%%time) + (declare (ignore real1 real2 run1 run2 gc1 gc2 gccount)) + (dpb space1 (byte 24 24) space2))) + +;;; Macintosh Common Lisp 2.0 +;;; Note that this includes bytes that were allocated during GC. +;;; We could subtract this out by advising GC like we did under +;;; MCL 1.3.2, but I'd rather users ran without GC. If they can't +;;; run without GC, then the bytes consed during GC are a cost of +;;; running their program. Metering the code a few times will +;;; avoid the consing values being too lopsided. If a user really really +;;; wants to subtract out the consing during GC, replace the following +;;; two lines with the commented out code. +#+openmcl +(defmacro get-cons () `(the consing-type (ccl::total-bytes-allocated))) + +#-(or clisp openmcl) +(progn + (eval-when (compile eval) + (warn "No consing will be reported unless a get-cons function is ~ + defined.")) + + (defmacro get-cons () '(the consing-type 0))) + +;; actually, neither `get-cons' nor `get-time' are used as is, +;; but only in the following macro `with-time/cons' +#-:clisp +(defmacro with-time/cons ((delta-time delta-cons) form &body post-process) + (let ((start-cons (gensym "START-CONS-")) + (start-time (gensym "START-TIME-"))) + `(let ((,start-time (get-time)) (,start-cons (get-cons))) + (declare (type time-type ,start-time) + (type consing-type ,start-cons)) + (multiple-value-prog1 ,form + (let ((,delta-time (- (get-time) ,start-time)) + (,delta-cons (- (get-cons) ,start-cons))) + ,@post-process))))) + +#+clisp +(progn + (defmacro delta4 (nv1 nv2 ov1 ov2 by) + `(- (dpb (- ,nv1 ,ov1) (byte ,by ,by) ,nv2) ,ov2)) + + (let ((del (find-symbol "DELTA4" "SYS"))) + (when del (setf (fdefinition 'delta4) (fdefinition del)))) + + (if (< internal-time-units-per-second 1000000) + ;; TIME_1: AMIGA, OS/2, UNIX_TIMES + (defmacro delta4-time (new-time1 new-time2 old-time1 old-time2) + `(delta4 ,new-time1 ,new-time2 ,old-time1 ,old-time2 16)) + ;; TIME_2: other UNIX, WIN32 + (defmacro delta4-time (new-time1 new-time2 old-time1 old-time2) + `(+ (* (- ,new-time1 ,old-time1) internal-time-units-per-second) + (- ,new-time2 ,old-time2)))) + + (defmacro delta4-cons (new-cons1 new-cons2 old-cons1 old-cons2) + `(delta4 ,new-cons1 ,new-cons2 ,old-cons1 ,old-cons2 24)) + + ;; avoid consing: when the application conses a lot, + ;; get-cons may return a bignum, so we really should not use it. + (defmacro with-time/cons ((delta-time delta-cons) form &body post-process) + (let ((beg-cons1 (gensym "BEG-CONS1-")) (end-cons1 (gensym "END-CONS1-")) + (beg-cons2 (gensym "BEG-CONS2-")) (end-cons2 (gensym "END-CONS2-")) + (beg-time1 (gensym "BEG-TIME1-")) (end-time1 (gensym "END-TIME1-")) + (beg-time2 (gensym "BEG-TIME2-")) (end-time2 (gensym "END-TIME2-")) + (re1 (gensym)) (re2 (gensym)) (gc1 (gensym)) (gc2 (gensym))) + `(multiple-value-bind (,re1 ,re2 ,beg-time1 ,beg-time2 + ,gc1 ,gc2 ,beg-cons1 ,beg-cons2) + (sys::%%time) + (declare (ignore ,re1 ,re2 ,gc1 ,gc2)) + (multiple-value-prog1 ,form + (multiple-value-bind (,re1 ,re2 ,end-time1 ,end-time2 + ,gc1 ,gc2 ,end-cons1 ,end-cons2) + (sys::%%time) + (declare (ignore ,re1 ,re2 ,gc1 ,gc2)) + (let ((,delta-time (delta4-time ,end-time1 ,end-time2 + ,beg-time1 ,beg-time2)) + (,delta-cons (delta4-cons ,end-cons1 ,end-cons2 + ,beg-cons1 ,beg-cons2))) + ,@post-process))))))) + +;;; ******************************** +;;; Required Arguments ************* +;;; ******************************** +;;; +;;; Required (Fixed) vs Optional Args +;;; +;;; To avoid unnecessary consing in the "encapsulation" code, we find out the +;;; number of required arguments, and use &rest to capture only non-required +;;; arguments. The function Required-Arguments returns two values: the first +;;; is the number of required arguments, and the second is T iff there are any +;;; non-required arguments (e.g. &optional, &rest, &key). + +;;; Lucid, Allegro, and Macintosh Common Lisp +#+openmcl +(defun required-arguments (name) + (let* ((function (symbol-function name)) + (args (ccl:arglist function)) + (pos (position-if #'(lambda (x) + (and (symbolp x) + (let ((name (symbol-name x))) + (and (>= (length name) 1) + (char= (schar name 0) + #\&))))) + args))) + (if pos + (values pos t) + (values (length args) nil)))) + +#+clisp +(defun required-arguments (name) + (multiple-value-bind (name req-num opt-num rest-p key-p keywords allow-p) + (sys::function-signature name t) + (if name ; no error + (values req-num (or (/= 0 opt-num) rest-p key-p keywords allow-p)) + (values 0 t)))) + +#-(or clisp openmcl) +(progn + (eval-when (compile eval) + (warn + "You may want to add an implementation-specific ~ +Required-Arguments function.")) + (eval-when (load eval) + (defun required-arguments (name) + (declare (ignore name)) + (values 0 t)))) + +#| +;;;Examples +(defun square (x) (* x x)) +(defun square2 (x &optional y) (* x x y)) +(defun test (x y &optional (z 3)) 3) +(defun test2 (x y &optional (z 3) &rest fred) 3) + +(required-arguments 'square) => 1 nil +(required-arguments 'square2) => 1 t +(required-arguments 'test) => 2 t +(required-arguments 'test2) => 2 t +|# + + +;;; **************************************************************** +;;; Main METERING Code ********************************************* +;;; **************************************************************** + +;;; ******************************** +;;; Global Variables *************** +;;; ******************************** +(defvar *MONITOR-TIME-OVERHEAD* nil + "The amount of time an empty monitored function costs.") +(defvar *MONITOR-CONS-OVERHEAD* nil + "The amount of cons an empty monitored function costs.") + +(defvar *TOTAL-TIME* 0 + "Total amount of time monitored so far.") +(defvar *TOTAL-CONS* 0 + "Total amount of consing monitored so far.") +(defvar *TOTAL-CALLS* 0 + "Total number of calls monitored so far.") +(proclaim '(type time-type *total-time*)) +(proclaim '(type consing-type *total-cons*)) +(proclaim '(fixnum *total-calls*)) + +;;; ******************************** +;;; Accessor Functions ************* +;;; ******************************** +;;; Perhaps the SYMBOLP should be FBOUNDP? I.e., what about variables +;;; containing closures. +(defmacro PLACE-FUNCTION (function-place) + "Return the function found at FUNCTION-PLACE. Evals FUNCTION-PLACE +if it isn't a symbol, to allow monitoring of closures located in +variables/arrays/structures." + ;; Note that (fboundp 'fdefinition) returns T even if fdefinition + ;; is a macro, which is what we want. + (if (fboundp 'fdefinition) + `(if (fboundp ,function-place) + (fdefinition ,function-place) + (eval ,function-place)) + `(if (symbolp ,function-place) + (symbol-function ,function-place) + (eval ,function-place)))) + +(defsetf PLACE-FUNCTION (function-place) (function) + "Set the function in FUNCTION-PLACE to FUNCTION." + (if (fboundp 'fdefinition) + ;; If we're conforming to CLtL2, use fdefinition here. + `(if (fboundp ,function-place) + (setf (fdefinition ,function-place) ,function) + (eval '(setf ,function-place ',function))) + `(if (symbolp ,function-place) + (setf (symbol-function ,function-place) ,function) + (eval '(setf ,function-place ',function))))) + +#| +;;; before using fdefinition +(defun PLACE-FUNCTION (function-place) + "Return the function found at FUNCTION-PLACE. Evals FUNCTION-PLACE +if it isn't a symbol, to allow monitoring of closures located in +variables/arrays/structures." + (if (symbolp function-place) + (symbol-function function-place) + (eval function-place))) + +(defsetf PLACE-FUNCTION (function-place) (function) + "Set the function in FUNCTION-PLACE to FUNCTION." + `(if (symbolp ,function-place) + (setf (symbol-function ,function-place) ,function) + (eval '(setf ,function-place ',function)))) +|# + +(defun PLACE-FBOUNDP (function-place) + "Test to see if FUNCTION-PLACE is a function." + ;; probably should be + #|(or (and (symbolp function-place)(fboundp function-place)) + (functionp (place-function function-place)))|# + (if (symbolp function-place) + (fboundp function-place) + (functionp (place-function function-place)))) + +(defun PLACE-MACROP (function-place) + "Test to see if FUNCTION-PLACE is a macro." + (when (symbolp function-place) + (macro-function function-place))) + +;;; ******************************** +;;; Measurement Tables ************* +;;; ******************************** +(defvar *monitored-functions* nil + "List of monitored symbols.") + +;;; We associate a METERING-FUNCTIONS structure with each monitored function +;;; name or other closure. This holds the functions that we call to manipulate +;;; the closure which implements the encapsulation. +;;; +(defstruct metering-functions + (name nil) + (old-definition nil :type function) + (new-definition nil :type function) + (read-metering nil :type function) + (reset-metering nil :type function)) + +;;; In general using hash tables in time-critical programs is a bad idea, +;;; because when one has to grow the table and rehash everything, the +;;; timing becomes grossly inaccurate. In this case it is not an issue +;;; because all inserting of entries in the hash table occurs before the +;;; timing commences. The only circumstance in which this could be a +;;; problem is if the lisp rehashes on the next reference to the table, +;;; instead of when the entry which forces a rehash was inserted. +;;; +;;; Note that a similar kind of problem can occur with GC, which is why +;;; one should turn off GC when monitoring code. +;;; +(defvar *monitor* (make-hash-table :test #'equal) + "Hash table in which METERING-FUNCTIONS structures are stored.") +(defun get-monitor-info (name) + (gethash name *monitor*)) +(defsetf get-monitor-info (name) (info) + `(setf (gethash ,name *monitor*) ,info)) + +(defun MONITORED (function-place) + "Test to see if a FUNCTION-PLACE is monitored." + (and (place-fboundp function-place) ; this line necessary? + (get-monitor-info function-place))) + +(defun reset-monitoring-info (name) + "Reset the monitoring info for the specified function." + (let ((finfo (get-monitor-info name))) + (when finfo + (funcall (metering-functions-reset-metering finfo))))) +(defun reset-all-monitoring () + "Reset monitoring info for all functions." + (setq *total-time* 0 + *total-cons* 0 + *total-calls* 0) + (dolist (symbol *monitored-functions*) + (when (monitored symbol) + (reset-monitoring-info symbol)))) + +(defun monitor-info-values (name &optional (nested :exclusive) warn) + "Returns monitoring information values for the named function, +adjusted for overhead." + (let ((finfo (get-monitor-info name))) + (if finfo + (multiple-value-bind (inclusive-time inclusive-cons + exclusive-time exclusive-cons + calls nested-calls) + (funcall (metering-functions-read-metering finfo)) + (unless (or (null warn) + (eq (place-function name) + (metering-functions-new-definition finfo))) + (warn "Funtion ~S has been redefined, so times may be inaccurate.~@ + MONITOR it again to record calls to the new definition." + name)) + (case nested + (:exclusive (values calls + nested-calls + (- exclusive-time + (* calls *monitor-time-overhead*)) + (- exclusive-cons + (* calls *monitor-cons-overhead*)))) + ;; In :inclusive mode, subtract overhead for all the + ;; called functions as well. Nested-calls includes the + ;; calls of the function as well. [Necessary 'cause of + ;; functions which call themselves recursively.] + (:inclusive (values calls + nested-calls + (- inclusive-time + (* nested-calls ;(+ calls) + *monitor-time-overhead*)) + (- inclusive-cons + (* nested-calls ;(+ calls) + *monitor-cons-overhead*)))))) + (values 0 0 0 0)))) + +;;; ******************************** +;;; Encapsulate ******************** +;;; ******************************** +(eval-when (compile load eval) +;; Returns a lambda expression for a function that, when called with the +;; function name, will set up that function for metering. +;; +;; A function is monitored by replacing its definition with a closure +;; created by the following function. The closure records the monitoring +;; data, and updates the data with each call of the function. +;; +;; Other closures are used to read and reset the data. +(defun make-monitoring-encapsulation (min-args optionals-p) + (let (required-args) + (dotimes (i min-args) (push (gensym) required-args)) + `(lambda (name) + (let ((inclusive-time 0) + (inclusive-cons 0) + (exclusive-time 0) + (exclusive-cons 0) + (calls 0) + (nested-calls 0) + (old-definition (place-function name))) + (declare (type time-type inclusive-time) + (type time-type exclusive-time) + (type consing-type inclusive-cons) + (type consing-type exclusive-cons) + (fixnum calls) + (fixnum nested-calls)) + (pushnew name *monitored-functions*) + + (setf (place-function name) + #'(lambda (,@required-args + ,@(when optionals-p + `(&rest optional-args))) + (let ((prev-total-time *total-time*) + (prev-total-cons *total-cons*) + (prev-total-calls *total-calls*) + ;; (old-time inclusive-time) + ;; (old-cons inclusive-cons) + ;; (old-nested-calls nested-calls) + ) + (declare (type time-type prev-total-time) + (type consing-type prev-total-cons) + (fixnum prev-total-calls)) + (with-time/cons (delta-time delta-cons) + ;; form + ,(if optionals-p + `(apply old-definition + ,@required-args optional-args) + `(funcall old-definition ,@required-args)) + ;; post-processing: + ;; Calls + (incf calls) + (incf *total-calls*) + ;; nested-calls includes this call + (incf nested-calls (the fixnum + (- *total-calls* + prev-total-calls))) + ;; (setf nested-calls (+ old-nested-calls + ;; (- *total-calls* + ;; prev-total-calls))) + ;; Time + ;; Problem with inclusive time is that it + ;; currently doesn't add values from recursive + ;; calls to the same function. Change the + ;; setf to an incf to fix this? + (incf inclusive-time (the time-type delta-time)) + ;; (setf inclusive-time (+ delta-time old-time)) + (incf exclusive-time (the time-type + (+ delta-time + (- prev-total-time + *total-time*)))) + (setf *total-time* (the time-type + (+ delta-time + prev-total-time))) + ;; Consing + (incf inclusive-cons (the consing-type delta-cons)) + ;; (setf inclusive-cons (+ delta-cons old-cons)) + (incf exclusive-cons (the consing-type + (+ delta-cons + (- prev-total-cons + *total-cons*)))) + (setf *total-cons* + (the consing-type + (+ delta-cons prev-total-cons))))))) + (setf (get-monitor-info name) + (make-metering-functions + :name name + :old-definition old-definition + :new-definition (place-function name) + :read-metering #'(lambda () + (values inclusive-time + inclusive-cons + exclusive-time + exclusive-cons + calls + nested-calls)) + :reset-metering #'(lambda () + (setq inclusive-time 0 + inclusive-cons 0 + exclusive-time 0 + exclusive-cons 0 + calls 0 + nested-calls 0) + t))))))) +);; End of EVAL-WHEN + +;;; For efficiency reasons, we precompute the encapsulation functions +;;; for a variety of combinations of argument structures +;;; (min-args . optional-p). These are stored in the following hash table +;;; along with any new ones we encounter. Since we're now precomputing +;;; closure functions for common argument signatures, this eliminates +;;; the former need to call COMPILE for each monitored function. +(eval-when (compile eval) + (defconstant precomputed-encapsulations 8)) + +(defvar *existing-encapsulations* (make-hash-table :test #'equal)) +(defun find-encapsulation (min-args optionals-p) + (or (gethash (cons min-args optionals-p) *existing-encapsulations*) + (setf (gethash (cons min-args optionals-p) *existing-encapsulations*) + (compile nil + (make-monitoring-encapsulation min-args optionals-p))))) + +(macrolet ((frob () + (let ((res ())) + (dotimes (i precomputed-encapsulations) + (push `(setf (gethash '(,i . nil) *existing-encapsulations*) + #',(make-monitoring-encapsulation i nil)) + res) + (push `(setf (gethash '(,i . t) *existing-encapsulations*) + #',(make-monitoring-encapsulation i t)) + res)) + `(progn ,@res)))) + (frob)) + +(defun monitoring-encapsulate (name &optional warn) + "Monitor the function Name. If already monitored, unmonitor first." + ;; Saves the current definition of name and inserts a new function which + ;; returns the result of evaluating body. + (cond ((not (place-fboundp name)) ; not a function + (when warn + (warn "Ignoring undefined function ~S." name))) + ((place-macrop name) ; a macro + (when warn + (warn "Ignoring macro ~S." name))) + (t ; tis a function + (when (get-monitor-info name) ; monitored + (when warn + (warn "~S already monitored, so unmonitoring it first." name)) + (monitoring-unencapsulate name)) + (multiple-value-bind (min-args optionals-p) + (required-arguments name) + (funcall (find-encapsulation min-args optionals-p) name))))) + +(defun monitoring-unencapsulate (name &optional warn) + "Removes monitoring encapsulation code from around Name." + (let ((finfo (get-monitor-info name))) + (when finfo ; monitored + (remprop name 'metering-functions) + (setq *monitored-functions* + (remove name *monitored-functions* :test #'equal)) + (if (eq (place-function name) + (metering-functions-new-definition finfo)) + (setf (place-function name) + (metering-functions-old-definition finfo)) + (when warn + (warn "Preserving current definition of redefined function ~S." + name)))))) + +;;; ******************************** +;;; Main Monitoring Functions ****** +;;; ******************************** +(defmacro MONITOR (&rest names) + "Monitor the named functions. As in TRACE, the names are not evaluated. + If a function is already monitored, then unmonitor and remonitor (useful + to notice function redefinition). If a name is undefined, give a warning + and ignore it. See also unmonitor, report-monitoring, + display-monitoring-results and reset-time." + `(progn + ,@(mapcar #'(lambda (name) `(monitoring-encapsulate ',name)) names) + *monitored-functions*)) + +(defmacro UNMONITOR (&rest names) + "Remove the monitoring on the named functions. + Names defaults to the list of all currently monitored functions." + `(dolist (name ,(if names `',names '*monitored-functions*) (values)) + (monitoring-unencapsulate name))) + +(defun MONITOR-ALL (&optional (package *package*)) + "Monitor all functions in the specified package." + (let ((package (if (packagep package) + package + (find-package package)))) + (do-symbols (symbol package) + (when (eq (symbol-package symbol) package) + (monitoring-encapsulate symbol))))) + +(defmacro MONITOR-FORM (form + &optional (nested :exclusive) (threshold 0.01) + (key :percent-time)) + "Monitor the execution of all functions in the current package +during the execution of FORM. All functions that are executed above +THRESHOLD % will be reported." + `(unwind-protect + (progn + (monitor-all) + (reset-all-monitoring) + (prog1 + (time ,form) + (report-monitoring :all ,nested ,threshold ,key :ignore-no-calls))) + (unmonitor))) + +(defmacro WITH-MONITORING ((&rest functions) + (&optional (nested :exclusive) + (threshold 0.01) + (key :percent-time)) + &body body) + "Monitor the specified functions during the execution of the body." + `(unwind-protect + (progn + (dolist (fun ',functions) + (monitoring-encapsulate fun)) + (reset-all-monitoring) + ,@body + (report-monitoring :all ,nested ,threshold ,key)) + (unmonitor))) + +;;; ******************************** +;;; Overhead Calculations ********** +;;; ******************************** +(defconstant overhead-iterations 5000 + "Number of iterations over which the timing overhead is averaged.") + +;;; Perhaps this should return something to frustrate clever compilers. +(defun STUB-FUNCTION (x) + (declare (ignore x)) + nil) +(proclaim '(notinline stub-function)) + +(defun SET-MONITOR-OVERHEAD () + "Determines the average overhead of monitoring by monitoring the execution +of an empty function many times." + (setq *monitor-time-overhead* 0 + *monitor-cons-overhead* 0) + (stub-function nil) + (monitor stub-function) + (reset-all-monitoring) + (let ((overhead-function (symbol-function 'stub-function))) + (dotimes (x overhead-iterations) + (funcall overhead-function overhead-function))) +; (dotimes (x overhead-iterations) +; (stub-function nil)) + (let ((fiter (float overhead-iterations))) + (multiple-value-bind (calls nested-calls time cons) + (monitor-info-values 'stub-function) + (declare (ignore calls nested-calls)) + (setq *monitor-time-overhead* (/ time fiter) + *monitor-cons-overhead* (/ cons fiter)))) + (unmonitor stub-function)) +(set-monitor-overhead) + +;;; ******************************** +;;; Report Data ******************** +;;; ******************************** +(defvar *monitor-results* nil + "A table of monitoring statistics is stored here.") +(defvar *no-calls* nil + "A list of monitored functions which weren't called.") +(defvar *estimated-total-overhead* 0) +;; (proclaim '(type time-type *estimated-total-overhead*)) + +(defstruct (monitoring-info + (:conc-name m-info-) + (:constructor make-monitoring-info + (name calls time cons + percent-time percent-cons + time-per-call cons-per-call))) + name + calls + time + cons + percent-time + percent-cons + time-per-call + cons-per-call) + +(defun REPORT (&key (names :all) + (nested :exclusive) + (threshold 0.01) + (sort-key :percent-time) + (ignore-no-calls nil)) + "Same as REPORT-MONITORING but with a nicer keyword interface" + (declare (type (member :function :percent-time :time :percent-cons + :cons :calls :time-per-call :cons-per-call) + sort-key) + (type (member :inclusive :exclusive) nested)) + (report-monitoring names nested threshold sort-key ignore-no-calls)) + +(defun REPORT-MONITORING (&optional names + (nested :exclusive) + (threshold 0.01) + (key :percent-time) + ignore-no-calls) + "Report the current monitoring state. +The percentage of the total time spent executing unmonitored code +in each function (:exclusive mode), or total time (:inclusive mode) +will be printed together with the number of calls and +the unmonitored time per call. Functions that have been executed +below THRESHOLD % of the time will not be reported. To report on all +functions set NAMES to be either NIL or :ALL." + (when (or (null names) (eq names :all)) (setq names *monitored-functions*)) + + (let ((total-time 0) + (total-cons 0) + (total-calls 0)) + ;; Compute overall time and consing. + (dolist (name names) + (multiple-value-bind (calls nested-calls time cons) + (monitor-info-values name nested :warn) + (declare (ignore nested-calls)) + (incf total-calls calls) + (incf total-time time) + (incf total-cons cons))) + ;; Total overhead. + (setq *estimated-total-overhead* + (/ (* *monitor-time-overhead* total-calls) + time-units-per-second)) + ;; Assemble data for only the specified names (all monitored functions) + (if (zerop total-time) + (format *trace-output* "Not enough execution time to monitor.") + (progn + (setq *monitor-results* nil *no-calls* nil) + (dolist (name names) + (multiple-value-bind (calls nested-calls time cons) + (monitor-info-values name nested) + (declare (ignore nested-calls)) + (when (minusp time) (setq time 0.0)) + (when (minusp cons) (setq cons 0.0)) + (if (zerop calls) + (push (if (symbolp name) + (symbol-name name) + (format nil "~S" name)) + *no-calls*) + (push (make-monitoring-info + (format nil "~S" name) ; name + calls ; calls + (/ time (float time-units-per-second)) ; time in secs + (round cons) ; consing + (/ time (float total-time)) ; percent-time + (if (zerop total-cons) 0 + (/ cons (float total-cons))) ; percent-cons + (/ (/ time (float calls)) ; time-per-call + time-units-per-second) ; sec/call + (round (/ cons (float calls)))) ; cons-per-call + *monitor-results*)))) + (display-monitoring-results threshold key ignore-no-calls))))) + +(defun display-monitoring-results (&optional (threshold 0.01) + (key :percent-time) + (ignore-no-calls t)) + (let ((max-length 8) ; Function header size + (max-cons-length 8) + (total-time 0.0) + (total-consed 0) + (total-calls 0) + (total-percent-time 0) + (total-percent-cons 0)) + (sort-results key) + (dolist (result *monitor-results*) + (when (or (zerop threshold) + (> (m-info-percent-time result) threshold)) + (setq max-length + (max max-length + (length (m-info-name result)))) + (setq max-cons-length + (max max-cons-length + (m-info-cons-per-call result))))) + (incf max-length 2) + (setf max-cons-length (+ 2 (ceiling (log max-cons-length 10)))) + (format *trace-output* + "~%~%~ + ~VT ~VA~ + ~% ~VT % % ~VA ~ +Total Total~ + ~%Function~VT Time Cons Calls Sec/Call ~VA ~ +Time Cons~ + ~%~V,,,'-A" + max-length + max-cons-length "Cons" + max-length + max-cons-length "Per" + max-length + max-cons-length "Call" + (+ max-length 62 (max 0 (- max-cons-length 5))) "-") + (dolist (result *monitor-results*) + (when (or (zerop threshold) + (> (m-info-percent-time result) threshold)) + (format *trace-output* + "~%~A:~VT~6,2F ~6,2F ~7D ~,6F ~VD ~8,3F ~10D" + (m-info-name result) + max-length + (* 100 (m-info-percent-time result)) + (* 100 (m-info-percent-cons result)) + (m-info-calls result) + (m-info-time-per-call result) + max-cons-length + (m-info-cons-per-call result) + (m-info-time result) + (m-info-cons result)) + (incf total-time (m-info-time result)) + (incf total-consed (m-info-cons result)) + (incf total-calls (m-info-calls result)) + (incf total-percent-time (m-info-percent-time result)) + (incf total-percent-cons (m-info-percent-cons result)))) + (format *trace-output* + "~%~V,,,'-A~ + ~%TOTAL:~VT~6,2F ~6,2F ~7D ~9@T ~VA ~8,3F ~10D~ + ~%Estimated monitoring overhead: ~5,2F seconds~ + ~%Estimated total monitoring overhead: ~5,2F seconds" + (+ max-length 62 (max 0 (- max-cons-length 5))) "-" + max-length + (* 100 total-percent-time) + (* 100 total-percent-cons) + total-calls + max-cons-length " " + total-time total-consed + (/ (* *monitor-time-overhead* total-calls) + time-units-per-second) + *estimated-total-overhead*) + (when (and (not ignore-no-calls) *no-calls*) + (setq *no-calls* (sort *no-calls* #'string<)) + (let ((num-no-calls (length *no-calls*))) + (if (> num-no-calls 20) + (format *trace-output* + "~%~@(~r~) monitored functions were not called. ~ + ~%See the variable swank-monitor::*no-calls* for a list." + num-no-calls) + (format *trace-output* + "~%The following monitored functions were not called:~ + ~%~{~<~%~:; ~A~>~}~%" + *no-calls*)))) + (values))) + +(defun sort-results (&optional (key :percent-time)) + (setq *monitor-results* + (case key + (:function (sort *monitor-results* #'string> + :key #'m-info-name)) + ((:percent-time :time) (sort *monitor-results* #'> + :key #'m-info-time)) + ((:percent-cons :cons) (sort *monitor-results* #'> + :key #'m-info-cons)) + (:calls (sort *monitor-results* #'> + :key #'m-info-calls)) + (:time-per-call (sort *monitor-results* #'> + :key #'m-info-time-per-call)) + (:cons-per-call (sort *monitor-results* #'> + :key #'m-info-cons-per-call))))) + +;;; *END OF FILE* + + diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/nregex.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/nregex.lisp new file mode 100644 index 0000000..43586ef --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/nregex.lisp @@ -0,0 +1,523 @@ +;;; +;;; This code was written by: +;;; +;;; Lawrence E. Freil +;;; National Science Center Foundation +;;; Augusta, Georgia 30909 +;;; +;;; This program was released into the public domain on 2005-08-31. +;;; (See the slime-devel mailing list archive for details.) +;;; +;;; nregex.lisp - My 4/8/92 attempt at a Lisp based regular expression +;;; parser. +;;; +;;; This regular expression parser operates by taking a +;;; regular expression and breaking it down into a list +;;; consisting of lisp expressions and flags. The list +;;; of lisp expressions is then taken in turned into a +;;; lambda expression that can be later applied to a +;;; string argument for parsing. +;;;; +;;;; Modifications made 6 March 2001 By Chris Double (chris@double.co.nz) +;;;; to get working with Corman Lisp 1.42, add package statement and export +;;;; relevant functions. +;;;; + +(in-package :cl-user) + +;; Renamed to slime-nregex avoid name clashes with other versions of +;; this file. -- he + +;;;; CND - 6/3/2001 +(defpackage slime-nregex + (:use #:common-lisp) + (:export + #:regex + #:regex-compile + )) + +;;;; CND - 6/3/2001 +(in-package :slime-nregex) + +;;; +;;; First we create a copy of macros to help debug the beast +(eval-when (:compile-toplevel :load-toplevel :execute) +(defvar *regex-debug* nil) ; Set to nil for no debugging code +) + +(defmacro info (message &rest args) + (if *regex-debug* + `(format *standard-output* ,message ,@args))) + +;;; +;;; Declare the global variables for storing the paren index list. +;;; +(defvar *regex-groups* (make-array 10)) +(defvar *regex-groupings* 0) + +;;; +;;; Declare a simple interface for testing. You probably wouldn't want +;;; to use this interface unless you were just calling this once. +;;; +(defun regex (expression string) + "Usage: (regex &optional invert) + Returns either the quoted character or a simple bit vector of bits set for + the matching values" + (let ((first (char char-string 0)) + (result (char char-string 0)) + (used-length 1)) + (cond ((eql first #\n) + (setf result #\NewLine)) + ((eql first #\c) + (setf result #\Return)) + ((eql first #\t) + (setf result #\Tab)) + ((eql first #\d) + (setf result #*0000000000000000000000000000000000000000000000001111111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000)) + ((eql first #\D) + (setf result #*1111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111)) + ((eql first #\w) + (setf result #*0000000000000000000000000000000000000000000000001111111111000000011111111111111111111111111000010111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000)) + ((eql first #\W) + (setf result #*1111111111111111111111111111111111111111111111110000000000111111100000000000000000000000000111101000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111)) + ((eql first #\b) + (setf result #*0000000001000000000000000000000011000000000010100000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000)) + ((eql first #\B) + (setf result #*1111111110111111111111111111111100111111111101011111111111011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111)) + ((eql first #\s) + (setf result #*0000000001100000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000)) + ((eql first #\S) + (setf result #*1111111110011111111111111111111101111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111)) + ((and (>= (char-code first) (char-code #\0)) + (<= (char-code first) (char-code #\9))) + (if (and (> (length char-string) 2) + (and (>= (char-code (char char-string 1)) (char-code #\0)) + (<= (char-code (char char-string 1)) (char-code #\9)) + (>= (char-code (char char-string 2)) (char-code #\0)) + (<= (char-code (char char-string 2)) (char-code #\9)))) + ;; + ;; It is a single character specified in octal + ;; + (progn + (setf result (do ((x 0 (1+ x)) + (return 0)) + ((= x 2) return) + (setf return (+ (* return 8) + (- (char-code (char char-string x)) + (char-code #\0)))))) + (setf used-length 3)) + ;; + ;; We have a group number replacement. + ;; + (let ((group (- (char-code first) (char-code #\0)))) + (setf result `((let ((nstring (subseq string (car (aref *regex-groups* ,group)) + (cadr (aref *regex-groups* ,group))))) + (if (< length (+ index (length nstring))) + (return-from compare nil)) + (if (not (string= string nstring + :start1 index + :end1 (+ index (length nstring)))) + (return-from compare nil) + (incf index (length nstring))))))))) + (t + (setf result first))) + (if (and (vectorp result) invert) + (bit-xor result #*1111111110011111111111111111111101111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 t)) + (values result used-length))) + +;;; +;;; Now for the main regex compiler routine. +;;; +(defun regex-compile (source &key (anchored nil)) + "Usage: (regex-compile [ :anchored (t/nil) ]) + This function take a regular expression (supplied as source) and + compiles this into a lambda list that a string argument can then + be applied to. It is also possible to compile this lambda list + for better performance or to save it as a named function for later + use" + (info "Now entering regex-compile with \"~A\"~%" source) + ;; + ;; This routine works in two parts. + ;; The first pass take the regular expression and produces a list of + ;; operators and lisp expressions for the entire regular expression. + ;; The second pass takes this list and produces the lambda expression. + (let ((expression '()) ; holder for expressions + (group 1) ; Current group index + (group-stack nil) ; Stack of current group endings + (result nil) ; holder for built expression. + (fast-first nil)) ; holder for quick unanchored scan + ;; + ;; If the expression was an empty string then it alway + ;; matches (so lets leave early) + ;; + (if (= (length source) 0) + (return-from regex-compile + '(lambda (&rest args) + (declare (ignore args)) + t))) + ;; + ;; If the first character is a caret then set the anchored + ;; flags and remove if from the expression string. + ;; + (cond ((eql (char source 0) #\^) + (setf source (subseq source 1)) + (setf anchored t))) + ;; + ;; If the first sequence is .* then also set the anchored flags. + ;; (This is purely for optimization, it will work without this). + ;; + (if (>= (length source) 2) + (if (string= source ".*" :start1 0 :end1 2) + (setf anchored t))) + ;; + ;; Also, If this is not an anchored search and the first character is + ;; a literal, then do a quick scan to see if it is even in the string. + ;; If not then we can issue a quick nil, + ;; otherwise we can start the search at the matching character to skip + ;; the checks of the non-matching characters anyway. + ;; + ;; If I really wanted to speed up this section of code it would be + ;; easy to recognize the case of a fairly long multi-character literal + ;; and generate a Boyer-Moore search for the entire literal. + ;; + ;; I generate the code to do a loop because on CMU Lisp this is about + ;; twice as fast a calling position. + ;; + (if (and (not anchored) + (not (position (char source 0) *regex-special-chars*)) + (not (and (> (length source) 1) + (position (char source 1) *regex-special-chars*)))) + (setf fast-first `((if (not (dotimes (i length nil) + (if (eql (char string i) + ,(char source 0)) + (return (setf start i))))) + (return-from final-return nil))))) + ;; + ;; Generate the very first expression to save the starting index + ;; so that group 0 will be the entire string matched always + ;; + (add-exp '((setf (aref *regex-groups* 0) + (list index nil)))) + ;; + ;; Loop over each character in the regular expression building the + ;; expression list as we go. + ;; + (do ((eindex 0 (1+ eindex))) + ((= eindex (length source))) + (let ((current (char source eindex))) + (info "Now processing character ~A index = ~A~%" current eindex) + (case current + ((#\.) + ;; + ;; Generate code for a single wild character + ;; + (add-exp '((if (>= index length) + (return-from compare nil) + (incf index))))) + ((#\$) + ;; + ;; If this is the last character of the expression then + ;; anchor the end of the expression, otherwise let it slide + ;; as a standard character (even though it should be quoted). + ;; + (if (= eindex (1- (length source))) + (add-exp '((if (not (= index length)) + (return-from compare nil)))) + (add-exp '((if (not (and (< index length) + (eql (char string index) #\$))) + (return-from compare nil) + (incf index)))))) + ((#\*) + (add-exp '(ASTRISK))) + + ((#\+) + (add-exp '(PLUS))) + + ((#\?) + (add-exp '(QUESTION))) + + ((#\() + ;; + ;; Start a grouping. + ;; + (incf group) + (push group group-stack) + (add-exp `((setf (aref *regex-groups* ,(1- group)) + (list index nil)))) + (add-exp `(,group))) + ((#\)) + ;; + ;; End a grouping + ;; + (let ((group (pop group-stack))) + (add-exp `((setf (cadr (aref *regex-groups* ,(1- group))) + index))) + (add-exp `(,(- group))))) + ((#\[) + ;; + ;; Start of a range operation. + ;; Generate a bit-vector that has one bit per possible character + ;; and then on each character or range, set the possible bits. + ;; + ;; If the first character is carat then invert the set. + (let* ((invert (eql (char source (1+ eindex)) #\^)) + (bitstring (make-array 256 :element-type 'bit + :initial-element + (if invert 1 0))) + (set-char (if invert 0 1))) + (if invert (incf eindex)) + (do ((x (1+ eindex) (1+ x))) + ((eql (char source x) #\]) (setf eindex x)) + (info "Building range with character ~A~%" (char source x)) + (cond ((and (eql (char source (1+ x)) #\-) + (not (eql (char source (+ x 2)) #\]))) + (if (>= (char-code (char source x)) + (char-code (char source (+ 2 x)))) + (error "Invalid range \"~A-~A\". Ranges must be in acending order" + (char source x) (char source (+ 2 x)))) + (do ((j (char-code (char source x)) (1+ j))) + ((> j (char-code (char source (+ 2 x)))) + (incf x 2)) + (info "Setting bit for char ~A code ~A~%" (code-char j) j) + (setf (sbit bitstring j) set-char))) + (t + (cond ((not (eql (char source x) #\])) + (let ((char (char source x))) + ;; + ;; If the character is quoted then find out what + ;; it should have been + ;; + (if (eql (char source x) #\\ ) + (let ((length)) + (multiple-value-setq (char length) + (regex-quoted (subseq source x) invert)) + (incf x length))) + (info "Setting bit for char ~A code ~A~%" char (char-code char)) + (if (not (vectorp char)) + (setf (sbit bitstring (char-code (char source x))) set-char) + (bit-ior bitstring char t)))))))) + (add-exp `((let ((range ,bitstring)) + (if (>= index length) + (return-from compare nil)) + (if (= 1 (sbit range (char-code (char string index)))) + (incf index) + (return-from compare nil))))))) + ((#\\ ) + ;; + ;; Intreprete the next character as a special, range, octal, group or + ;; just the character itself. + ;; + (let ((length) + (value)) + (multiple-value-setq (value length) + (regex-quoted (subseq source (1+ eindex)) nil)) + (cond ((listp value) + (add-exp value)) + ((characterp value) + (add-exp `((if (not (and (< index length) + (eql (char string index) + ,value))) + (return-from compare nil) + (incf index))))) + ((vectorp value) + (add-exp `((let ((range ,value)) + (if (>= index length) + (return-from compare nil)) + (if (= 1 (sbit range (char-code (char string index)))) + (incf index) + (return-from compare nil))))))) + (incf eindex length))) + (t + ;; + ;; We have a literal character. + ;; Scan to see how many we have and if it is more than one + ;; generate a string= verses as single eql. + ;; + (let* ((lit "") + (term (dotimes (litindex (- (length source) eindex) nil) + (let ((litchar (char source (+ eindex litindex)))) + (if (position litchar *regex-special-chars*) + (return litchar) + (progn + (info "Now adding ~A index ~A to lit~%" litchar + litindex) + (setf lit (concatenate 'string lit + (string litchar))))))))) + (if (= (length lit) 1) + (add-exp `((if (not (and (< index length) + (eql (char string index) ,current))) + (return-from compare nil) + (incf index)))) + ;; + ;; If we have a multi-character literal then we must + ;; check to see if the next character (if there is one) + ;; is an astrisk or a plus or a question mark. If so then we must not use this + ;; character in the big literal. + (progn + (if (or (eql term #\*) + (eql term #\+) + (eql term #\?)) + (setf lit (subseq lit 0 (1- (length lit))))) + (add-exp `((if (< length (+ index ,(length lit))) + (return-from compare nil)) + (if (not (string= string ,lit :start1 index + :end1 (+ index ,(length lit)))) + (return-from compare nil) + (incf index ,(length lit))))))) + (incf eindex (1- (length lit)))))))) + ;; + ;; Plug end of list to return t. If we made it this far then + ;; We have matched! + (add-exp '((setf (cadr (aref *regex-groups* 0)) + index))) + (add-exp '((return-from final-return t))) + ;; +;;; (print expression) + ;; + ;; Now take the expression list and turn it into a lambda expression + ;; replacing the special flags with lisp code. + ;; For example: A BEGIN needs to be replace by an expression that + ;; saves the current index, then evaluates everything till it gets to + ;; the END then save the new index if it didn't fail. + ;; On an ASTRISK I need to take the previous expression and wrap + ;; it in a do that will evaluate the expression till an error + ;; occurs and then another do that encompases the remainder of the + ;; regular expression and iterates decrementing the index by one + ;; of the matched expression sizes and then returns nil. After + ;; the last expression insert a form that does a return t so that + ;; if the entire nested sub-expression succeeds then the loop + ;; is broken manually. + ;; + (setf result (copy-tree nil)) + ;; + ;; Reversing the current expression makes building up the + ;; lambda list easier due to the nexting of expressions when + ;; and astrisk has been encountered. + (setf expression (reverse expression)) + (do ((elt 0 (1+ elt))) + ((>= elt (length expression))) + (let ((piece (nth elt expression))) + ;; + ;; Now check for PLUS, if so then ditto the expression and then let the + ;; ASTRISK below handle the rest. + ;; + (cond ((eql piece 'PLUS) + (cond ((listp (nth (1+ elt) expression)) + (setf result (append (list (nth (1+ elt) expression)) + result))) + ;; + ;; duplicate the entire group + ;; NOTE: This hasn't been implemented yet!! + (t + (error "GROUP repeat hasn't been implemented yet~%"))))) + (cond ((listp piece) ;Just append the list + (setf result (append (list piece) result))) + ((eql piece 'QUESTION) ; Wrap it in a block that won't fail + (cond ((listp (nth (1+ elt) expression)) + (setf result + (append `((progn (block compare + ,(nth (1+ elt) + expression)) + t)) + result)) + (incf elt)) + ;; + ;; This is a QUESTION on an entire group which + ;; hasn't been implemented yet!!! + ;; + (t + (error "Optional groups not implemented yet~%")))) + ((or (eql piece 'ASTRISK) ; Do the wild thing! + (eql piece 'PLUS)) + (cond ((listp (nth (1+ elt) expression)) + ;; + ;; This is a single character wild card so + ;; do the simple form. + ;; + (setf result + `((let ((oindex index)) + (block compare + (do () + (nil) + ,(nth (1+ elt) expression))) + (do ((start index (1- start))) + ((< start oindex) nil) + (let ((index start)) + (block compare + ,@result)))))) + (incf elt)) + (t + ;; + ;; This is a subgroup repeated so I must build + ;; the loop using several values. + ;; + )) + ) + (t t)))) ; Just ignore everything else. + ;; + ;; Now wrap the result in a lambda list that can then be + ;; invoked or compiled, however the user wishes. + ;; + (if anchored + (setf result + `(lambda (string &key (start 0) (end (length string))) + (setf *regex-groupings* ,group) + (block final-return + (block compare + (let ((index start) + (length end)) + ,@result))))) + (setf result + `(lambda (string &key (start 0) (end (length string))) + (setf *regex-groupings* ,group) + (block final-return + (let ((length end)) + ,@fast-first + (do ((marker start (1+ marker))) + ((> marker end) nil) + (let ((index marker)) + (if (block compare + ,@result) + (return t))))))))))) + +;; (provide 'nregex) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/packages.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/packages.lisp new file mode 100644 index 0000000..b4b159f --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/packages.lisp @@ -0,0 +1,202 @@ +(defpackage swank/backend + (:use cl) + (:nicknames swank-backend) + (:export *debug-swank-backend* + *log-output* + sldb-condition + compiler-condition + original-condition + message + source-context + condition + severity + with-compilation-hooks + make-location + location + location-p + location-buffer + location-position + location-hints + position-p + position-pos + print-output-to-string + quit-lisp + references + unbound-slot-filler + declaration-arglist + type-specifier-arglist + with-struct + when-let + defimplementation + converting-errors-to-error-location + make-error-location + deinit-log-output + ;; interrupt macro for the backend + *pending-slime-interrupts* + check-slime-interrupts + *interrupt-queued-handler* + ;; inspector related symbols + emacs-inspect + label-value-line + label-value-line* + boolean-to-feature-expression + with-symbol + choose-symbol + ;; package helper for backend + import-to-swank-mop + import-swank-mop-symbols + ;; + default-directory + set-default-directory + frame-source-location + restart-frame + gdb-initial-commands + sldb-break-on-return + buffer-first-change + + profiled-functions + unprofile-all + profile-report + profile-reset + profile-package + + with-collected-macro-forms + auto-flush-loop + *auto-flush-interval*)) + +(defpackage swank/rpc + (:use :cl) + (:export + read-message + read-packet + swank-reader-error + swank-reader-error.packet + swank-reader-error.cause + write-message)) + +(defpackage swank/match + (:use cl) + (:export match)) + +;; FIXME: rename to sawnk/mop +(defpackage swank-mop + (:use) + (:export + ;; classes + standard-generic-function + standard-slot-definition + standard-method + standard-class + eql-specializer + eql-specializer-object + ;; standard-class readers + class-default-initargs + class-direct-default-initargs + class-direct-slots + class-direct-subclasses + class-direct-superclasses + class-finalized-p + class-name + class-precedence-list + class-prototype + class-slots + specializer-direct-methods + ;; generic function readers + generic-function-argument-precedence-order + generic-function-declarations + generic-function-lambda-list + generic-function-methods + generic-function-method-class + generic-function-method-combination + generic-function-name + ;; method readers + method-generic-function + method-function + method-lambda-list + method-specializers + method-qualifiers + ;; slot readers + slot-definition-allocation + slot-definition-documentation + slot-definition-initargs + slot-definition-initform + slot-definition-initfunction + slot-definition-name + slot-definition-type + slot-definition-readers + slot-definition-writers + slot-boundp-using-class + slot-value-using-class + slot-makunbound-using-class + ;; generic function protocol + compute-applicable-methods-using-classes + finalize-inheritance)) + +(defpackage swank + (:use cl swank/backend swank/match swank/rpc) + (:export #:startup-multiprocessing + #:start-server + #:create-server + #:stop-server + #:restart-server + #:ed-in-emacs + #:inspect-in-emacs + #:print-indentation-lossage + #:invoke-slime-debugger + #:swank-debugger-hook + #:emacs-inspect + ;;#:inspect-slot-for-emacs + ;; These are user-configurable variables: + #:*communication-style* + #:*dont-close* + #:*fasl-pathname-function* + #:*log-events* + #:*use-dedicated-output-stream* + #:*dedicated-output-stream-port* + #:*configure-emacs-indentation* + #:*readtable-alist* + #:*globally-redirect-io* + #:*global-debugger* + #:*sldb-quit-restart* + #:*backtrace-printer-bindings* + #:*default-worker-thread-bindings* + #:*macroexpand-printer-bindings* + #:*swank-pprint-bindings* + #:*record-repl-results* + #:*inspector-verbose* + ;; This is SETFable. + #:debug-on-swank-error + ;; These are re-exported directly from the backend: + #:buffer-first-change + #:frame-source-location + #:gdb-initial-commands + #:restart-frame + #:sldb-step + #:sldb-break + #:sldb-break-on-return + #:profiled-functions + #:profile-report + #:profile-reset + #:unprofile-all + #:profile-package + #:default-directory + #:set-default-directory + #:quit-lisp + #:eval-for-emacs + #:eval-in-emacs + #:ed-rpc + #:ed-rpc-no-wait + #:y-or-n-p-in-emacs + #:*find-definitions-right-trim* + #:*find-definitions-left-trim* + #:*after-toggle-trace-hook* + #:unreadable-result + #:unreadable-result-p + #:unreadable-result-string + #:parse-string + #:from-string + #:to-string + #:*swank-debugger-condition* + #:run-hook-with-args-until-success + #:make-output-function-for-target + #:make-output-stream-for-target)) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/sbcl-pprint-patch.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/sbcl-pprint-patch.lisp new file mode 100644 index 0000000..dfdc0bb --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/sbcl-pprint-patch.lisp @@ -0,0 +1,332 @@ +;; Pretty printer patch for SBCL, which adds the "annotations" feature +;; required for sending presentations through pretty-printing streams. +;; +;; The section marked "Changed functions" and the DEFSTRUCT +;; PRETTY-STREAM are based on SBCL's pprint.lisp. +;; +;; Public domain. + +(in-package "SB!PRETTY") + +(defstruct (annotation (:include queued-op)) + (handler (constantly nil) :type function) + (record)) + + +(defstruct (pretty-stream (:include sb!kernel:ansi-stream + (out #'pretty-out) + (sout #'pretty-sout) + (misc #'pretty-misc)) + (:constructor make-pretty-stream (target)) + (:copier nil)) + ;; Where the output is going to finally go. + (target (missing-arg) :type stream) + ;; Line length we should format to. Cached here so we don't have to keep + ;; extracting it from the target stream. + (line-length (or *print-right-margin* + (sb!impl::line-length target) + default-line-length) + :type column) + ;; A simple string holding all the text that has been output but not yet + ;; printed. + (buffer (make-string initial-buffer-size) :type (simple-array character (*))) + ;; The index into BUFFER where more text should be put. + (buffer-fill-pointer 0 :type index) + ;; Whenever we output stuff from the buffer, we shift the remaining noise + ;; over. This makes it difficult to keep references to locations in + ;; the buffer. Therefore, we have to keep track of the total amount of + ;; stuff that has been shifted out of the buffer. + (buffer-offset 0 :type posn) + ;; The column the first character in the buffer will appear in. Normally + ;; zero, but if we end up with a very long line with no breaks in it we + ;; might have to output part of it. Then this will no longer be zero. + (buffer-start-column (or (sb!impl::charpos target) 0) :type column) + ;; The line number we are currently on. Used for *PRINT-LINES* + ;; abbreviations and to tell when sections have been split across + ;; multiple lines. + (line-number 0 :type index) + ;; the value of *PRINT-LINES* captured at object creation time. We + ;; use this, instead of the dynamic *PRINT-LINES*, to avoid + ;; weirdness like + ;; (let ((*print-lines* 50)) + ;; (pprint-logical-block .. + ;; (dotimes (i 10) + ;; (let ((*print-lines* 8)) + ;; (print (aref possiblybigthings i) prettystream))))) + ;; terminating the output of the entire logical blockafter 8 lines. + (print-lines *print-lines* :type (or index null) :read-only t) + ;; Stack of logical blocks in effect at the buffer start. + (blocks (list (make-logical-block)) :type list) + ;; Buffer holding the per-line prefix active at the buffer start. + ;; Indentation is included in this. The length of this is stored + ;; in the logical block stack. + (prefix (make-string initial-buffer-size) :type (simple-array character (*))) + ;; Buffer holding the total remaining suffix active at the buffer start. + ;; The characters are right-justified in the buffer to make it easier + ;; to output the buffer. The length is stored in the logical block + ;; stack. + (suffix (make-string initial-buffer-size) :type (simple-array character (*))) + ;; Queue of pending operations. When empty, HEAD=TAIL=NIL. Otherwise, + ;; TAIL holds the first (oldest) cons and HEAD holds the last (newest) + ;; cons. Adding things to the queue is basically (setf (cdr head) (list + ;; new)) and removing them is basically (pop tail) [except that care must + ;; be taken to handle the empty queue case correctly.] + (queue-tail nil :type list) + (queue-head nil :type list) + ;; Block-start queue entries in effect at the queue head. + (pending-blocks nil :type list) + ;; Queue of annotations to the buffer + (annotations-tail nil :type list) + (annotations-head nil :type list)) + + +(defmacro enqueue (stream type &rest args) + (let ((constructor (intern (concatenate 'string + "MAKE-" + (symbol-name type)) + "SB-PRETTY"))) + (once-only ((stream stream) + (entry `(,constructor :posn + (index-posn + (pretty-stream-buffer-fill-pointer + ,stream) + ,stream) + ,@args)) + (op `(list ,entry)) + (head `(pretty-stream-queue-head ,stream))) + `(progn + (if ,head + (setf (cdr ,head) ,op) + (setf (pretty-stream-queue-tail ,stream) ,op)) + (setf (pretty-stream-queue-head ,stream) ,op) + ,entry)))) + +;;; +;;; New helper functions +;;; + +(defun enqueue-annotation (stream handler record) + (enqueue stream annotation :handler handler + :record record)) + +(defun re-enqueue-annotation (stream annotation) + (let* ((annotation-cons (list annotation)) + (head (pretty-stream-annotations-head stream))) + (if head + (setf (cdr head) annotation-cons) + (setf (pretty-stream-annotations-tail stream) annotation-cons)) + (setf (pretty-stream-annotations-head stream) annotation-cons) + nil)) + +(defun re-enqueue-annotations (stream end) + (loop for tail = (pretty-stream-queue-tail stream) then (cdr tail) + while (and tail (not (eql (car tail) end))) + when (annotation-p (car tail)) + do (re-enqueue-annotation stream (car tail)))) + +(defun dequeue-annotation (stream &key end-posn) + (let ((next-annotation (car (pretty-stream-annotations-tail stream)))) + (when next-annotation + (when (or (not end-posn) + (<= (annotation-posn next-annotation) end-posn)) + (pop (pretty-stream-annotations-tail stream)) + (unless (pretty-stream-annotations-tail stream) + (setf (pretty-stream-annotations-head stream) nil)) + next-annotation)))) + +(defun invoke-annotation (stream annotation truncatep) + (let ((target (pretty-stream-target stream))) + (funcall (annotation-handler annotation) + (annotation-record annotation) + target + truncatep))) + +(defun output-buffer-with-annotations (stream end) + (let ((target (pretty-stream-target stream)) + (buffer (pretty-stream-buffer stream)) + (end-posn (index-posn end stream)) + (start 0)) + (loop + for annotation = (dequeue-annotation stream :end-posn end-posn) + while annotation + do + (let ((annotation-index (posn-index (annotation-posn annotation) + stream))) + (when (> annotation-index start) + (write-string buffer target :start start + :end annotation-index) + (setf start annotation-index)) + (invoke-annotation stream annotation nil))) + (when (> end start) + (write-string buffer target :start start :end end)))) + +(defun flush-annotations (stream end truncatep) + (let ((end-posn (index-posn end stream))) + (loop + for annotation = (dequeue-annotation stream :end-posn end-posn) + while annotation + do (invoke-annotation stream annotation truncatep)))) + +;;; +;;; Changed functions +;;; + +(defun maybe-output (stream force-newlines-p) + (declare (type pretty-stream stream)) + (let ((tail (pretty-stream-queue-tail stream)) + (output-anything nil)) + (loop + (unless tail + (setf (pretty-stream-queue-head stream) nil) + (return)) + (let ((next (pop tail))) + (etypecase next + (newline + (when (ecase (newline-kind next) + ((:literal :mandatory :linear) t) + (:miser (misering-p stream)) + (:fill + (or (misering-p stream) + (> (pretty-stream-line-number stream) + (logical-block-section-start-line + (first (pretty-stream-blocks stream)))) + (ecase (fits-on-line-p stream + (newline-section-end next) + force-newlines-p) + ((t) nil) + ((nil) t) + (:dont-know + (return)))))) + (setf output-anything t) + (output-line stream next))) + (indentation + (unless (misering-p stream) + (set-indentation stream + (+ (ecase (indentation-kind next) + (:block + (logical-block-start-column + (car (pretty-stream-blocks stream)))) + (:current + (posn-column + (indentation-posn next) + stream))) + (indentation-amount next))))) + (block-start + (ecase (fits-on-line-p stream (block-start-section-end next) + force-newlines-p) + ((t) + ;; Just nuke the whole logical block and make it look like one + ;; nice long literal. (But don't nuke annotations.) + (let ((end (block-start-block-end next))) + (expand-tabs stream end) + (re-enqueue-annotations stream end) + (setf tail (cdr (member end tail))))) + ((nil) + (really-start-logical-block + stream + (posn-column (block-start-posn next) stream) + (block-start-prefix next) + (block-start-suffix next))) + (:dont-know + (return)))) + (block-end + (really-end-logical-block stream)) + (tab + (expand-tabs stream next)) + (annotation + (re-enqueue-annotation stream next)))) + (setf (pretty-stream-queue-tail stream) tail)) + output-anything)) + +(defun output-line (stream until) + (declare (type pretty-stream stream) + (type newline until)) + (let* ((target (pretty-stream-target stream)) + (buffer (pretty-stream-buffer stream)) + (kind (newline-kind until)) + (literal-p (eq kind :literal)) + (amount-to-consume (posn-index (newline-posn until) stream)) + (amount-to-print + (if literal-p + amount-to-consume + (let ((last-non-blank + (position #\space buffer :end amount-to-consume + :from-end t :test #'char/=))) + (if last-non-blank + (1+ last-non-blank) + 0))))) + (output-buffer-with-annotations stream amount-to-print) + (flush-annotations stream amount-to-consume nil) + (let ((line-number (pretty-stream-line-number stream))) + (incf line-number) + (when (and (not *print-readably*) + (pretty-stream-print-lines stream) + (>= line-number (pretty-stream-print-lines stream))) + (write-string " .." target) + (flush-annotations stream + (pretty-stream-buffer-fill-pointer stream) + t) + (let ((suffix-length (logical-block-suffix-length + (car (pretty-stream-blocks stream))))) + (unless (zerop suffix-length) + (let* ((suffix (pretty-stream-suffix stream)) + (len (length suffix))) + (write-string suffix target + :start (- len suffix-length) + :end len)))) + (throw 'line-limit-abbreviation-happened t)) + (setf (pretty-stream-line-number stream) line-number) + (write-char #\newline target) + (setf (pretty-stream-buffer-start-column stream) 0) + (let* ((fill-ptr (pretty-stream-buffer-fill-pointer stream)) + (block (first (pretty-stream-blocks stream))) + (prefix-len + (if literal-p + (logical-block-per-line-prefix-end block) + (logical-block-prefix-length block))) + (shift (- amount-to-consume prefix-len)) + (new-fill-ptr (- fill-ptr shift)) + (new-buffer buffer) + (buffer-length (length buffer))) + (when (> new-fill-ptr buffer-length) + (setf new-buffer + (make-string (max (* buffer-length 2) + (+ buffer-length + (floor (* (- new-fill-ptr buffer-length) + 5) + 4))))) + (setf (pretty-stream-buffer stream) new-buffer)) + (replace new-buffer buffer + :start1 prefix-len :start2 amount-to-consume :end2 fill-ptr) + (replace new-buffer (pretty-stream-prefix stream) + :end1 prefix-len) + (setf (pretty-stream-buffer-fill-pointer stream) new-fill-ptr) + (incf (pretty-stream-buffer-offset stream) shift) + (unless literal-p + (setf (logical-block-section-column block) prefix-len) + (setf (logical-block-section-start-line block) line-number)))))) + +(defun output-partial-line (stream) + (let* ((fill-ptr (pretty-stream-buffer-fill-pointer stream)) + (tail (pretty-stream-queue-tail stream)) + (count + (if tail + (posn-index (queued-op-posn (car tail)) stream) + fill-ptr)) + (new-fill-ptr (- fill-ptr count)) + (buffer (pretty-stream-buffer stream))) + (when (zerop count) + (error "Output-partial-line called when nothing can be output.")) + (output-buffer-with-annotations stream count) + (incf (pretty-stream-buffer-start-column stream) count) + (replace buffer buffer :end1 new-fill-ptr :start2 count :end2 fill-ptr) + (setf (pretty-stream-buffer-fill-pointer stream) new-fill-ptr) + (incf (pretty-stream-buffer-offset stream) count))) + +(defun force-pretty-output (stream) + (maybe-output stream nil) + (expand-tabs stream nil) + (re-enqueue-annotations stream nil) + (output-buffer-with-annotations stream + (pretty-stream-buffer-fill-pointer stream))) + \ No newline at end of file diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/slime-autoloads.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/slime-autoloads.el new file mode 100644 index 0000000..0666f37 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/slime-autoloads.el @@ -0,0 +1,51 @@ +;;; slime-autoloads.el --- autoload definitions for SLIME -*- no-byte-compile: t -*- + +;; Copyright (C) 2007 Helmut Eller + +;; This file is protected by the GNU GPLv2 (or later), as distributed +;; with GNU Emacs. + +;;; Commentary: + +;; This code defines the necessary autoloads, so that we don't need to +;; load everything from .emacs. +;; +;; JT@14/01/09: FIXME: This file should be auto-generated with autoload cookies. + +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + +(autoload 'slime "slime" + "Start a Lisp subprocess and connect to its Swank server." t) + +(autoload 'slime-mode "slime" + "SLIME: The Superior Lisp Interaction (Minor) Mode for Emacs." t) + +(autoload 'slime-connect "slime" + "Connect to a running Swank server." t) + +(autoload 'slime-selector "slime" + "Select a new by type, indicated by a single character." t) + +(autoload 'hyperspec-lookup "lib/hyperspec" nil t) + +(autoload 'slime-lisp-mode-hook "slime") + +(autoload 'slime-scheme-mode-hook "slime") + +(defvar slime-contribs nil + "A list of contrib packages to load with SLIME.") + +(autoload 'slime-setup "slime" + "Setup some SLIME contribs.") + +(define-obsolete-variable-alias 'slime-setup-contribs + 'slime-contribs "2.3.2") + +(add-hook 'lisp-mode-hook 'slime-lisp-mode-hook) + +(provide 'slime-autoloads) + +;;; slime-autoloads.el ends here diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/slime-tests.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/slime-tests.el new file mode 100644 index 0000000..87f81f1 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/slime-tests.el @@ -0,0 +1,1459 @@ +;;; slime-tests.el --- Automated tests for slime.el +;; +;;;; License +;; Copyright (C) 2003 Eric Marsden, Luke Gorrie, Helmut Eller +;; Copyright (C) 2004,2005,2006 Luke Gorrie, Helmut Eller +;; Copyright (C) 2007,2008,2009 Helmut Eller, Tobias C. Rittweiler +;; Copyright (C) 2013 +;; +;; For a detailed list of contributors, see the manual. +;; +;; This program is free software; you can redistribute it and/or +;; modify it under the terms of the GNU General Public License as +;; published by the Free Software Foundation; either version 2 of +;; the License, or (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public +;; License along with this program; if not, write to the Free +;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +;; MA 02111-1307, USA. + + +;;;; Tests +(require 'slime) +(require 'ert nil t) +(require 'ert "lib/ert" t) ;; look for bundled version for Emacs 23 +(require 'cl-lib) +(require 'bytecomp) ; byte-compile-current-file +(eval-when-compile + (require 'cl)) ; lexical-let + +(defun slime-shuffle-list (list) + (let* ((len (length list)) + (taken (make-vector len nil)) + (result (make-vector len nil))) + (dolist (e list) + (while (let ((i (random len))) + (cond ((aref taken i)) + (t (aset taken i t) + (aset result i e) + nil))))) + (append result '()))) + +(defun slime-batch-test (&optional test-name randomize) + "Run the test suite in batch-mode. +Exits Emacs when finished. The exit code is the number of failed tests." + (interactive) + (let ((ert-debug-on-error nil) + (timeout 30) + (slime-background-message-function #'ignore)) + (slime) + ;; Block until we are up and running. + (lexical-let (timed-out) + (run-with-timer timeout nil + (lambda () (setq timed-out t))) + (while (not (slime-connected-p)) + (sit-for 1) + (when timed-out + (when noninteractive + (kill-emacs 252))))) + (slime-sync-to-top-level 5) + (let* ((selector (if randomize + `(member ,@(slime-shuffle-list + (ert-select-tests (or test-name t) t))) + (or test-name t))) + (ert-fun (if noninteractive + 'ert-run-tests-batch + 'ert))) + (let ((stats (funcall ert-fun selector))) + (if noninteractive + (kill-emacs (ert-stats-completed-unexpected stats))))))) + +(defun slime-skip-test (message) + ;; ERT for Emacs 23 and earlier doesn't have `ert-skip' + (if (fboundp 'ert-skip) + (ert-skip message) + (message (concat "SKIPPING: " message)) + (ert-pass))) + +(defun slime-tests--undefine-all () + (dolist (test (ert-select-tests t t)) + (let* ((sym (ert-test-name test))) + (cl-assert (eq (get sym 'ert--test) test)) + (cl-remprop sym 'ert--test)))) + +(slime-tests--undefine-all) + +(eval-and-compile + (defun slime-tests-auto-tags () + (append '(slime) + (let ((file-name (or load-file-name + byte-compile-current-file))) + (if (and file-name + (string-match "contrib/test/slime-\\(.*\\)\.elc?$" + file-name)) + (list 'contrib (intern (match-string 1 file-name))) + '(core))))) + + (defmacro define-slime-ert-test (name &rest args) + "Like `ert-deftest', but set tags automatically. +Also don't error if `ert.el' is missing." + (if (not (featurep 'ert)) + (warn "No ert.el found: not defining test %s" + name) + (let* ((docstring (and (stringp (second args)) + (second args))) + (args (if docstring + (cddr args) + (cdr args))) + (tags (slime-tests-auto-tags))) + `(ert-deftest ,name () ,(or docstring "No docstring for this test.") + :tags ',tags + ,@args)))) + + (defun slime-test-ert-test-for (name input i doc body fails-for style fname) + `(define-slime-ert-test + ,(intern (format "%s-%d" name i)) () + ,(format "For input %s, %s" (truncate-string-to-width + (format "%s" input) + 15 nil nil 'ellipsis) + (replace-regexp-in-string "^.??\\(\\w+\\)" + (lambda (s) (downcase s)) + doc + t)) + ,@(if fails-for + `(:expected-result '(satisfies + (lambda (result) + (ert-test-result-type-p + result + (if (member + (slime-lisp-implementation-name) + ',fails-for) + :failed + :passed)))))) + + ,@(when style + `((let ((style (slime-communication-style))) + (when (not (member style ',style)) + (slime-skip-test (format "test not applicable for style %s" + style)))))) + (apply #',fname ',input)))) + +(defmacro def-slime-test (name args doc inputs &rest body) + "Define a test case. +NAME ::= SYMBOL | (SYMBOL OPTION*) is a symbol naming the test. +OPTION ::= (:fails-for IMPLEMENTATION*) | (:style COMMUNICATION-STYLE*) +ARGS is a lambda-list. +DOC is a docstring. +INPUTS is a list of argument lists, each tested separately. +BODY is the test case. The body can use `slime-check' to test +conditions (assertions)." + (declare (debug (&define name sexp sexp sexp &rest def-form))) + (if (not (featurep 'ert)) + (warn "No ert.el found: not defining test %s" + name) + `(progn + ,@(cl-destructuring-bind (name &rest options) + (if (listp name) name (list name)) + (let ((fname (intern (format "slime-test-%s" name)))) + (cons `(defun ,fname ,args + (slime-sync-to-top-level 0.3) + ,@body + (slime-sync-to-top-level 0.3)) + (cl-loop for input in (eval inputs) + for i from 1 + with fails-for = (cdr (assoc :fails-for options)) + with style = (cdr (assoc :style options)) + collect (slime-test-ert-test-for name + input + i + doc + body + fails-for + style + fname)))))))) + +(put 'def-slime-test 'lisp-indent-function 4) + +(defmacro slime-check (check &rest body) + (declare (indent defun)) + `(unless (progn ,@body) + (ert-fail ,(cl-etypecase check + (cons `(concat "Ooops, " ,(cons 'format check))) + (string `(concat "Check failed: " ,check)) + (symbol `(concat "Check failed: " ,(symbol-name check))))))) + + +;;;;; Test case definitions +(defun slime-check-top-level () ;(&optional _test-name) + (accept-process-output nil 0.001) + (slime-check "At the top level (no debugging or pending RPCs)" + (slime-at-top-level-p))) + +(defun slime-at-top-level-p () + (and (not (sldb-get-default-buffer)) + (null (slime-rex-continuations)))) + +(defun slime-wait-condition (name predicate timeout) + (let ((end (time-add (current-time) (seconds-to-time timeout)))) + (while (not (funcall predicate)) + (let ((now (current-time))) + (message "waiting for condition: %s [%s.%06d]" name + (format-time-string "%H:%M:%S" now) (third now))) + (cond ((time-less-p end (current-time)) + (error "Timeout waiting for condition: %S" name)) + (t + ;; XXX if a process-filter enters a recursive-edit, we + ;; hang forever + (accept-process-output nil 0.1)))))) + +(defun slime-sync-to-top-level (timeout) + (slime-wait-condition "top-level" #'slime-at-top-level-p timeout)) + +;; XXX: unused function +(defun slime-check-sldb-level (expected) + (let ((sldb-level (let ((sldb (sldb-get-default-buffer))) + (if sldb + (with-current-buffer sldb + sldb-level))))) + (slime-check ("SLDB level (%S) is %S" expected sldb-level) + (equal expected sldb-level)))) + +(defun slime-test-expect (_name expected actual &optional test) + (when (stringp expected) (setq expected (substring-no-properties expected))) + (when (stringp actual) (setq actual (substring-no-properties actual))) + (if test + (should (funcall test expected actual)) + (should (equal expected actual)))) + +(defun sldb-level () + (let ((sldb (sldb-get-default-buffer))) + (if sldb + (with-current-buffer sldb + sldb-level)))) + +(defun slime-sldb-level= (level) + (equal level (sldb-level))) + +(eval-when-compile + (defvar slime-test-symbols + '(("foobar") ("foo@bar") ("@foobar") ("foobar@") ("\\@foobar") + ("|asdf||foo||bar|") + ("\\#") + ("\\(setf\\ car\\)")))) + +(defun slime-check-symbol-at-point (prefix symbol suffix) + ;; We test that `slime-symbol-at-point' works at every + ;; character of the symbol name. + (with-temp-buffer + (lisp-mode) + (insert prefix) + (let ((start (point))) + (insert symbol suffix) + (dotimes (i (length symbol)) + (goto-char (+ start i)) + (slime-test-expect (format "Check `%s' (at %d)..." + (buffer-string) (point)) + symbol + (slime-symbol-at-point) + #'equal))))) + + + +(def-slime-test symbol-at-point.2 (sym) + "fancy symbol-name _not_ at BOB/EOB" + slime-test-symbols + (slime-check-symbol-at-point "(foo " sym " bar)")) + +(def-slime-test symbol-at-point.3 (sym) + "fancy symbol-name with leading ," + (remove-if (lambda (s) (eq (aref (car s) 0) ?@)) slime-test-symbols) + (slime-check-symbol-at-point "," sym "")) + +(def-slime-test symbol-at-point.4 (sym) + "fancy symbol-name with leading ,@" + slime-test-symbols + (slime-check-symbol-at-point ",@" sym "")) + +(def-slime-test symbol-at-point.5 (sym) + "fancy symbol-name with leading `" + slime-test-symbols + (slime-check-symbol-at-point "`" sym "")) + +(def-slime-test symbol-at-point.6 (sym) + "fancy symbol-name wrapped in ()" + slime-test-symbols + (slime-check-symbol-at-point "(" sym ")")) + +(def-slime-test symbol-at-point.7 (sym) + "fancy symbol-name wrapped in #< {DEADBEEF}>" + slime-test-symbols + (slime-check-symbol-at-point "#<" sym " {DEADBEEF}>")) + +;;(def-slime-test symbol-at-point.8 (sym) +;; "fancy symbol-name wrapped in #<>" +;; slime-test-symbols +;; (slime-check-symbol-at-point "#<" sym ">")) + +(def-slime-test symbol-at-point.9 (sym) + "fancy symbol-name wrapped in #| ... |#" + slime-test-symbols + (slime-check-symbol-at-point "#|\n" sym "\n|#")) + +(def-slime-test symbol-at-point.10 (sym) + "fancy symbol-name after #| )))(( |# (1)" + slime-test-symbols + (slime-check-symbol-at-point "#| )))(( #|\n" sym "")) + +(def-slime-test symbol-at-point.11 (sym) + "fancy symbol-name after #| )))(( |# (2)" + slime-test-symbols + (slime-check-symbol-at-point "#| )))(( #|" sym "")) + +(def-slime-test symbol-at-point.12 (sym) + "fancy symbol-name wrapped in \"...\"" + slime-test-symbols + (slime-check-symbol-at-point "\"\n" sym "\"\n")) + +(def-slime-test symbol-at-point.13 (sym) + "fancy symbol-name wrapped in \" )))(( \" (1)" + slime-test-symbols + (slime-check-symbol-at-point "\" )))(( \"\n" sym "")) + +(def-slime-test symbol-at-point.14 (sym) + "fancy symbol-name wrapped in \" )))(( \" (1)" + slime-test-symbols + (slime-check-symbol-at-point "\" )))(( \"" sym "")) + +(def-slime-test symbol-at-point.15 (sym) + "symbol-at-point after #." + slime-test-symbols + (slime-check-symbol-at-point "#." sym "")) + +(def-slime-test symbol-at-point.16 (sym) + "symbol-at-point after #+" + slime-test-symbols + (slime-check-symbol-at-point "#+" sym "")) + + +(def-slime-test sexp-at-point.1 (string) + "symbol-at-point after #'" + '(("foo") + ("#:foo") + ("#'foo") + ("#'(lambda (x) x)") + ("()")) + (with-temp-buffer + (lisp-mode) + (insert string) + (goto-char (point-min)) + (slime-test-expect (format "Check sexp `%s' (at %d)..." + (buffer-string) (point)) + string + (slime-sexp-at-point) + #'equal))) + +(def-slime-test narrowing () + "Check that narrowing is properly sustained." + '() + (slime-check-top-level) + (let ((random-buffer-name (symbol-name (cl-gensym))) + (defun-pos) (tmpbuffer)) + (with-temp-buffer + (dotimes (i 100) (insert (format ";;; %d. line\n" i))) + (setq tmpbuffer (current-buffer)) + (setq defun-pos (point)) + (insert (concat "(defun __foo__ (x y)" "\n" + " 'nothing)" "\n")) + (dotimes (i 100) (insert (format ";;; %d. line\n" (+ 100 i)))) + (slime-check "Checking that newly created buffer is not narrowed." + (not (slime-buffer-narrowed-p))) + + (goto-char defun-pos) + (narrow-to-defun) + (slime-check "Checking that narrowing succeeded." + (slime-buffer-narrowed-p)) + + (slime-with-popup-buffer (random-buffer-name) + (slime-check ("Checking that we're in Slime's temp buffer `%s'" + random-buffer-name) + (equal (buffer-name (current-buffer)) random-buffer-name))) + (with-current-buffer random-buffer-name + ;; Notice that we cannot quit the buffer within the extent + ;; of slime-with-output-to-temp-buffer. + (quit-window t)) + (slime-check ("Checking that we've got back from `%s'" + random-buffer-name) + (and (eq (current-buffer) tmpbuffer) + (= (point) defun-pos))) + + (slime-check "Checking that narrowing sustained \ +after quitting Slime's temp buffer." + (slime-buffer-narrowed-p)) + + (let ((slime-buffer-package "SWANK") + (symbol '*buffer-package*)) + (slime-edit-definition (symbol-name symbol)) + (slime-check ("Checking that we've got M-. into swank.lisp. %S" symbol) + (string= (file-name-nondirectory (buffer-file-name)) + "swank.lisp")) + (slime-pop-find-definition-stack) + (slime-check ("Checking that we've got back.") + (and (eq (current-buffer) tmpbuffer) + (= (point) defun-pos))) + + (slime-check "Checking that narrowing sustained after M-," + (slime-buffer-narrowed-p))) + )) + (slime-check-top-level)) + +(defun slime-test--display-region-eval-arg (line window-height) + (cl-etypecase line + (number line) + (cons (slime-dcase line + ((+h line) + (+ (slime-test--display-region-eval-arg line window-height) + window-height)) + ((-h line) + (- (slime-test--display-region-eval-arg line window-height) + window-height)))))) + +(defun slime-test--display-region-line-to-position (line window-height) + (let ((line (slime-test--display-region-eval-arg line window-height))) + (save-excursion + (goto-char (point-min)) + (forward-line (1- line)) + (line-beginning-position)))) + +(def-slime-test display-region + (start end pos window-start expected-window-start expected-point) + "Test `slime-display-region'." + ;; numbers are actually lines numbers + '(;; region visible, point in region + (2 4 3 1 1 3) + ;; region visible, point visible but ouside region + (2 4 5 1 1 5) + ;; end not visible, point at start + (2 (+h 2) 2 1 2 2) + ;; start not visible, point at start + ((+h 2) (+h 500) (+h 2) 1 (+h 2) (+h 2)) + ;; start not visible, point after end + ((+h 2) (+h 500) (+h 6) 1 (+h 2) (+h 6)) + ;; end - start should be visible, point after end + ((+h 2) (+h 7) (+h 10) 1 (-h (+h 7)) (+h 6)) + ;; region is window-height + 1 and ends with newline + ((+h -2) (+h (+h -3)) (+h -2) 1 (+h -3) (+h -2)) + (2 (+h 1) 3 1 1 3) + (2 (+h 0) 3 1 1 3) + (2 (+h -1) 3 1 1 3) + ;; start and end are the beginning + (1 1 1 1 1 1) + ;; + (1 (+h 1) (+h 22) (+h 20) 1 (+h 0)) + ) + (when noninteractive + (slime-skip-test "Can't test slime-display-region in batch mode")) + (with-temp-buffer + (dotimes (i 1000) + (insert (format "%09d\n" i))) + (let* ((win (display-buffer (current-buffer) t)) + (wh (window-text-height win))) + (cl-macrolet ((l2p (l) + `(slime-test--display-region-line-to-position ,l wh))) + (select-window win) + (set-window-start win (l2p window-start)) + (redisplay) + (goto-char (l2p pos)) + (cl-assert (= (l2p window-start) (window-start win))) + (cl-assert (= (point) (l2p pos))) + (slime--display-region (l2p start) (l2p end)) + (redisplay) + (cl-assert (= (l2p expected-window-start) (window-start))) + (cl-assert (= (l2p expected-point) (point))) + )))) + +(def-slime-test find-definition + (name buffer-package snippet) + "Find the definition of a function or macro in swank.lisp." + '(("start-server" "SWANK" "(defun start-server ") + ("swank::start-server" "CL-USER" "(defun start-server ") + ("swank:start-server" "CL-USER" "(defun start-server ") + ("swank::connection" "CL-USER" "(defstruct (connection") + ("swank::*emacs-connection*" "CL-USER" "(defvar \\*emacs-connection\\*") + ) + (switch-to-buffer "*scratch*") ; not buffer of definition + (slime-check-top-level) + (let ((orig-buffer (current-buffer)) + (orig-pos (point)) + (enable-local-variables nil) ; don't get stuck on -*- eval: -*- + (slime-buffer-package buffer-package)) + (slime-edit-definition name) + ;; Postconditions + (slime-check ("Definition of `%S' is in swank.lisp." name) + (string= (file-name-nondirectory (buffer-file-name)) "swank.lisp")) + (slime-check ("Looking at '%s'." snippet) (looking-at snippet)) + (slime-pop-find-definition-stack) + (slime-check "Returning from definition restores original buffer/position." + (and (eq orig-buffer (current-buffer)) + (= orig-pos (point))))) + (slime-check-top-level)) + +(def-slime-test (find-definition.2 (:fails-for "allegro" "lispworks")) + (buffer-content buffer-package snippet) + "Check that we're able to find definitions even when +confronted with nasty #.-fu." + '(("#.(prog1 nil (defvar *foobar* 42)) + + (defun .foo. (x) + (+ x #.*foobar*)) + + #.(prog1 nil (makunbound '*foobar*)) + " + "SWANK" + "[ \t]*(defun .foo. " + ) + ("#.(prog1 nil (defvar *foobar* 42)) + + ;; some comment + (defun .foo. (x) + (+ x #.*foobar*)) + + #.(prog1 nil (makunbound '*foobar*)) + " + "SWANK" + "[ \t]*(defun .foo. " + ) + ("(in-package swank) + (eval-when (:compile-toplevel) (defparameter *bar* 456)) + (eval-when (:load-toplevel :execute) (makunbound '*bar*)) + (defun bar () #.*bar*) + (defun .foo. () 123)" + "SWANK" + "[ \t]*(defun .foo. () 123)")) + (let ((slime-buffer-package buffer-package)) + (with-temp-buffer + (insert buffer-content) + (slime-check-top-level) + (slime-eval + `(swank:compile-string-for-emacs + ,buffer-content + ,(buffer-name) + '((:position 0) (:line 1 1)) + ,nil + ,nil)) + (let ((bufname (buffer-name))) + (slime-edit-definition ".foo.") + (slime-check ("Definition of `.foo.' is in buffer `%s'." bufname) + (string= (buffer-name) bufname)) + (slime-check "Definition now at point." (looking-at snippet)))))) + +(def-slime-test (find-definition.3 + (:fails-for "abcl" "allegro" "clisp" "lispworks" "sbcl" + "ecl")) + (name source regexp) + "Extra tests for defstruct." + '(("swank::foo-struct" + "(progn + (defun foo-fun ()) + (defstruct (foo-struct (:constructor nil) (:predicate nil))) +)" + "(defstruct (foo-struct")) + (switch-to-buffer "*scratch*") + (with-temp-buffer + (insert source) + (let ((slime-buffer-package "SWANK")) + (slime-eval + `(swank:compile-string-for-emacs + ,source + ,(buffer-name) + '((:position 0) (:line 1 1)) + ,nil + ,nil))) + (let ((temp-buffer (current-buffer))) + (with-current-buffer "*scratch*" + (slime-edit-definition name) + (slime-check ("Definition of %S is in buffer `%s'." + name temp-buffer) + (eq (current-buffer) temp-buffer)) + (slime-check "Definition now at point." (looking-at regexp))) + ))) + +(def-slime-test complete-symbol + (prefix expected-completions) + "Find the completions of a symbol-name prefix." + '(("cl:compile" ("cl:compile" "cl:compile-file" "cl:compile-file-pathname" + "cl:compiled-function" "cl:compiled-function-p" + "cl:compiler-macro" "cl:compiler-macro-function")) + ("cl:foobar" ()) + ("swank::compile-file" ("swank::compile-file" + "swank::compile-file-for-emacs" + "swank::compile-file-if-needed" + "swank::compile-file-output" + "swank::compile-file-pathname")) + ("cl:m-v-l" ())) + (let ((completions (slime-simple-completions prefix))) + (slime-test-expect "Completion set" expected-completions completions))) + +(def-slime-test read-from-minibuffer + (input-keys expected-result) + "Test `slime-read-from-minibuffer' with INPUT-KEYS as events." + '(("( r e v e TAB SPC ' ( 1 SPC 2 SPC 3 ) ) RET" + "(reverse '(1 2 3))") + ("( c l : c o n TAB s t a n t l TAB SPC 4 2 ) RET" + "(cl:constantly 42)")) + (when noninteractive + (slime-skip-test "Can't use unread-command-events in batch mode")) + (let ((keys (eval `(kbd ,input-keys)))) ; kbd is a macro in Emacs 23 + (setq unread-command-events (listify-key-sequence keys))) + (let ((actual-result (slime-read-from-minibuffer "Test: "))) + (accept-process-output) ; run idle timers + (slime-test-expect "Completed string" expected-result actual-result))) + +(def-slime-test arglist + ;; N.B. Allegro apparently doesn't return the default values of + ;; optional parameters. Thus the regexp in the start-server + ;; expected value. In a perfect world we'd find a way to smooth + ;; over this difference between implementations--perhaps by + ;; convincing Franz to provide a function that does what we want. + (function-name expected-arglist) + "Lookup the argument list for FUNCTION-NAME. +Confirm that EXPECTED-ARGLIST is displayed." + '(("swank::operator-arglist" "(swank::operator-arglist name package)") + ("swank::compute-backtrace" "(swank::compute-backtrace start end)") + ("swank::emacs-connected" "(swank::emacs-connected)") + ("swank::compile-string-for-emacs" + "(swank::compile-string-for-emacs \ +string buffer position filename policy)") + ("swank::connection.socket-io" + "(swank::connection.socket-io \ +\\(struct\\(ure\\)?\\|object\\|instance\\|x\\|connection\\))") + ("cl:lisp-implementation-type" "(cl:lisp-implementation-type)") + ("cl:class-name" + "(cl:class-name \\(class\\|object\\|instance\\|structure\\))")) + (let ((arglist (slime-eval `(swank:operator-arglist ,function-name + "swank")))) + (slime-test-expect "Argument list is as expected" + expected-arglist (and arglist (downcase arglist)) + (lambda (pattern arglist) + (and arglist (string-match pattern arglist)))))) + +(defun slime-test--compile-defun (program subform) + (slime-check-top-level) + (with-temp-buffer + (lisp-mode) + (insert program) + (let ((font-lock-verbose nil)) + (setq slime-buffer-package ":swank") + (slime-compile-string (buffer-string) 1) + (setq slime-buffer-package ":cl-user") + (slime-sync-to-top-level 5) + (goto-char (point-max)) + (slime-previous-note) + (slime-check error-location-correct + (equal (read (current-buffer)) subform)))) + (slime-check-top-level)) + +(def-slime-test (compile-defun (:fails-for "allegro" "lispworks" "clisp")) + (program subform) + "Compile PROGRAM containing errors. +Confirm that SUBFORM is correctly located." + '(("(defun cl-user::foo () (cl-user::bar))" (cl-user::bar)) + ("(defun cl-user::foo () + #\\space + ;;Sdf + (cl-user::bar))" + (cl-user::bar)) + ("(defun cl-user::foo () + #+(or)skipped + #| #||# + #||# |# + (cl-user::bar))" + (cl-user::bar)) + ("(defun cl-user::foo () + \"\\\" bla bla \\\"\" + (cl-user::bar))" + (cl-user::bar)) + ("(defun cl-user::foo () + #.*log-events* + (cl-user::bar))" + (cl-user::bar)) + ("#.'(defun x () (/ 1 0)) + (defun foo () + (cl-user::bar)) + + " + (cl-user::bar))) + (slime-test--compile-defun program subform)) + +;; This test ideally would be collapsed into the previous +;; compile-defun test, but only 1 case fails for ccl--and that's here +(def-slime-test (compile-defun-with-reader-conditionals + (:fails-for "allegro" "lispworks" "clisp" "ccl")) + (program subform) + "Compile PROGRAM containing errors. +Confirm that SUBFORM is correctly located." + '(("(defun foo () + #+#.'(:and) (/ 1 0))" + (/ 1 0))) + (slime-test--compile-defun program subform)) + +;; SBCL used to pass this one but since they changed the +;; backquote/unquote reader it fails. +(def-slime-test (compile-defun-with-backquote + (:fails-for "allegro" "lispworks" "clisp" "sbcl")) + (program subform) + "Compile PROGRAM containing errors. +Confirm that SUBFORM is correctly located." + '(("(defun cl-user::foo () + (list `(1 ,(random 10) 2 ,@(make-list (random 10)) 3 + ,(cl-user::bar))))" + (cl-user::bar))) + (slime-test--compile-defun program subform)) + +(def-slime-test (compile-file (:fails-for "allegro" "clisp")) + (string) + "Insert STRING in a file, and compile it." + `((,(pp-to-string '(defun foo () nil)))) + (let ((filename "/tmp/slime-tmp-file.lisp")) + (with-temp-file filename + (insert string)) + (let ((cell (cons nil nil))) + (slime-eval-async + `(swank:compile-file-for-emacs ,filename nil) + (slime-rcurry (lambda (result cell) + (setcar cell t) + (setcdr cell result)) + cell)) + (slime-wait-condition "Compilation finished" (lambda () (car cell)) + 0.5) + (let ((result (cdr cell))) + (slime-check "Compilation successfull" + (eq (slime-compilation-result.successp result) t)))))) + +(def-slime-test utf-8-source + (input output) + "Source code containing utf-8 should work" + (list (let* ((bytes "\343\201\212\343\201\257\343\202\210\343\201\206") + ;;(encode-coding-string (string #x304a #x306f #x3088 #x3046) + ;; 'utf-8) + (string (decode-coding-string bytes 'utf-8-unix))) + (assert (equal bytes (encode-coding-string string 'utf-8-unix))) + (list (concat "(defun cl-user::foo () \"" string "\")") + string))) + (slime-eval `(cl:eval (cl:read-from-string ,input))) + (slime-test-expect "Eval result correct" + output (slime-eval '(cl-user::foo))) + (let ((cell (cons nil nil))) + (let ((hook (slime-curry (lambda (cell &rest _) (setcar cell t)) cell))) + (add-hook 'slime-compilation-finished-hook hook) + (unwind-protect + (progn + (slime-compile-string input 0) + (slime-wait-condition "Compilation finished" + (lambda () (car cell)) + 0.5) + (slime-test-expect "Compile-string result correct" + output (slime-eval '(cl-user::foo)))) + (remove-hook 'slime-compilation-finished-hook hook)) + (let ((filename "/tmp/slime-tmp-file.lisp")) + (setcar cell nil) + (add-hook 'slime-compilation-finished-hook hook) + (unwind-protect + (with-temp-buffer + (when (fboundp 'set-buffer-multibyte) + (set-buffer-multibyte t)) + (setq buffer-file-coding-system 'utf-8-unix) + (setq buffer-file-name filename) + (insert ";; -*- coding: utf-8-unix -*- \n") + (insert input) + (let ((coding-system-for-write 'utf-8-unix)) + (write-region nil nil filename nil t)) + (let ((slime-load-failed-fasl 'always)) + (slime-compile-and-load-file) + (slime-wait-condition "Compilation finished" + (lambda () (car cell)) + 0.5)) + (slime-test-expect "Compile-file result correct" + output (slime-eval '(cl-user::foo)))) + (remove-hook 'slime-compilation-finished-hook hook) + (ignore-errors (delete-file filename))))))) + +(def-slime-test async-eval-debugging (depth) + "Test recursive debugging of asynchronous evaluation requests." + '((1) (2) (3)) + (lexical-let ((depth depth) + (debug-hook-max-depth 0)) + (let ((debug-hook + (lambda () + (with-current-buffer (sldb-get-default-buffer) + (when (> sldb-level debug-hook-max-depth) + (setq debug-hook-max-depth sldb-level) + (if (= sldb-level depth) + ;; We're at maximum recursion - time to unwind + (sldb-quit) + ;; Going down - enter another recursive debug + ;; Recursively debug. + (slime-eval-async '(error)))))))) + (let ((sldb-hook (cons debug-hook sldb-hook))) + (slime-eval-async '(error)) + (slime-sync-to-top-level 5) + (slime-check ("Maximum depth reached (%S) is %S." + debug-hook-max-depth depth) + (= debug-hook-max-depth depth)))))) + +(def-slime-test unwind-to-previous-sldb-level (level2 level1) + "Test recursive debugging and returning to lower SLDB levels." + '((2 1) (4 2)) + (slime-check-top-level) + (lexical-let ((level2 level2) + (level1 level1) + (state 'enter) + (max-depth 0)) + (let ((debug-hook + (lambda () + (with-current-buffer (sldb-get-default-buffer) + (setq max-depth (max sldb-level max-depth)) + (ecase state + (enter + (cond ((= sldb-level level2) + (setq state 'leave) + (sldb-invoke-restart (sldb-first-abort-restart))) + (t + (slime-eval-async `(cl:aref cl:nil ,sldb-level))))) + (leave + (cond ((= sldb-level level1) + (setq state 'ok) + (sldb-quit)) + (t + (sldb-invoke-restart (sldb-first-abort-restart)) + )))))))) + (let ((sldb-hook (cons debug-hook sldb-hook))) + (slime-eval-async `(cl:aref cl:nil 0)) + (slime-sync-to-top-level 15) + (slime-check-top-level) + (slime-check ("Maximum depth reached (%S) is %S." max-depth level2) + (= max-depth level2)) + (slime-check ("Final state reached.") + (eq state 'ok)))))) + +(defun sldb-first-abort-restart () + (let ((case-fold-search t)) + (cl-position-if (lambda (x) (string-match "abort" (car x))) + sldb-restarts))) + +(def-slime-test loop-interrupt-quit + () + "Test interrupting a loop." + '(()) + (slime-check-top-level) + (slime-eval-async '(cl:loop) (lambda (_) ) "CL-USER") + (accept-process-output nil 1) + (slime-check "In eval state." (slime-busy-p)) + (slime-interrupt) + (slime-wait-condition "First interrupt" (lambda () (slime-sldb-level= 1)) 5) + (with-current-buffer (sldb-get-default-buffer) + (sldb-quit)) + (slime-sync-to-top-level 5) + (slime-check-top-level)) + +(def-slime-test loop-interrupt-continue-interrupt-quit + () + "Test interrupting a previously interrupted but continued loop." + '(()) + (slime-check-top-level) + (slime-eval-async '(cl:loop) (lambda (_) ) "CL-USER") + (sleep-for 1) + (slime-wait-condition "running" #'slime-busy-p 5) + (slime-interrupt) + (slime-wait-condition "First interrupt" (lambda () (slime-sldb-level= 1)) 5) + (with-current-buffer (sldb-get-default-buffer) + (sldb-continue)) + (slime-wait-condition "running" (lambda () + (and (slime-busy-p) + (not (sldb-get-default-buffer)))) 5) + (slime-interrupt) + (slime-wait-condition "Second interrupt" (lambda () (slime-sldb-level= 1)) 5) + (with-current-buffer (sldb-get-default-buffer) + (sldb-quit)) + (slime-sync-to-top-level 5) + (slime-check-top-level)) + +(def-slime-test interactive-eval + () + "Test interactive eval and continuing from the debugger." + '(()) + (slime-check-top-level) + (lexical-let ((done nil)) + (let ((sldb-hook (lambda () (sldb-continue) (setq done t)))) + (slime-interactive-eval + "(progn\ + (cerror \"foo\" \"restart\")\ + (cerror \"bar\" \"restart\")\ + (+ 1 2))") + (while (not done) (accept-process-output)) + (slime-sync-to-top-level 5) + (slime-check-top-level) + (unless noninteractive + (let ((message (current-message))) + (slime-check "Minibuffer contains: \"3\"" + (equal "=> 3 (2 bits, #x3, #o3, #b11)" message))))))) + +(def-slime-test report-condition-with-circular-list + (format-control format-argument) + "Test conditions involving circular lists." + '(("~a" "(let ((x (cons nil nil))) (setf (cdr x) x))") + ("~a" "(let ((x (cons nil nil))) (setf (car x) x))") + ("~a" "(let ((x (cons (make-string 100000 :initial-element #\\X) nil)))\ + (setf (cdr x) x))")) + (slime-check-top-level) + (lexical-let ((done nil)) + (let ((sldb-hook (lambda () (sldb-continue) (setq done t)))) + (slime-interactive-eval + (format "(with-standard-io-syntax (cerror \"foo\" \"%s\" %s) (+ 1 2))" + format-control format-argument)) + (while (not done) (accept-process-output)) + (slime-sync-to-top-level 5) + (slime-check-top-level) + (unless noninteractive + (let ((message (current-message))) + (slime-check "Minibuffer contains: \"3\"" + (equal "=> 3 (2 bits, #x3, #o3, #b11)" message))))))) + +(def-slime-test interrupt-bubbling-idiot + () + "Test interrupting a loop that sends a lot of output to Emacs." + '(()) + (accept-process-output nil 1) + (slime-check-top-level) + (slime-eval-async '(cl:loop :for i :from 0 :do (cl:progn (cl:print i) + (cl:finish-output))) + (lambda (_) ) + "CL-USER") + (sleep-for 1) + (slime-interrupt) + (slime-wait-condition "Debugger visible" + (lambda () + (and (slime-sldb-level= 1) + (get-buffer-window (sldb-get-default-buffer)))) + 30) + (with-current-buffer (sldb-get-default-buffer) + (sldb-quit)) + (slime-sync-to-top-level 5)) + +(def-slime-test (interrupt-encode-message (:style :sigio)) + () + "Test interrupt processing during swank::encode-message" + '(()) + (slime-eval-async '(cl:loop :for i :from 0 + :do (swank::background-message "foo ~d" i))) + (sleep-for 1) + (slime-eval-async '(cl:/ 1 0)) + (slime-wait-condition "Debugger visible" + (lambda () + (and (slime-sldb-level= 1) + (get-buffer-window (sldb-get-default-buffer)))) + 30) + (with-current-buffer (sldb-get-default-buffer) + (sldb-quit)) + (slime-sync-to-top-level 5)) + +(def-slime-test inspector + (exp) + "Test basic inspector workingness." + '(((let ((h (make-hash-table))) + (loop for i below 10 do (setf (gethash i h) i)) + h)) + ((make-array 10)) + ((make-list 10)) + ('cons) + (#'cons)) + (slime-inspect (prin1-to-string exp)) + (cl-assert (not (slime-inspector-visible-p))) + (slime-wait-condition "Inspector visible" #'slime-inspector-visible-p 5) + (with-current-buffer (window-buffer (selected-window)) + (slime-inspector-quit)) + (slime-wait-condition "Inspector closed" + (lambda () (not (slime-inspector-visible-p))) + 5) + (slime-sync-to-top-level 1)) + +(defun slime-buffer-visible-p (name) + (let ((buffer (window-buffer (selected-window)))) + (string-match name (buffer-name buffer)))) + +(defun slime-inspector-visible-p () + (slime-buffer-visible-p (slime-buffer-name :inspector))) + +(defun slime-execute-as-command (name) + "Execute `name' as if it was done by the user through the +Command Loop. Similiar to `call-interactively' but also pushes on +the buffer's undo-list." + (undo-boundary) + (call-interactively name)) + +(def-slime-test macroexpand + (macro-defs bufcontent expansion1 search-str expansion2) + "foo" + '((("(defmacro qwertz (&body body) `(list :qwertz ',body))" + "(defmacro yxcv (&body body) `(list :yxcv (qwertz ,@body)))") + "(yxcv :A :B :C)" + "(list :yxcv (qwertz :a :b :c))" + "(qwertz" + "(list :yxcv (list :qwertz '(:a :b :c)))")) + (slime-check-top-level) + (setq slime-buffer-package ":swank") + (with-temp-buffer + (lisp-mode) + (dolist (def macro-defs) + (slime-compile-string def 0) + (slime-sync-to-top-level 5)) + (insert bufcontent) + (goto-char (point-min)) + (slime-execute-as-command 'slime-macroexpand-1) + (slime-wait-condition "Macroexpansion buffer visible" + (lambda () + (slime-buffer-visible-p + (slime-buffer-name :macroexpansion))) + 5) + (with-current-buffer (get-buffer (slime-buffer-name :macroexpansion)) + (slime-test-expect "Initial macroexpansion is correct" + expansion1 + (downcase (buffer-string)) + #'slime-test-macroexpansion=) + (search-forward search-str) + (backward-up-list) + (slime-execute-as-command 'slime-macroexpand-1-inplace) + (slime-sync-to-top-level 3) + (slime-test-expect "In-place macroexpansion is correct" + expansion2 + (downcase (buffer-string)) + #'slime-test-macroexpansion=) + (slime-execute-as-command 'slime-macroexpand-undo) + (slime-test-expect "Expansion after undo is correct" + expansion1 + (downcase (buffer-string)) + #'slime-test-macroexpansion=))) + (setq slime-buffer-package ":cl-user")) + +(defun slime-test-macroexpansion= (string1 string2) + (let ((string1 (replace-regexp-in-string " *\n *" " " string1)) + (string2 (replace-regexp-in-string " *\n *" " " string2))) + (equal string1 string2))) + +(def-slime-test indentation (buffer-content point-markers) + "Check indentation update to work correctly." + '((" +\(in-package :swank) + +\(defmacro with-lolipop (&body body) + `(progn ,@body)) + +\(defmacro lolipop (&body body) + `(progn ,@body)) + +\(with-lolipop + 1 + 2 + 42) + +\(lolipop + 1 + 2 + 23) +" + ("23" "42"))) + (with-temp-buffer + (lisp-mode) + (slime-lisp-mode-hook) + (insert buffer-content) + (slime-compile-region (point-min) (point-max)) + (slime-sync-to-top-level 3) + (slime-update-indentation) + (slime-sync-to-top-level 3) + (dolist (marker point-markers) + (search-backward marker) + (beginning-of-defun) + (indent-sexp)) + (slime-test-expect "Correct buffer content" + buffer-content + (substring-no-properties (buffer-string))))) + +(def-slime-test break + (times exp) + "Test whether BREAK invokes SLDB." + (let ((exp1 '(break))) + `((1 ,exp1) (2 ,exp1) (3 ,exp1))) + (accept-process-output nil 0.2) + (slime-check-top-level) + (slime-eval-async + `(cl:eval (cl:read-from-string + ,(prin1-to-string `(dotimes (i ,times) + (unless (= i 0) + (swank::sleep-for 1)) + ,exp))))) + (dotimes (_i times) + (slime-wait-condition "Debugger visible" + (lambda () + (and (slime-sldb-level= 1) + (get-buffer-window + (sldb-get-default-buffer)))) + 3) + (with-current-buffer (sldb-get-default-buffer) + (sldb-continue)) + (slime-wait-condition "sldb closed" + (lambda () (not (sldb-get-default-buffer))) + 0.5)) + (slime-sync-to-top-level 1)) + +(def-slime-test (break2 (:fails-for "cmucl" "allegro")) + (times exp) + "Backends should arguably make sure that BREAK does not depend +on *DEBUGGER-HOOK*." + (let ((exp2 + '(block outta + (let ((*debugger-hook* (lambda (c h) (return-from outta 42)))) + (break))))) + `((1 ,exp2) (2 ,exp2) (3 ,exp2))) + (slime-test-break times exp)) + +(def-slime-test locally-bound-debugger-hook + () + "Test that binding *DEBUGGER-HOOK* locally works properly." + '(()) + (accept-process-output nil 1) + (slime-check-top-level) + (slime-compile-string + (prin1-to-string `(defun cl-user::quux () + (block outta + (let ((*debugger-hook* + (lambda (c hook) + (declare (ignore c hook)) + (return-from outta 42)))) + (error "FOO"))))) + 0) + (slime-sync-to-top-level 2) + (slime-eval-async '(cl-user::quux)) + ;; FIXME: slime-wait-condition returns immediately if the test returns true + (slime-wait-condition "Checking that Debugger does not popup" + (lambda () + (not (sldb-get-default-buffer))) + 3) + (slime-sync-to-top-level 5)) + +(def-slime-test end-of-file + (expr) + "Signalling END-OF-FILE should invoke the debugger." + '(((cl:error 'cl:end-of-file)) + ((cl:read-from-string ""))) + (let ((value (slime-eval + `(cl:let ((condition nil)) + (cl:with-simple-restart + (cl:continue "continue") + (cl:let ((cl:*debugger-hook* + (cl:lambda (c h) + (cl:setq condition c) + (cl:continue)))) + ,expr)) + (cl:if (cl:typep condition 'cl:end-of-file) t))))) + (slime-test-expect "Debugger invoked" t value))) + +(def-slime-test interrupt-at-toplevel + () + "Let's see what happens if we send a user interrupt at toplevel." + '(()) + (slime-check-top-level) + (unless (and (eq (slime-communication-style) :spawn) + (not (featurep 'slime-repl))) + (slime-interrupt) + (slime-wait-condition + "Debugger visible" + (lambda () + (and (slime-sldb-level= 1) + (get-buffer-window (sldb-get-default-buffer)))) + 5) + (with-current-buffer (sldb-get-default-buffer) + (sldb-quit)) + (slime-sync-to-top-level 5))) + +(def-slime-test interrupt-in-debugger (interrupts continues) + "Let's see what happens if we interrupt the debugger. +INTERRUPTS ... number of nested interrupts +CONTINUES ... how often the continue restart should be invoked" + '((1 0) (2 1) (4 2)) + (slime-check "No debugger" (not (sldb-get-default-buffer))) + (when (and (eq (slime-communication-style) :spawn) + (not (featurep 'slime-repl))) + (slime-eval-async '(swank::without-slime-interrupts + (swank::receive))) + (sit-for 0.2)) + (dotimes (i interrupts) + (slime-interrupt) + (let ((level (1+ i))) + (slime-wait-condition (format "Debug level %d reachend" level) + (lambda () (equal (sldb-level) level)) + 2))) + (dotimes (i continues) + (with-current-buffer (sldb-get-default-buffer) + (sldb-continue)) + (let ((level (- interrupts (1+ i)))) + (slime-wait-condition (format "Return to debug level %d" level) + (lambda () (equal (sldb-level) level)) + 2))) + (with-current-buffer (sldb-get-default-buffer) + (sldb-quit)) + (slime-sync-to-top-level 1)) + +(def-slime-test flow-control + (n delay interrupts) + "Let Lisp produce output faster than Emacs can consume it." + `((400 0.03 3)) + (when noninteractive + (slime-skip-test "test is currently unstable")) + (slime-check "No debugger" (not (sldb-get-default-buffer))) + (slime-eval-async `(swank:flow-control-test ,n ,delay)) + (sleep-for 0.2) + (dotimes (_i interrupts) + (slime-interrupt) + (slime-wait-condition "In debugger" (lambda () (slime-sldb-level= 1)) 5) + (slime-check "In debugger" (slime-sldb-level= 1)) + (with-current-buffer (sldb-get-default-buffer) + (sldb-continue)) + (slime-wait-condition "No debugger" (lambda () (slime-sldb-level= nil)) 3) + (slime-check "Debugger closed" (slime-sldb-level= nil))) + (slime-sync-to-top-level 8)) + +(def-slime-test sbcl-world-lock + (n delay) + "Print something from *MACROEXPAND-HOOK*. +In SBCL, the compiler grabs a lock which can be problematic because +no method dispatch code can be generated for other threads. +This test will fail more likely before dispatch caches are warmed up." + '((10 0.03) + ;;((cl:+ swank::send-counter-limit 10) 0.03) + ) + (slime-test-expect "no error" + 123 + (slime-eval + `(cl:let ((cl:*macroexpand-hook* + (cl:lambda (fun form env) + (swank:flow-control-test ,n ,delay) + (cl:funcall fun form env)))) + (cl:eval '(cl:macrolet ((foo () 123)) + (foo))))))) + +(def-slime-test (disconnect-one-connection (:style :spawn)) () + "`slime-disconnect' should disconnect only the current connection" + '(()) + (let ((connection-count (length slime-net-processes)) + (old-connection slime-default-connection) + (slime-connected-hook nil)) + (unwind-protect + (let ((slime-dispatching-connection + (slime-connect "localhost" + ;; Here we assume that the request will + ;; be evaluated in its own thread. + (slime-eval `(swank:create-server + :port 0 ; use random port + :style :spawn + :dont-close nil))))) + (slime-sync-to-top-level 3) + (slime-disconnect) + (slime-test-expect "Number of connections must remane the same" + connection-count + (length slime-net-processes))) + (slime-select-connection old-connection)))) + +(def-slime-test disconnect-and-reconnect + () + "Close the connetion. +Confirm that the subprocess continues gracefully. +Reconnect afterwards." + '(()) + (slime-check-top-level) + (let* ((c (slime-connection)) + (p (slime-inferior-process c))) + (with-current-buffer (process-buffer p) + (erase-buffer)) + (delete-process c) + (assert (equal (process-status c) 'closed) nil "Connection not closed") + (accept-process-output nil 0.1) + (assert (equal (process-status p) 'run) nil "Subprocess not running") + (with-current-buffer (process-buffer p) + (assert (< (buffer-size) 500) nil "Unusual output")) + (slime-inferior-connect p (slime-inferior-lisp-args p)) + (lexical-let ((hook nil) (p p)) + (setq hook (lambda () + (slime-test-expect + "We are connected again" p (slime-inferior-process)) + (remove-hook 'slime-connected-hook hook))) + (add-hook 'slime-connected-hook hook) + (slime-wait-condition "Lisp restarted" + (lambda () + (not (member hook slime-connected-hook))) + 5)))) + + +;;;; SLIME-loading tests that launch separate Emacsen +;;;; +(cl-defun slime-test-recipe-test-for (&key preflight + takeoff + landing) + (let ((success nil) + (test-file (make-temp-file "slime-recipe-" nil ".el")) + (test-forms + `((require 'cl) + (labels + ((die + (reason &optional more) + (princ reason) + (terpri) + (and more (pp more)) + (kill-emacs 254))) + (condition-case err + (progn ,@preflight) + (error + (die "Unexpected error running preflight forms" + err))) + (add-hook + 'slime-connected-hook + #'(lambda () + (condition-case err + (progn + ,@landing + (kill-emacs 0)) + (error + (die "Unexpected error running landing forms" + err)))) + t) + (condition-case err + (progn + ,@takeoff + ,(when (null landing) '(kill-emacs 0))) + (error + (die "Unexpected error running takeoff forms" + err))) + (with-timeout + (20 + (die "Timeout waiting for recipe test to finish." + takeoff)) + (while t (sit-for 1))))))) + (unwind-protect + (progn + (with-temp-buffer + (mapc #'insert (mapcar #'pp-to-string test-forms)) + (write-file test-file)) + (with-temp-buffer + (let ((retval + (call-process (concat invocation-directory invocation-name) + nil (list t nil) nil + "-Q" "--batch" + "-l" test-file))) + (unless (= 0 retval) + (ert-fail (buffer-substring + (+ (goto-char (point-min)) + (skip-chars-forward " \t\n")) + (+ (goto-char (point-max)) + (skip-chars-backward " \t\n"))))))) + (setq success t)) + (if success (delete-file test-file) + (message "Test failed: keeping %s for inspection" test-file))))) + +(define-slime-ert-test readme-recipe () + "Test the README.md's autoload recipe." + (slime-test-recipe-test-for + :preflight `((add-to-list 'load-path ,slime-path) + (require 'slime-autoloads) + (setq inferior-lisp-program ,inferior-lisp-program) + (setq slime-contribs '(slime-fancy))) + :takeoff `((call-interactively 'slime)) + :landing `((unless (and (featurep 'slime-repl) + (find 'swank-repl slime-required-modules)) + (die "slime-repl not loaded properly")) + (with-current-buffer (slime-repl-buffer) + (unless (and (string-match "^; +SLIME" (buffer-string)) + (string-match "CL-USER> *$" (buffer-string))) + (die "REPL prompt not properly setup" + (buffer-substring-no-properties (point-min) + (point-max)))))))) + +(define-slime-ert-test traditional-recipe () + "Test the README.md's traditional recipe." + (slime-test-recipe-test-for + :preflight `((add-to-list 'load-path ,slime-path) + (require 'slime) + (setq inferior-lisp-program ,inferior-lisp-program) + (slime-setup '(slime-fancy))) + :takeoff `((call-interactively 'slime)) + :landing `((unless (and (featurep 'slime-repl) + (find 'swank-repl slime-required-modules)) + (die "slime-repl not loaded properly")) + (with-current-buffer (slime-repl-buffer) + (unless (and (string-match "^; +SLIME" (buffer-string)) + (string-match "CL-USER> *$" (buffer-string))) + (die "REPL prompt not properly setup" + (buffer-substring-no-properties (point-min) + (point-max)))))))) + +(define-slime-ert-test readme-recipe-autoload-on-lisp-visit () + "Test more autoload bits in README.md's installation recipe." + (slime-test-recipe-test-for + :preflight `((add-to-list 'load-path ,slime-path) + (require 'slime-autoloads)) + :takeoff `((if (featurep 'slime) + (die "Didn't expect SLIME to be loaded so early!")) + (find-file ,(make-temp-file "slime-lisp-source-file" nil + ".lisp")) + (unless (featurep 'slime) + (die "Expected SLIME to be fully loaded by now"))))) + +(defun slime-test-eval-now (string) + (second (slime-eval `(swank:eval-and-grab-output ,string)))) + +(def-slime-test (slime-recompile-all-xrefs (:fails-for "cmucl")) () + "Test recompilation of all references within an xref buffer." + '(()) + (let* ((cell (cons nil nil)) + (hook (slime-curry (lambda (cell &rest _) (setcar cell t)) cell)) + (filename (make-temp-file "slime-recompile-all-xrefs" nil ".lisp"))) + (add-hook 'slime-compilation-finished-hook hook) + (unwind-protect + (with-temp-file filename + (set-visited-file-name filename) + (slime-test-eval-now "(defparameter swank::*.var.* nil)") + (insert "(in-package :swank) + (defun .fn1. ()) + (defun .fn2. () (.fn1.) #.*.var.*) + (defun .fn3. () (.fn1.) #.*.var.*)") + (save-buffer) + (slime-compile-and-load-file) + (slime-wait-condition "Compilation finished" + (lambda () (car cell)) + 0.5) + (slime-test-eval-now "(setq *.var.* t)") + (setcar cell nil) + (slime-xref :calls ".fn1." + (lambda (&rest args) + (apply #'slime-show-xrefs args) + (setcar cell t))) + (slime-wait-condition "Xrefs computed and displayed" + (lambda () (car cell)) + 0.5) + (setcar cell nil) + (with-current-buffer slime-xref-last-buffer + (slime-recompile-all-xrefs) + (slime-wait-condition "Compilation finished" + (lambda () (car cell)) + 0.5)) + (should (cl-equalp (list (slime-test-eval-now "(.fn2.)") + (slime-test-eval-now "(.fn3.)")) + '("T" "T")))) + (remove-hook 'slime-compilation-finished-hook hook) + (when slime-xref-last-buffer + (kill-buffer slime-xref-last-buffer))))) + +(provide 'slime-tests) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/slime.el b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/slime.el new file mode 100644 index 0000000..cce0f88 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/slime.el @@ -0,0 +1,7659 @@ +;;; slime.el --- Superior Lisp Interaction Mode for Emacs -*-lexical-binding:t-*- + +;; URL: https://github.com/slime/slime +;; Package-Requires: ((cl-lib "0.5") (macrostep "0.9")) +;; Keywords: languages, lisp, slime +;; Version: 2.24 + +;;;; License and Commentary + +;; Copyright (C) 2003 Eric Marsden, Luke Gorrie, Helmut Eller +;; Copyright (C) 2004,2005,2006 Luke Gorrie, Helmut Eller +;; Copyright (C) 2007,2008,2009 Helmut Eller, Tobias C. Rittweiler +;; +;; For a detailed list of contributors, see the manual. +;; +;; This program is free software; you can redistribute it and/or +;; modify it under the terms of the GNU General Public License as +;; published by the Free Software Foundation; either version 2 of +;; the License, or (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public +;; License along with this program; if not, write to the Free +;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +;; MA 02111-1307, USA. + +;;; Commentary: + +;; SLIME is the ``Superior Lisp Interaction Mode for Emacs.'' +;; +;; SLIME extends Emacs with support for interactive programming in +;; Common Lisp. The features are centered around slime-mode, an Emacs +;; minor-mode that complements the standard lisp-mode. While lisp-mode +;; supports editing Lisp source files, slime-mode adds support for +;; interacting with a running Common Lisp process for compilation, +;; debugging, documentation lookup, and so on. +;; +;; The slime-mode programming environment follows the example of +;; Emacs's native Emacs Lisp environment. We have also included good +;; ideas from similar systems (such as ILISP) and some new ideas of +;; our own. +;; +;; SLIME is constructed from two parts: a user-interface written in +;; Emacs Lisp, and a supporting server program written in Common +;; Lisp. The two sides are connected together with a socket and +;; communicate using an RPC-like protocol. +;; +;; The Lisp server is primarily written in portable Common Lisp. The +;; required implementation-specific functionality is specified by a +;; well-defined interface and implemented separately for each Lisp +;; implementation. This makes SLIME readily portable. + +;;; Code: + + +;;;; Dependencies and setup +(eval-and-compile + (require 'cl-lib nil t) + ;; For emacs 23, look for bundled version + (require 'cl-lib "lib/cl-lib")) + +(eval-when-compile (require 'cl)) ; defsetf, lexical-let + +(eval-and-compile + (if (< emacs-major-version 23) + (error "Slime requires an Emacs version of 23, or above"))) + +(require 'hyperspec "lib/hyperspec") +(require 'thingatpt) +(require 'comint) +(require 'pp) +(require 'easymenu) +(require 'outline) +(require 'arc-mode) +(require 'etags) +(require 'compile) + +(eval-when-compile + (require 'apropos) + (require 'gud) + (require 'lisp-mnt)) + +(declare-function lm-version "lisp-mnt") + +(defvar slime-path nil + "Directory containing the Slime package. +This is used to load the supporting Common Lisp library, Swank. +The default value is automatically computed from the location of +the Emacs Lisp package.") +(setq slime-path (file-name-directory load-file-name)) + +(defvar slime-version nil + "The version of SLIME that you're using.") +(setq slime-version + (eval-when-compile + (lm-version + (cl-find "slime.el" + (remove nil + (list load-file-name + (when (boundp 'byte-compile-current-file) + byte-compile-current-file))) + :key #'file-name-nondirectory + :test #'string-equal)))) + +(defvar slime-lisp-modes '(lisp-mode)) +(defvar slime-contribs nil + "A list of contrib packages to load with SLIME.") +(define-obsolete-variable-alias 'slime-setup-contribs +'slime-contribs "2.3.2") + +(defun slime-setup (&optional contribs) + "Setup Emacs so that lisp-mode buffers always use SLIME. +CONTRIBS is a list of contrib packages to load. If `nil', use +`slime-contribs'. " + (interactive) + (when (member 'lisp-mode slime-lisp-modes) + (add-hook 'lisp-mode-hook 'slime-lisp-mode-hook)) + (when contribs + (setq slime-contribs contribs)) + (slime--setup-contribs)) + +(defvar slime-required-modules '()) + +(defun slime--setup-contribs () + "Load and initialize contribs." + (dolist (c slime-contribs) + (unless (featurep c) + (require c) + (let ((init (intern (format "%s-init" c)))) + (when (fboundp init) + (funcall init)))))) + +(defun slime-lisp-mode-hook () + (slime-mode 1) + (set (make-local-variable 'lisp-indent-function) + 'common-lisp-indent-function)) + +(defvar slime-protocol-version nil) +(setq slime-protocol-version slime-version) + + +;;;; Customize groups +;; +;;;;; slime + +(defgroup slime nil + "Interaction with the Superior Lisp Environment." + :prefix "slime-" + :group 'applications) + +;;;;; slime-ui + +(defgroup slime-ui nil + "Interaction with the Superior Lisp Environment." + :prefix "slime-" + :group 'slime) + +(defcustom slime-truncate-lines t + "Set `truncate-lines' in popup buffers. +This applies to buffers that present lines as rows of data, such as +debugger backtraces and apropos listings." + :type 'boolean + :group 'slime-ui) + +(defcustom slime-kill-without-query-p nil + "If non-nil, kill SLIME processes without query when quitting Emacs. +This applies to the *inferior-lisp* buffer and the network connections." + :type 'boolean + :group 'slime-ui) + +;;;;; slime-lisp + +(defgroup slime-lisp nil + "Lisp server configuration." + :prefix "slime-" + :group 'slime) + +(defcustom slime-backend "swank-loader.lisp" + "The name of the Lisp file that loads the Swank server. +This name is interpreted relative to the directory containing +slime.el, but could also be set to an absolute filename." + :type 'string + :group 'slime-lisp) + +(defcustom slime-connected-hook nil + "List of functions to call when SLIME connects to Lisp." + :type 'hook + :group 'slime-lisp) + +(defcustom slime-enable-evaluate-in-emacs nil + "*If non-nil, the inferior Lisp can evaluate arbitrary forms in Emacs. +The default is nil, as this feature can be a security risk." + :type '(boolean) + :group 'slime-lisp) + +(defcustom slime-lisp-host "localhost" + "The default hostname (or IP address) to connect to." + :type 'string + :group 'slime-lisp) + +(defcustom slime-port 4005 + "Port to use as the default for `slime-connect'." + :type 'integer + :group 'slime-lisp) + +(defvar slime-connect-host-history (list slime-lisp-host)) +(defvar slime-connect-port-history (list (prin1-to-string slime-port))) + +(defvar slime-net-valid-coding-systems + '((iso-latin-1-unix nil "iso-latin-1-unix") + (iso-8859-1-unix nil "iso-latin-1-unix") + (binary nil "iso-latin-1-unix") + (utf-8-unix t "utf-8-unix") + (emacs-mule-unix t "emacs-mule-unix") + (euc-jp-unix t "euc-jp-unix")) + "A list of valid coding systems. +Each element is of the form: (NAME MULTIBYTEP CL-NAME)") + +(defun slime-find-coding-system (name) + "Return the coding system for the symbol NAME. +The result is either an element in `slime-net-valid-coding-systems' +of nil." + (let ((probe (assq name slime-net-valid-coding-systems))) + (when (and probe (if (fboundp 'check-coding-system) + (ignore-errors (check-coding-system (car probe))) + (eq (car probe) 'binary))) + probe))) + +(defcustom slime-net-coding-system + (car (cl-find-if 'slime-find-coding-system + slime-net-valid-coding-systems :key 'car)) + "Coding system used for network connections. +See also `slime-net-valid-coding-systems'." + :type (cons 'choice + (mapcar (lambda (x) + (list 'const (car x))) + slime-net-valid-coding-systems)) + :group 'slime-lisp) + +;;;;; slime-mode + +(defgroup slime-mode nil + "Settings for slime-mode Lisp source buffers." + :prefix "slime-" + :group 'slime) + +(defcustom slime-find-definitions-function 'slime-find-definitions-rpc + "Function to find definitions for a name. +The function is called with the definition name, a string, as its +argument." + :type 'function + :group 'slime-mode + :options '(slime-find-definitions-rpc + slime-etags-definitions + (lambda (name) + (append (slime-find-definitions-rpc name) + (slime-etags-definitions name))) + (lambda (name) + (or (slime-find-definitions-rpc name) + (and tags-table-list + (slime-etags-definitions name)))))) + +;; FIXME: remove one day +(defcustom slime-complete-symbol-function 'nil + "Obsolete. Use `slime-completion-at-point-functions' instead." + :group 'slime-mode + :type '(choice (const :tag "Compound" slime-complete-symbol*) + (const :tag "Fuzzy" slime-fuzzy-complete-symbol))) + +(make-obsolete-variable 'slime-complete-symbol-function + 'slime-completion-at-point-functions + "2015-10-18") + +(defcustom slime-completion-at-point-functions + '(slime-filename-completion + slime-simple-completion-at-point) + "List of functions to perform completion. +Works like `completion-at-point-functions'. +`slime--completion-at-point' uses this variable." + :group 'slime-mode) + +;;;;; slime-mode-faces + +(defgroup slime-mode-faces nil + "Faces in slime-mode source code buffers." + :prefix "slime-" + :group 'slime-mode) + +(defface slime-error-face + `((((class color) (background light)) + (:underline "red")) + (((class color) (background dark)) + (:underline "red")) + (t (:underline t))) + "Face for errors from the compiler." + :group 'slime-mode-faces) + +(defface slime-warning-face + `((((class color) (background light)) + (:underline "orange")) + (((class color) (background dark)) + (:underline "coral")) + (t (:underline t))) + "Face for warnings from the compiler." + :group 'slime-mode-faces) + +(defface slime-style-warning-face + `((((class color) (background light)) + (:underline "brown")) + (((class color) (background dark)) + (:underline "gold")) + (t (:underline t))) + "Face for style-warnings from the compiler." + :group 'slime-mode-faces) + +(defface slime-note-face + `((((class color) (background light)) + (:underline "brown4")) + (((class color) (background dark)) + (:underline "light goldenrod")) + (t (:underline t))) + "Face for notes from the compiler." + :group 'slime-mode-faces) + +(defface slime-early-deprecation-warning-face + `((((type graphic) (class color) (background light)) + (:strike-through "brown")) + (((type graphic) (class color) (background dark)) + (:strike-through "gold")) + (((type graphic)) + (:strike-through t)) + (((class color) (background light)) + (:underline "brown")) + (((class color) (background dark)) + (:underline "gold")) + (t + (:underline t))) + "Face for early deprecation warnings from the compiler." + :group 'slime-mode-faces) + +(defface slime-late-deprecation-warning-face + `((((type graphic) (class color) (background light)) + (:strike-through "orange")) + (((type graphic) (class color) (background dark)) + (:strike-through "coral")) + (((type graphic)) + (:strike-through t)) + (((class color) (background light)) + (:underline "orange")) + (((class color) (background dark)) + (:underline "coral")) + (t + (:underline t))) + "Face for late deprecation warnings from the compiler." + :group 'slime-mode-faces) + +(defface slime-final-deprecation-warning-face + `((((type graphic) (class color) (background light)) + (:strike-through "red")) + (((type graphic) (class color) (background dark)) + (:strike-through "red")) + (((type graphic)) + (:strike-through t)) + (((class color) (background light)) + (:underline "red")) + (((class color) (background dark)) + (:underline "red")) + (t + (:strike-through t))) + "Face for final deprecation warnings from the compiler." + :group 'slime-mode-faces) + +(defface slime-highlight-face + '((t (:inherit highlight :underline nil))) + "Face for compiler notes while selected." + :group 'slime-mode-faces) + +;;;;; sldb + +(defgroup slime-debugger nil + "Backtrace options and fontification." + :prefix "sldb-" + :group 'slime) + +(defmacro define-sldb-faces (&rest faces) + "Define the set of SLDB faces. +Each face specifiation is (NAME DESCRIPTION &optional PROPERTIES). +NAME is a symbol; the face will be called sldb-NAME-face. +DESCRIPTION is a one-liner for the customization buffer. +PROPERTIES specifies any default face properties." + `(progn ,@(cl-loop for face in faces + collect `(define-sldb-face ,@face)))) + +(defmacro define-sldb-face (name description &optional default) + (let ((facename (intern (format "sldb-%s-face" (symbol-name name))))) + `(defface ,facename + (list (list t ,default)) + ,(format "Face for %s." description) + :group 'slime-debugger))) + +(define-sldb-faces + (topline "the top line describing the error") + (condition "the condition class" + '(:inherit font-lock-warning-face)) + (section "the labels of major sections in the debugger buffer" + '(:inherit header-line)) + (frame-label "backtrace frame numbers" + '(:inherit shadow)) + (restart-type "restart names." + '(:inherit font-lock-keyword-face)) + (restart "restart descriptions") + (restart-number "restart numbers (correspond to keystrokes to invoke)" + '(:bold t)) + (frame-line "function names and arguments in the backtrace") + (restartable-frame-line + "frames which are surely restartable" + '(:foreground "lime green")) + (non-restartable-frame-line + "frames which are surely not restartable") + (detailed-frame-line + "function names and arguments in a detailed (expanded) frame") + (local-name "local variable names" + '(:inherit font-lock-variable-name-face)) + (local-value "local variable values") + (catch-tag "catch tags" + '(:inherit highlight))) + + +;;;; Minor modes + +;;;;; slime-mode + +(defvar slime-mode-indirect-map (make-sparse-keymap) + "Empty keymap which has `slime-mode-map' as it's parent. +This is a hack so that we can reinitilize the real slime-mode-map +more easily. See `slime-init-keymaps'.") + +(defvar slime-buffer-connection) +(defvar slime-dispatching-connection) +(defvar slime-current-thread) + +(defun slime--on () + (slime-setup-completion)) + +(defun slime--off () + (remove-hook 'completion-at-point-functions #'slime--completion-at-point t)) + +(define-minor-mode slime-mode + "\\\ +SLIME: The Superior Lisp Interaction Mode for Emacs (minor-mode). + +Commands to compile the current buffer's source file and visually +highlight any resulting compiler notes and warnings: +\\[slime-compile-and-load-file] - Compile and load the current buffer's file. +\\[slime-compile-file] - Compile (but not load) the current buffer's file. +\\[slime-compile-defun] - Compile the top-level form at point. + +Commands for visiting compiler notes: +\\[slime-next-note] - Goto the next form with a compiler note. +\\[slime-previous-note] - Goto the previous form with a compiler note. +\\[slime-remove-notes] - Remove compiler-note annotations in buffer. + +Finding definitions: +\\[slime-edit-definition] +- Edit the definition of the function called at point. +\\[slime-pop-find-definition-stack] +- Pop the definition stack to go back from a definition. + +Documentation commands: +\\[slime-describe-symbol] - Describe symbol. +\\[slime-apropos] - Apropos search. +\\[slime-disassemble-symbol] - Disassemble a function. + +Evaluation commands: +\\[slime-eval-defun] - Evaluate top-level from containing point. +\\[slime-eval-last-expression] - Evaluate sexp before point. +\\[slime-pprint-eval-last-expression] \ +- Evaluate sexp before point, pretty-print result. + +Full set of commands: +\\{slime-mode-map}" + :keymap slime-mode-indirect-map + :lighter (:eval (slime-modeline-string)) + (cond (slime-mode (slime--on)) + (t (slime--off)))) + + +;;;;;; Modeline + +(defun slime-modeline-string () + "Return the string to display in the modeline. +\"Slime\" only appears if we aren't connected. If connected, +include package-name, connection-name, and possibly some state +information." + (let ((conn (slime-current-connection))) + ;; Bail out early in case there's no connection, so we won't + ;; implicitly invoke `slime-connection' which may query the user. + (if (not conn) + (and slime-mode " Slime") + (let ((local (eq conn slime-buffer-connection)) + (pkg (slime-current-package))) + (concat " " + (if local "{" "[") + (if pkg (slime-pretty-package-name pkg) "?") + " " + ;; ignore errors for closed connections + (ignore-errors (slime-connection-name conn)) + (slime-modeline-state-string conn) + (if local "}" "]")))))) + +(defun slime-pretty-package-name (name) + "Return a pretty version of a package name NAME." + (cond ((string-match "^#?:\\(.*\\)$" name) + (match-string 1 name)) + ((string-match "^\"\\(.*\\)\"$" name) + (match-string 1 name)) + (t name))) + +(defun slime-modeline-state-string (conn) + "Return a string possibly describing CONN's state." + (cond ((not (eq (process-status conn) 'open)) + (format " %s" (process-status conn))) + ((let ((pending (length (slime-rex-continuations conn))) + (sldbs (length (sldb-buffers conn)))) + (cond ((and (zerop sldbs) (zerop pending)) nil) + ((zerop sldbs) (format " %s" pending)) + (t (format " %s/%s" pending sldbs))))))) + +(defun slime--recompute-modelines () + (force-mode-line-update t)) + + +;;;;; Key bindings + +(defvar slime-parent-map nil + "Parent keymap for shared between all Slime related modes.") + +(defvar slime-parent-bindings + '(("\M-." slime-edit-definition) + ("\M-," slime-pop-find-definition-stack) + ("\M-_" slime-edit-uses) ; for German layout + ("\M-?" slime-edit-uses) ; for USian layout + ("\C-x4." slime-edit-definition-other-window) + ("\C-x5." slime-edit-definition-other-frame) + ("\C-x\C-e" slime-eval-last-expression) + ("\C-\M-x" slime-eval-defun) + ;; Include PREFIX keys... + ("\C-c" slime-prefix-map))) + +(defvar slime-prefix-map nil + "Keymap for commands prefixed with `slime-prefix-key'.") + +(defvar slime-prefix-bindings + '(("\C-r" slime-eval-region) + (":" slime-interactive-eval) + ("\C-e" slime-interactive-eval) + ("E" slime-edit-value) + ("\C-l" slime-load-file) + ("\C-b" slime-interrupt) + ("\M-d" slime-disassemble-symbol) + ("\C-t" slime-toggle-trace-fdefinition) + ("I" slime-inspect) + ("\C-xt" slime-list-threads) + ("\C-xn" slime-next-connection) + ("\C-xp" slime-prev-connection) + ("\C-xc" slime-list-connections) + ("<" slime-list-callers) + (">" slime-list-callees) + ;; Include DOC keys... + ("\C-d" slime-doc-map) + ;; Include XREF WHO-FOO keys... + ("\C-w" slime-who-map) + )) + +(defvar slime-editing-map nil + "These keys are useful for buffers where the user can insert and +edit s-exprs, e.g. for source buffers and the REPL.") + +(defvar slime-editing-keys + `(;; Arglist display & completion + (" " slime-space) + ;; Evaluating + ;;("\C-x\M-e" slime-eval-last-expression-display-output :inferior t) + ("\C-c\C-p" slime-pprint-eval-last-expression) + ;; Macroexpand + ("\C-c\C-m" slime-expand-1) + ("\C-c\M-m" slime-macroexpand-all) + ;; Misc + ("\C-c\C-u" slime-undefine-function) + (,(kbd "C-M-.") slime-next-location) + (,(kbd "C-M-,") slime-previous-location) + ;; Obsolete, redundant bindings + ("\C-c\C-i" completion-at-point) + ;;("\M-*" pop-tag-mark) ; almost to clever + )) + +(defvar slime-mode-map nil + "Keymap for slime-mode.") + +(defvar slime-keys + '( ;; Compiler notes + ("\M-p" slime-previous-note) + ("\M-n" slime-next-note) + ("\C-c\M-c" slime-remove-notes) + ("\C-c\C-k" slime-compile-and-load-file) + ("\C-c\M-k" slime-compile-file) + ("\C-c\C-c" slime-compile-defun))) + +(defun slime-nop () + "The null command. Used to shadow currently-unused keybindings." + (interactive) + (call-interactively 'undefined)) + +(defvar slime-doc-map nil + "Keymap for documentation commands. Bound to a prefix key.") + +(defvar slime-doc-bindings + '((?a slime-apropos) + (?z slime-apropos-all) + (?p slime-apropos-package) + (?d slime-describe-symbol) + (?f slime-describe-function) + (?h slime-documentation-lookup) + (?~ common-lisp-hyperspec-format) + (?g common-lisp-hyperspec-glossary-term) + (?# common-lisp-hyperspec-lookup-reader-macro))) + +(defvar slime-who-map nil + "Keymap for who-xref commands. Bound to a prefix key.") + +(defvar slime-who-bindings + '((?c slime-who-calls) + (?w slime-calls-who) + (?r slime-who-references) + (?b slime-who-binds) + (?s slime-who-sets) + (?m slime-who-macroexpands) + (?a slime-who-specializes))) + +(defun slime-init-keymaps () + "(Re)initialize the keymaps for `slime-mode'." + (interactive) + (slime-init-keymap 'slime-doc-map t t slime-doc-bindings) + (slime-init-keymap 'slime-who-map t t slime-who-bindings) + (slime-init-keymap 'slime-prefix-map t nil slime-prefix-bindings) + (slime-init-keymap 'slime-parent-map nil nil slime-parent-bindings) + (slime-init-keymap 'slime-editing-map nil nil slime-editing-keys) + (set-keymap-parent slime-editing-map slime-parent-map) + (slime-init-keymap 'slime-mode-map nil nil slime-keys) + (set-keymap-parent slime-mode-map slime-editing-map) + (set-keymap-parent slime-mode-indirect-map slime-mode-map)) + +(defun slime-init-keymap (keymap-name prefixp bothp bindings) + (set keymap-name (make-sparse-keymap)) + (when prefixp (define-prefix-command keymap-name)) + (slime-bind-keys (eval keymap-name) bothp bindings)) + +(defun slime-bind-keys (keymap bothp bindings) + "Add BINDINGS to KEYMAP. +If BOTHP is true also add bindings with control modifier." + (cl-loop for (key command) in bindings do + (cond (bothp + (define-key keymap `[,key] command) + (unless (equal key ?h) ; But don't bind C-h + (define-key keymap `[(control ,key)] command))) + (t (define-key keymap key command))))) + +(slime-init-keymaps) + +(define-minor-mode slime-editing-mode + "Minor mode which makes slime-editing-map available. +\\{slime-editing-map}" + nil + nil + slime-editing-map) + + +;;;; Framework'ey bits +;;; +;;; This section contains some standard SLIME idioms: basic macros, +;;; ways of showing messages to the user, etc. All the code in this +;;; file should use these functions when applicable. +;;; +;;;;; Syntactic sugar + +(defmacro slime-dcase (value &rest patterns) + (declare (indent 1)) + "Dispatch VALUE to one of PATTERNS. +A cross between `case' and `destructuring-bind'. +The pattern syntax is: + ((HEAD . ARGS) . BODY) +The list of patterns is searched for a HEAD `eq' to the car of +VALUE. If one is found, the BODY is executed with ARGS bound to the +corresponding values in the CDR of VALUE." + (let ((operator (cl-gensym "op-")) + (operands (cl-gensym "rand-")) + (tmp (cl-gensym "tmp-"))) + `(let* ((,tmp ,value) + (,operator (car ,tmp)) + (,operands (cdr ,tmp))) + (cl-case ,operator + ,@(mapcar (lambda (clause) + (if (eq (car clause) t) + `(t ,@(cdr clause)) + (cl-destructuring-bind ((op &rest rands) &rest body) + clause + `(,op (cl-destructuring-bind ,rands ,operands + . ,(or body + '((ignore)) ; suppress some warnings + )))))) + patterns) + ,@(if (eq (caar (last patterns)) t) + '() + `((t (error "slime-dcase failed: %S" ,tmp)))))))) + +(defmacro slime-define-keys (keymap &rest key-command) + "Define keys in KEYMAP. Each KEY-COMMAND is a list of (KEY COMMAND)." + (declare (indent 1)) + `(progn . ,(mapcar (lambda (k-c) `(define-key ,keymap . ,k-c)) + key-command))) + +(cl-defmacro with-struct ((conc-name &rest slots) struct &body body) + "Like with-slots but works only for structs. +\(fn (CONC-NAME &rest SLOTS) STRUCT &body BODY)" + (declare (indent 2)) + (let ((struct-var (cl-gensym "struct")) + (reader (lambda (slot) + (intern (concat (symbol-name conc-name) + (symbol-name slot)))))) + `(let ((,struct-var ,struct)) + (cl-symbol-macrolet + ,(mapcar (lambda (slot) + (cl-etypecase slot + (symbol `(,slot (,(funcall reader slot) ,struct-var))) + (cons `(,(cl-first slot) + (,(funcall reader (cl-second slot)) + ,struct-var))))) + slots) + . ,body)))) + +;;;;; Very-commonly-used functions + +(defvar slime-message-function 'message) + +;; Interface +(defun slime-buffer-name (type &optional hidden) + (cl-assert (keywordp type)) + (concat (if hidden " " "") + (format "*slime-%s*" (substring (symbol-name type) 1)))) + +;; Interface +(defun slime-message (format &rest args) + "Like `message' but with special support for multi-line messages. +Single-line messages use the echo area." + (apply slime-message-function format args)) + +(defun slime-display-warning (message &rest args) + (display-warning '(slime warning) (apply #'format message args))) + +(defvar slime-background-message-function 'slime-display-oneliner) + +;; Interface +(defun slime-background-message (format-string &rest format-args) + "Display a message in passing. +This is like `slime-message', but less distracting because it +will never pop up a buffer or display multi-line messages. +It should be used for \"background\" messages such as argument lists." + (apply slime-background-message-function format-string format-args)) + +(defun slime-display-oneliner (format-string &rest format-args) + (let* ((msg (apply #'format format-string format-args))) + (unless (minibuffer-window-active-p (minibuffer-window)) + (message "%s" (slime-oneliner msg))))) + +(defun slime-oneliner (string) + "Return STRING truncated to fit in a single echo-area line." + (substring string 0 (min (length string) + (or (cl-position ?\n string) most-positive-fixnum) + (1- (window-width (minibuffer-window)))))) + +;; Interface +(defun slime-set-truncate-lines () + "Apply `slime-truncate-lines' to the current buffer." + (when slime-truncate-lines + (set (make-local-variable 'truncate-lines) t))) + +;; Interface +(defun slime-read-package-name (prompt &optional initial-value) + "Read a package name from the minibuffer, prompting with PROMPT." + (let ((completion-ignore-case t)) + (completing-read prompt (slime-bogus-completion-alist + (slime-eval + `(swank:list-all-package-names t))) + nil t initial-value))) + +;; Interface +(defun slime-read-symbol-name (prompt &optional query) + "Either read a symbol name or choose the one at point. +The user is prompted if a prefix argument is in effect, if there is no +symbol at point, or if QUERY is non-nil." + (cond ((or current-prefix-arg query (not (slime-symbol-at-point))) + (slime-read-from-minibuffer prompt (slime-symbol-at-point))) + (t (slime-symbol-at-point)))) + +;; Interface +(defmacro slime-propertize-region (props &rest body) + "Execute BODY and add PROPS to all the text it inserts. +More precisely, PROPS are added to the region between the point's +positions before and after executing BODY." + (declare (indent 1) (debug (sexp &rest form))) + (let ((start (cl-gensym))) + `(let ((,start (point))) + (prog1 (progn ,@body) + (add-text-properties ,start (point) ,props))))) + +(defun slime-add-face (face string) + (declare (indent 1)) + (add-text-properties 0 (length string) (list 'face face) string) + string) + +;; Interface +(defsubst slime-insert-propertized (props &rest args) + "Insert all ARGS and then add text-PROPS to the inserted text." + (slime-propertize-region props (apply #'insert args))) + +(defmacro slime-with-rigid-indentation (level &rest body) + "Execute BODY and then rigidly indent its text insertions. +Assumes all insertions are made at point." + (declare (indent 1)) + (let ((start (cl-gensym)) (l (cl-gensym))) + `(let ((,start (point)) (,l ,(or level '(current-column)))) + (prog1 (progn ,@body) + (slime-indent-rigidly ,start (point) ,l))))) + +(defun slime-indent-rigidly (start end column) + ;; Similar to `indent-rigidly' but doesn't inherit text props. + (let ((indent (make-string column ?\ ))) + (save-excursion + (goto-char end) + (beginning-of-line) + (while (and (<= start (point)) + (progn + (insert-before-markers indent) + (zerop (forward-line -1)))))))) + +(defun slime-insert-indented (&rest strings) + "Insert all arguments rigidly indented." + (slime-with-rigid-indentation nil + (apply #'insert strings))) + +(defun slime-property-bounds (prop) + "Return two the positions of the previous and next changes to PROP. +PROP is the name of a text property." + (cl-assert (get-text-property (point) prop)) + (let ((end (next-single-char-property-change (point) prop))) + (list (previous-single-char-property-change end prop) end))) + +(defun slime-curry (fun &rest args) + "Partially apply FUN to ARGS. The result is a new function. +This idiom is preferred over `lexical-let'." + `(lambda (&rest more) (apply ',fun (append ',args more)))) + +(defun slime-rcurry (fun &rest args) + "Like `slime-curry' but ARGS on the right are applied." + `(lambda (&rest more) (apply ',fun (append more ',args)))) + + +;;;;; Temporary popup buffers + +;; keep compiler quiet +(defvar slime-buffer-package) +(defvar slime-buffer-connection) + +;; Interface +(cl-defmacro slime-with-popup-buffer ((name &key package connection select + mode) + &body body) + "Similar to `with-output-to-temp-buffer'. +Bind standard-output and initialize some buffer-local variables. +Restore window configuration when closed. + +NAME is the name of the buffer to be created. +PACKAGE is the value `slime-buffer-package'. +CONNECTION is the value for `slime-buffer-connection', + if nil, no explicit connection is associated with + the buffer. If t, the current connection is taken. +MODE is the name of a major mode which will be enabled. +" + (declare (indent 1)) + (let ((package-sym (cl-gensym "package-")) + (connection-sym (cl-gensym "connection-"))) + `(let ((,package-sym ,(if (eq package t) + `(slime-current-package) + package)) + (,connection-sym ,(if (eq connection t) + `(slime-current-connection) + connection))) + (with-current-buffer (get-buffer-create ,name) + (let ((inhibit-read-only t) + (standard-output (current-buffer))) + (erase-buffer) + (funcall (or ,mode 'fundamental-mode)) + (setq slime-buffer-package ,package-sym + slime-buffer-connection ,connection-sym) + (set-syntax-table lisp-mode-syntax-table) + ,@body + (slime-popup-buffer-mode 1) + (funcall (if ,select 'pop-to-buffer 'display-buffer) + (current-buffer)) + (current-buffer)))))) + +(defvar slime-popup-buffer-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "q") 'quit-window) + ;;("\C-c\C-z" . slime-switch-to-output-buffer) + (define-key map (kbd "M-.") 'slime-edit-definition) + map)) + +(define-minor-mode slime-popup-buffer-mode + "Mode for displaying read only stuff" + nil nil nil + (setq buffer-read-only t)) + +(add-to-list 'minor-mode-alist + `(slime-popup-buffer-mode + (:eval (unless slime-mode + (slime-modeline-string))))) + +(set-keymap-parent slime-popup-buffer-mode-map slime-parent-map) + +;;;;; Filename translation +;;; +;;; Filenames passed between Emacs and Lisp should be translated using +;;; these functions. This way users who run Emacs and Lisp on separate +;;; machines have a chance to integrate file operations somehow. + +(defvar slime-to-lisp-filename-function #'convert-standard-filename + "Function to translate Emacs filenames to CL namestrings.") +(defvar slime-from-lisp-filename-function #'identity + "Function to translate CL namestrings to Emacs filenames.") + +(defun slime-to-lisp-filename (filename) + "Translate the string FILENAME to a Lisp filename." + (funcall slime-to-lisp-filename-function filename)) + +(defun slime-from-lisp-filename (filename) + "Translate the Lisp filename FILENAME to an Emacs filename." + (funcall slime-from-lisp-filename-function filename)) + + +;;;; Starting SLIME +;;; +;;; This section covers starting an inferior-lisp, compiling and +;;; starting the server, initiating a network connection. + +;;;;; Entry points + +;; We no longer load inf-lisp, but we use this variable for backward +;; compatibility. +(defvar inferior-lisp-program "lisp" + "*Program name for invoking an inferior Lisp with for Inferior Lisp mode.") + +(defvar slime-lisp-implementations nil + "*A list of known Lisp implementations. +The list should have the form: + ((NAME (PROGRAM PROGRAM-ARGS...) &key KEYWORD-ARGS) ...) + +NAME is a symbol for the implementation. +PROGRAM and PROGRAM-ARGS are strings used to start the Lisp process. +For KEYWORD-ARGS see `slime-start'. + +Here's an example: + ((cmucl (\"/opt/cmucl/bin/lisp\" \"-quiet\") :init slime-init-command) + (acl (\"acl7\") :coding-system emacs-mule))") + +(defvar slime-default-lisp nil + "*The name of the default Lisp implementation. +See `slime-lisp-implementations'") + +;; dummy definitions for the compiler +(defvar slime-net-processes) +(defvar slime-default-connection) + +(defun slime (&optional command coding-system) + "Start an inferior^_superior Lisp and connect to its Swank server." + (interactive) + (slime-setup) + (let ((inferior-lisp-program (or command inferior-lisp-program)) + (slime-net-coding-system (or coding-system slime-net-coding-system))) + (slime-start* (cond ((and command (symbolp command)) + (slime-lisp-options command)) + (t (slime-read-interactive-args)))))) + +(defvar slime-inferior-lisp-program-history '() + "History list of command strings. Used by `slime'.") + +(defun slime-read-interactive-args () + "Return the list of args which should be passed to `slime-start'. + +The rules for selecting the arguments are rather complicated: + +- In the most common case, i.e. if there's no prefix-arg in + effect and if `slime-lisp-implementations' is nil, use + `inferior-lisp-program' as fallback. + +- If the table `slime-lisp-implementations' is non-nil use the + implementation with name `slime-default-lisp' or if that's nil + the first entry in the table. + +- If the prefix-arg is `-', prompt for one of the registered + lisps. + +- If the prefix-arg is positive, read the command to start the + process." + (let ((table slime-lisp-implementations)) + (cond ((not current-prefix-arg) (slime-lisp-options)) + ((eq current-prefix-arg '-) + (let ((key (completing-read + "Lisp name: " (mapcar (lambda (x) + (list (symbol-name (car x)))) + table) + nil t))) + (slime-lookup-lisp-implementation table (intern key)))) + (t + (cl-destructuring-bind (program &rest program-args) + (split-string-and-unquote + (read-shell-command "Run lisp: " inferior-lisp-program + 'slime-inferior-lisp-program-history)) + (let ((coding-system + (if (eq 16 (prefix-numeric-value current-prefix-arg)) + (read-coding-system "set slime-coding-system: " + slime-net-coding-system) + slime-net-coding-system))) + (list :program program :program-args program-args + :coding-system coding-system))))))) + +(defun slime-lisp-options (&optional name) + (let ((table slime-lisp-implementations)) + (cl-assert (or (not name) table)) + (cond (table (slime-lookup-lisp-implementation slime-lisp-implementations + (or name slime-default-lisp + (car (car table))))) + (t (cl-destructuring-bind (program &rest args) + (split-string inferior-lisp-program) + (list :program program :program-args args)))))) + +(defun slime-lookup-lisp-implementation (table name) + (let ((arguments (cl-rest (assoc name table)))) + (unless arguments + (error "Could not find lisp implementation with the name '%S'" name)) + (when (and (= (length arguments) 1) + (functionp (cl-first arguments))) + (setf arguments (funcall (cl-first arguments)))) + (cl-destructuring-bind ((prog &rest args) &rest keys) arguments + (cl-list* :name name :program prog :program-args args keys)))) + +(cl-defun slime-start (&key (program inferior-lisp-program) program-args + directory + (coding-system slime-net-coding-system) + (init 'slime-init-command) + name + (buffer "*inferior-lisp*") + init-function + env) + "Start a Lisp process and connect to it. +This function is intended for programmatic use if `slime' is not +flexible enough. + +PROGRAM and PROGRAM-ARGS are the filename and argument strings + for the subprocess. +INIT is a function that should return a string to load and start + Swank. The function will be called with the PORT-FILENAME and ENCODING as + arguments. INIT defaults to `slime-init-command'. +CODING-SYSTEM a symbol for the coding system. The default is + slime-net-coding-system +ENV environment variables for the subprocess (see `process-environment'). +INIT-FUNCTION function to call right after the connection is established. +BUFFER the name of the buffer to use for the subprocess. +NAME a symbol to describe the Lisp implementation +DIRECTORY change to this directory before starting the process. +" + (let ((args (list :program program :program-args program-args :buffer buffer + :coding-system coding-system :init init :name name + :init-function init-function :env env))) + (slime-check-coding-system coding-system) + (when (slime-bytecode-stale-p) + (slime-urge-bytecode-recompile)) + (let ((proc (slime-maybe-start-lisp program program-args env + directory buffer))) + (slime-inferior-connect proc args) + (pop-to-buffer (process-buffer proc))))) + +(defun slime-start* (options) + (apply #'slime-start options)) + +(defun slime-connect (host port &optional _coding-system interactive-p) + "Connect to a running Swank server. Return the connection." + (interactive (list (read-from-minibuffer + "Host: " (cl-first slime-connect-host-history) + nil nil '(slime-connect-host-history . 1)) + (string-to-number + (read-from-minibuffer + "Port: " (cl-first slime-connect-port-history) + nil nil '(slime-connect-port-history . 1))) + nil t)) + (slime-setup) + (when (and interactive-p + slime-net-processes + (y-or-n-p "Close old connections first? ")) + (slime-disconnect-all)) + (message "Connecting to Swank on port %S.." port) + (let* ((process (slime-net-connect host port)) + (slime-dispatching-connection process)) + (slime-setup-connection process))) + +;; FIXME: seems redundant +(defun slime-start-and-init (options fun) + (let* ((rest (plist-get options :init-function)) + (init (cond (rest `(lambda () (funcall ',rest) (funcall ',fun))) + (t fun)))) + (slime-start* (plist-put (cl-copy-list options) :init-function init)))) + +;;;;; Start inferior lisp +;;; +;;; Here is the protocol for starting SLIME: +;;; +;;; 0. Emacs recompiles/reloads slime.elc if it exists and is stale. +;;; 1. Emacs starts an inferior Lisp process. +;;; 2. Emacs tells Lisp (via stdio) to load and start Swank. +;;; 3. Lisp recompiles the Swank if needed. +;;; 4. Lisp starts the Swank server and writes its TCP port to a temp file. +;;; 5. Emacs reads the temp file to get the port and then connects. +;;; 6. Emacs prints a message of warm encouragement for the hacking ahead. +;;; +;;; Between steps 2-5 Emacs polls for the creation of the temp file so +;;; that it can make the connection. This polling may continue for a +;;; fair while if Swank needs recompilation. + +(defvar slime-connect-retry-timer nil + "Timer object while waiting for an inferior-lisp to start.") + +;;; Recompiling bytecode: + +(defun slime-bytecode-stale-p () + "Return true if slime.elc is older than slime.el." + (let ((libfile (locate-library "slime"))) + (when libfile + (let* ((basename (file-name-sans-extension libfile)) + (sourcefile (concat basename ".el")) + (bytefile (concat basename ".elc"))) + (and (file-exists-p bytefile) + (file-newer-than-file-p sourcefile bytefile)))))) + +(defun slime-recompile-bytecode () + "Recompile and reload slime." + (interactive) + (let ((sourcefile (concat (file-name-sans-extension (locate-library "slime")) + ".el"))) + (byte-compile-file sourcefile t))) + +(defun slime-urge-bytecode-recompile () + "Urge the user to recompile slime.elc. +Return true if we have been given permission to continue." + (when (y-or-n-p "slime.elc is older than source. Recompile first? ") + (slime-recompile-bytecode))) + +(defun slime-abort-connection () + "Abort connection the current connection attempt." + (interactive) + (cond (slime-connect-retry-timer + (slime-cancel-connect-retry-timer) + (message "Cancelled connection attempt.")) + (t (error "Not connecting")))) + +;;; Starting the inferior Lisp and loading Swank: + +(defun slime-maybe-start-lisp (program program-args env directory buffer) + "Return a new or existing inferior lisp process." + (cond ((not (comint-check-proc buffer)) + (slime-start-lisp program program-args env directory buffer)) + ((slime-reinitialize-inferior-lisp-p program program-args env buffer) + (let ((conn (cl-find (get-buffer-process buffer) + slime-net-processes + :key #'slime-inferior-process))) + (when conn + (slime-net-close conn))) + (get-buffer-process buffer)) + (t (slime-start-lisp program program-args env directory + (generate-new-buffer-name buffer))))) + +(defun slime-reinitialize-inferior-lisp-p (program program-args env buffer) + (let ((args (slime-inferior-lisp-args (get-buffer-process buffer)))) + (and (equal (plist-get args :program) program) + (equal (plist-get args :program-args) program-args) + (equal (plist-get args :env) env) + (not (y-or-n-p "Create an additional *inferior-lisp*? "))))) + +(defvar slime-inferior-process-start-hook nil + "Hook called whenever a new process gets started.") + +(defun slime-start-lisp (program program-args env directory buffer) + "Does the same as `inferior-lisp' but less ugly. +Return the created process." + (with-current-buffer (get-buffer-create buffer) + (when directory + (cd (expand-file-name directory))) + (comint-mode) + (let ((process-environment (append env process-environment)) + (process-connection-type nil)) + (comint-exec (current-buffer) "inferior-lisp" program nil program-args)) + (lisp-mode-variables t) + (let ((proc (get-buffer-process (current-buffer)))) + (slime-set-query-on-exit-flag proc) + (run-hooks 'slime-inferior-process-start-hook) + proc))) + +(defun slime-inferior-connect (process args) + "Start a Swank server in the inferior Lisp and connect." + (slime-delete-swank-port-file 'quiet) + (slime-start-swank-server process args) + (slime-read-port-and-connect process)) + +(defvar slime-inferior-lisp-args nil + "A buffer local variable in the inferior proccess. +See `slime-start'.") + +(defun slime-start-swank-server (process args) + "Start a Swank server on the inferior lisp." + (cl-destructuring-bind (&key coding-system init &allow-other-keys) args + (with-current-buffer (process-buffer process) + (make-local-variable 'slime-inferior-lisp-args) + (setq slime-inferior-lisp-args args) + (let ((str (funcall init (slime-swank-port-file) coding-system))) + (goto-char (process-mark process)) + (insert-before-markers str) + (process-send-string process str))))) + +(defun slime-inferior-lisp-args (process) + "Return the initial process arguments. +See `slime-start'." + (with-current-buffer (process-buffer process) + slime-inferior-lisp-args)) + +;; XXX load-server & start-server used to be separated. maybe that was better. +(defun slime-init-command (port-filename _coding-system) + "Return a string to initialize Lisp." + (let ((loader (if (file-name-absolute-p slime-backend) + slime-backend + (concat slime-path slime-backend)))) + ;; Return a single form to avoid problems with buffered input. + (format "%S\n\n" + `(progn + (load ,(slime-to-lisp-filename (expand-file-name loader)) + :verbose t) + (funcall (read-from-string "swank-loader:init") + :from-emacs t) + (funcall (read-from-string "swank:start-server") + ,(slime-to-lisp-filename port-filename)))))) + +(defun slime-swank-port-file () + "Filename where the SWANK server writes its TCP port number." + (expand-file-name (format "slime.%S" (emacs-pid)) (slime-temp-directory))) + +(defun slime-temp-directory () + (cond ((fboundp 'temp-directory) (temp-directory)) + ((boundp 'temporary-file-directory) temporary-file-directory) + (t "/tmp/"))) + +(defun slime-delete-swank-port-file (&optional quiet) + (condition-case data + (delete-file (slime-swank-port-file)) + (error + (cl-ecase quiet + ((nil) (signal (car data) (cdr data))) + (quiet) + (message (message "Unable to delete swank port file %S" + (slime-swank-port-file))))))) + +(defun slime-read-port-and-connect (inferior-process) + (slime-attempt-connection inferior-process nil 1)) + +(defun slime-attempt-connection (process retries attempt) + ;; A small one-state machine to attempt a connection with + ;; timer-based retries. + (slime-cancel-connect-retry-timer) + (let ((file (slime-swank-port-file))) + (unless (active-minibuffer-window) + (message "Polling %S .. %d (Abort with `M-x slime-abort-connection'.)" + file attempt)) + (cond ((and (file-exists-p file) + (> (nth 7 (file-attributes file)) 0)) ; file size + (let ((port (slime-read-swank-port)) + (args (slime-inferior-lisp-args process))) + (slime-delete-swank-port-file 'message) + (let ((c (slime-connect slime-lisp-host port + (plist-get args :coding-system)))) + (slime-set-inferior-process c process)))) + ((and retries (zerop retries)) + (message "Gave up connecting to Swank after %d attempts." attempt)) + ((eq (process-status process) 'exit) + (message "Failed to connect to Swank: inferior process exited.")) + (t + (when (and (file-exists-p file) + (zerop (nth 7 (file-attributes file)))) + (message "(Zero length port file)") + ;; the file may be in the filesystem but not yet written + (unless retries (setq retries 3))) + (cl-assert (not slime-connect-retry-timer)) + (setq slime-connect-retry-timer + (run-with-timer + 0.3 nil + #'slime-timer-call #'slime-attempt-connection + process (and retries (1- retries)) + (1+ attempt))))))) + +(defun slime-timer-call (fun &rest args) + "Call function FUN with ARGS, reporting all errors. + +The default condition handler for timer functions (see +`timer-event-handler') ignores errors." + (condition-case data + (apply fun args) + ((debug error) + (debug nil (list "Error in timer" fun args data))))) + +(defun slime-cancel-connect-retry-timer () + (when slime-connect-retry-timer + (cancel-timer slime-connect-retry-timer) + (setq slime-connect-retry-timer nil))) + +(defun slime-read-swank-port () + "Read the Swank server port number from the `slime-swank-port-file'." + (save-excursion + (with-temp-buffer + (insert-file-contents (slime-swank-port-file)) + (goto-char (point-min)) + (let ((port (read (current-buffer)))) + (cl-assert (integerp port)) + port)))) + +(defun slime-toggle-debug-on-swank-error () + (interactive) + (if (slime-eval `(swank:toggle-debug-on-swank-error)) + (message "Debug on SWANK error enabled.") + (message "Debug on SWANK error disabled."))) + +;;; Words of encouragement + +(defun slime-user-first-name () + (let ((name (if (string= (user-full-name) "") + (user-login-name) + (user-full-name)))) + (string-match "^[^ ]*" name) + (capitalize (match-string 0 name)))) + +(defvar slime-words-of-encouragement + `("Let the hacking commence!" + "Hacks and glory await!" + "Hack and be merry!" + "Your hacking starts... NOW!" + "May the source be with you!" + "Take this REPL, brother, and may it serve you well." + "Lemonodor-fame is but a hack away!" + "Are we consing yet?" + ,(format "%s, this could be the start of a beautiful program." + (slime-user-first-name))) + "Scientifically-proven optimal words of hackerish encouragement.") + +(defun slime-random-words-of-encouragement () + "Return a string of hackerish encouragement." + (eval (nth (random (length slime-words-of-encouragement)) + slime-words-of-encouragement))) + + +;;;; Networking +;;; +;;; This section covers the low-level networking: establishing +;;; connections and encoding/decoding protocol messages. +;;; +;;; Each SLIME protocol message beings with a 6-byte header followed +;;; by an S-expression as text. The sexp must be readable both by +;;; Emacs and by Common Lisp, so if it contains any embedded code +;;; fragments they should be sent as strings: +;;; +;;; The set of meaningful protocol messages are not specified +;;; here. They are defined elsewhere by the event-dispatching +;;; functions in this file and in swank.lisp. + +(defvar slime-net-processes nil + "List of processes (sockets) connected to Lisps.") + +(defvar slime-net-process-close-hooks '() + "List of functions called when a slime network connection closes. +The functions are called with the process as their argument.") + +(defun slime-secret () + "Find the magic secret from the user's home directory. +Return nil if the file doesn't exist or is empty; otherwise the +first line of the file." + (condition-case _err + (with-temp-buffer + (insert-file-contents "~/.slime-secret") + (goto-char (point-min)) + (buffer-substring (point-min) (line-end-position))) + (file-error nil))) + +;;; Interface + +(defun slime-send-secret (proc) + (let ((secret (slime-secret))) + (when secret + (let* ((payload (encode-coding-string secret 'utf-8-unix)) + (string (concat (slime-net-encode-length (length payload)) + payload))) + (process-send-string proc string))))) + +(defun slime-net-connect (host port) + "Establish a connection with a CL." + (let* ((inhibit-quit nil) + (proc (open-network-stream "SLIME Lisp" nil host port)) + (buffer (slime-make-net-buffer " *cl-connection*"))) + (push proc slime-net-processes) + (set-process-buffer proc buffer) + (set-process-filter proc 'slime-net-filter) + (set-process-sentinel proc 'slime-net-sentinel) + (slime-set-query-on-exit-flag proc) + (when (fboundp 'set-process-coding-system) + (set-process-coding-system proc 'binary 'binary)) + (slime-send-secret proc) + proc)) + +(defun slime-make-net-buffer (name) + "Make a buffer suitable for a network process." + (let ((buffer (generate-new-buffer name))) + (with-current-buffer buffer + (buffer-disable-undo) + (set (make-local-variable 'kill-buffer-query-functions) nil)) + buffer)) + +(defun slime-set-query-on-exit-flag (process) + "Set PROCESS's query-on-exit-flag to `slime-kill-without-query-p'." + (when slime-kill-without-query-p + ;; avoid byte-compiler warnings + (let ((fun (if (fboundp 'set-process-query-on-exit-flag) + 'set-process-query-on-exit-flag + 'process-kill-without-query))) + (funcall fun process nil)))) + +;;;;; Coding system madness + +(defun slime-check-coding-system (coding-system) + "Signal an error if CODING-SYSTEM isn't a valid coding system." + (interactive) + (let ((props (slime-find-coding-system coding-system))) + (unless props + (error "Invalid slime-net-coding-system: %s. %s" + coding-system (mapcar #'car slime-net-valid-coding-systems))) + (when (and (cl-second props) (boundp 'default-enable-multibyte-characters)) + (cl-assert default-enable-multibyte-characters)) + t)) + +(defun slime-coding-system-mulibyte-p (coding-system) + (cl-second (slime-find-coding-system coding-system))) + +(defun slime-coding-system-cl-name (coding-system) + (cl-third (slime-find-coding-system coding-system))) + +;;; Interface +(defun slime-net-send (sexp proc) + "Send a SEXP to Lisp over the socket PROC. +This is the lowest level of communication. The sexp will be READ and +EVAL'd by Lisp." + (let* ((payload (encode-coding-string + (concat (slime-prin1-to-string sexp) "\n") + 'utf-8-unix)) + (string (concat (slime-net-encode-length (length payload)) + payload))) + (slime-log-event sexp) + (process-send-string proc string))) + +(defun slime-safe-encoding-p (coding-system string) + "Return true iff CODING-SYSTEM can safely encode STRING." + (or (let ((candidates (find-coding-systems-string string)) + (base (coding-system-base coding-system))) + (or (equal candidates '(undecided)) + (memq base candidates))) + (and (not (multibyte-string-p string)) + (not (slime-coding-system-mulibyte-p coding-system))))) + +(defun slime-net-close (process &optional debug) + (setq slime-net-processes (remove process slime-net-processes)) + (when (eq process slime-default-connection) + (setq slime-default-connection nil)) + (cond (debug + (set-process-sentinel process 'ignore) + (set-process-filter process 'ignore) + (delete-process process)) + (t + (run-hook-with-args 'slime-net-process-close-hooks process) + ;; killing the buffer also closes the socket + (kill-buffer (process-buffer process))))) + +(defun slime-net-sentinel (process message) + (message "Lisp connection closed unexpectedly: %s" message) + (slime-net-close process)) + +;;; Socket input is handled by `slime-net-filter', which decodes any +;;; complete messages and hands them off to the event dispatcher. + +(defun slime-net-filter (process string) + "Accept output from the socket and process all complete messages." + (with-current-buffer (process-buffer process) + (goto-char (point-max)) + (insert string)) + (slime-process-available-input process)) + +(defun slime-process-available-input (process) + "Process all complete messages that have arrived from Lisp." + (with-current-buffer (process-buffer process) + (while (slime-net-have-input-p) + (let ((event (slime-net-read-or-lose process)) + (ok nil)) + (slime-log-event event) + (unwind-protect + (save-current-buffer + (slime-dispatch-event event process) + (setq ok t)) + (unless ok + (slime-run-when-idle 'slime-process-available-input process))))))) + +(defun slime-net-have-input-p () + "Return true if a complete message is available." + (goto-char (point-min)) + (and (>= (buffer-size) 6) + (>= (- (buffer-size) 6) (slime-net-decode-length)))) + +(defun slime-run-when-idle (function &rest args) + "Call FUNCTION as soon as Emacs is idle." + (apply #'run-at-time 0 nil function args)) + +(defun slime-handle-net-read-error (error) + (let ((packet (buffer-string))) + (slime-with-popup-buffer ((slime-buffer-name :error)) + (princ (format "%s\nin packet:\n%s" (error-message-string error) packet)) + (goto-char (point-min))) + (cond ((y-or-n-p "Skip this packet? ") + `(:emacs-skipped-packet ,packet)) + (t + (when (y-or-n-p "Enter debugger instead? ") + (debug 'error error)) + (signal (car error) (cdr error)))))) + +(defun slime-net-read-or-lose (process) + (condition-case error + (slime-net-read) + (error + (slime-net-close process t) + (error "net-read error: %S" error)))) + +(defun slime-net-read () + "Read a message from the network buffer." + (goto-char (point-min)) + (let* ((length (slime-net-decode-length)) + (start (+ (point) 6)) + (end (+ start length))) + (cl-assert (cl-plusp length)) + (prog1 (save-restriction + (narrow-to-region start end) + (condition-case error + (progn + (decode-coding-region start end 'utf-8-unix) + (setq end (point-max)) + (read (current-buffer))) + (error + (slime-handle-net-read-error error)))) + (delete-region (point-min) end)))) + +(defun slime-net-decode-length () + (string-to-number (buffer-substring-no-properties (point) (+ (point) 6)) + 16)) + +(defun slime-net-encode-length (n) + (format "%06x" n)) + +(defun slime-prin1-to-string (sexp) + "Like `prin1-to-string' but don't octal-escape non-ascii characters. +This is more compatible with the CL reader." + (let (print-escape-nonascii + print-escape-newlines + print-length + print-level) + (prin1-to-string sexp))) + + +;;;; Connections +;;; +;;; "Connections" are the high-level Emacs<->Lisp networking concept. +;;; +;;; Emacs has a connection to each Lisp process that it's interacting +;;; with. Typically there would only be one, but a user can choose to +;;; connect to many Lisps simultaneously. +;;; +;;; A connection consists of a control socket, optionally an extra +;;; socket dedicated to receiving Lisp output (an optimization), and a +;;; set of connection-local state variables. +;;; +;;; The state variables are stored as buffer-local variables in the +;;; control socket's process-buffer and are used via accessor +;;; functions. These variables include things like the *FEATURES* list +;;; and Unix Pid of the Lisp process. +;;; +;;; One connection is "current" at any given time. This is: +;;; `slime-dispatching-connection' if dynamically bound, or +;;; `slime-buffer-connection' if this is set buffer-local, or +;;; `slime-default-connection' otherwise. +;;; +;;; When you're invoking commands in your source files you'll be using +;;; `slime-default-connection'. This connection can be interactively +;;; reassigned via the connection-list buffer. +;;; +;;; When a command creates a new buffer it will set +;;; `slime-buffer-connection' so that commands in the new buffer will +;;; use the connection that the buffer originated from. For example, +;;; the apropos command creates the *Apropos* buffer and any command +;;; in that buffer (e.g. `M-.') will go to the same Lisp that did the +;;; apropos search. REPL buffers are similarly tied to their +;;; respective connections. +;;; +;;; When Emacs is dispatching some network message that arrived from a +;;; connection it will dynamically bind `slime-dispatching-connection' +;;; so that the event will be processed in the context of that +;;; connection. +;;; +;;; This is mostly transparent. The user should be aware that he can +;;; set the default connection to pick which Lisp handles commands in +;;; Lisp-mode source buffers, and slime hackers should be aware that +;;; they can tie a buffer to a specific connection. The rest takes +;;; care of itself. + +(defvar slime-dispatching-connection nil + "Network process currently executing. +This is dynamically bound while handling messages from Lisp; it +overrides `slime-buffer-connection' and `slime-default-connection'.") + +(make-variable-buffer-local + (defvar slime-buffer-connection nil + "Network connection to use in the current buffer. +This overrides `slime-default-connection'.")) + +(defvar slime-default-connection nil + "Network connection to use by default. +Used for all Lisp communication, except when overridden by +`slime-dispatching-connection' or `slime-buffer-connection'.") + +(defun slime-current-connection () + "Return the connection to use for Lisp interaction. +Return nil if there's no connection." + (or slime-dispatching-connection + slime-buffer-connection + slime-default-connection)) + +(defun slime-connection () + "Return the connection to use for Lisp interaction. +Signal an error if there's no connection." + (let ((conn (slime-current-connection))) + (cond ((and (not conn) slime-net-processes) + (or (slime-auto-select-connection) + (error "No default connection selected."))) + ((not conn) + (or (slime-auto-start) + (error "Not connected."))) + ((not (eq (process-status conn) 'open)) + (error "Connection closed.")) + (t conn)))) + +(define-obsolete-variable-alias 'slime-auto-connect +'slime-auto-start "2.5") +(defcustom slime-auto-start 'never + "Controls auto connection when information from lisp process is needed. +This doesn't mean it will connect right after Slime is loaded." + :group 'slime-mode + :type '(choice (const never) + (const always) + (const ask))) + +(defun slime-auto-start () + (cond ((or (eq slime-auto-start 'always) + (and (eq slime-auto-start 'ask) + (y-or-n-p "No connection. Start Slime? "))) + (save-window-excursion + (slime) + (while (not (slime-current-connection)) + (sleep-for 1)) + (slime-connection))) + (t nil))) + +(defcustom slime-auto-select-connection 'ask + "Controls auto selection after the default connection was closed." + :group 'slime-mode + :type '(choice (const never) + (const always) + (const ask))) + +(defun slime-auto-select-connection () + (let* ((c0 (car slime-net-processes)) + (c (cond ((eq slime-auto-select-connection 'always) c0) + ((and (eq slime-auto-select-connection 'ask) + (y-or-n-p + (format "No default connection selected. %s %s? " + "Switch to" (slime-connection-name c0)))) + c0)))) + (when c + (slime-select-connection c) + (message "Switching to connection: %s" (slime-connection-name c)) + c))) + +(defun slime-select-connection (process) + "Make PROCESS the default connection." + (setq slime-default-connection process)) + +(defvar slime-cycle-connections-hook nil) + +(defun slime-cycle-connections-within (connections) + (let* ((tail (or (cdr (member (slime-current-connection) connections)) + connections)) ; loop around to the beginning + (next (car tail))) + (slime-select-connection next) + (run-hooks 'slime-cycle-connections-hook) + (message "Lisp: %s %s" + (slime-connection-name next) + (process-contact next)))) + +(defun slime-next-connection () + "Change current slime connection, cycling through all connections." + (interactive) + (slime-cycle-connections-within (reverse slime-net-processes))) + +(define-obsolete-function-alias 'slime-cycle-connections + 'slime-next-connection "2.13") + +(defun slime-prev-connection () + "Change current slime connection, cycling through all connections. +Goes in reverse order, relative to `slime-next-connection'." + (interactive) + (slime-cycle-connections-within slime-net-processes)) + +(cl-defmacro slime-with-connection-buffer ((&optional process) &rest body) + "Execute BODY in the process-buffer of PROCESS. +If PROCESS is not specified, `slime-connection' is used. + +\(fn (&optional PROCESS) &body BODY))" + (declare (indent 1)) + `(with-current-buffer + (process-buffer (or ,process (slime-connection) + (error "No connection"))) + ,@body)) + +;;; Connection-local variables: + +(defmacro slime-def-connection-var (varname &rest initial-value-and-doc) + "Define a connection-local variable. +The value of the variable can be read by calling the function of the +same name (it must not be accessed directly). The accessor function is +setf-able. + +The actual variable bindings are stored buffer-local in the +process-buffers of connections. The accessor function refers to +the binding for `slime-connection'." + (declare (indent 2)) + (let ((real-var (intern (format "%s:connlocal" varname)))) + `(progn + ;; Variable + (make-variable-buffer-local + (defvar ,real-var ,@initial-value-and-doc)) + ;; Accessor + (defun ,varname (&optional process) + (slime-with-connection-buffer (process) ,real-var)) + ;; Setf + (defsetf ,varname (&optional process) (store) + `(slime-with-connection-buffer (,process) + (setq (\, (quote (\, real-var))) (\, store)))) + '(\, varname)))) + +(slime-def-connection-var slime-connection-number nil + "Serial number of a connection. +Bound in the connection's process-buffer.") + +(slime-def-connection-var slime-lisp-features '() + "The symbol-names of Lisp's *FEATURES*. +This is automatically synchronized from Lisp.") + +(slime-def-connection-var slime-lisp-modules '() + "The strings of Lisp's *MODULES*.") + +(slime-def-connection-var slime-pid nil + "The process id of the Lisp process.") + +(slime-def-connection-var slime-lisp-implementation-type nil + "The implementation type of the Lisp process.") + +(slime-def-connection-var slime-lisp-implementation-version nil + "The implementation type of the Lisp process.") + +(slime-def-connection-var slime-lisp-implementation-name nil + "The short name for the Lisp implementation.") + +(slime-def-connection-var slime-lisp-implementation-program nil + "The argv[0] of the process running the Lisp implementation.") + +(slime-def-connection-var slime-connection-name nil + "The short name for connection.") + +(slime-def-connection-var slime-inferior-process nil + "The inferior process for the connection if any.") + +(slime-def-connection-var slime-communication-style nil + "The communication style.") + +(slime-def-connection-var slime-machine-instance nil + "The name of the (remote) machine running the Lisp process.") + +(slime-def-connection-var slime-connection-coding-systems nil + "Coding systems supported by the Lisp process.") + +;;;;; Connection setup + +(defvar slime-connection-counter 0 + "The number of SLIME connections made. For generating serial numbers.") + +;;; Interface +(defun slime-setup-connection (process) + "Make a connection out of PROCESS." + (let ((slime-dispatching-connection process)) + (slime-init-connection-state process) + (slime-select-connection process) + process)) + +(defun slime-init-connection-state (proc) + "Initialize connection state in the process-buffer of PROC." + ;; To make life simpler for the user: if this is the only open + ;; connection then reset the connection counter. + (when (equal slime-net-processes (list proc)) + (setq slime-connection-counter 0)) + (slime-with-connection-buffer () + (setq slime-buffer-connection proc)) + (setf (slime-connection-number proc) (cl-incf slime-connection-counter)) + ;; We do the rest of our initialization asynchronously. The current + ;; function may be called from a timer, and if we setup the REPL + ;; from a timer then it mysteriously uses the wrong keymap for the + ;; first command. + (let ((slime-current-thread t)) + (slime-eval-async '(swank:connection-info) + (slime-curry #'slime-set-connection-info proc)))) + +(defun slime-set-connection-info (connection info) + "Initialize CONNECTION with INFO received from Lisp." + (let ((slime-dispatching-connection connection) + (slime-current-thread t)) + (cl-destructuring-bind (&key pid style lisp-implementation machine + features version modules encoding + &allow-other-keys) info + (slime-check-version version connection) + (setf (slime-pid) pid + (slime-communication-style) style + (slime-lisp-features) features + (slime-lisp-modules) modules) + (cl-destructuring-bind (&key type name version program) + lisp-implementation + (setf (slime-lisp-implementation-type) type + (slime-lisp-implementation-version) version + (slime-lisp-implementation-name) name + (slime-lisp-implementation-program) program + (slime-connection-name) (slime-generate-connection-name name))) + (cl-destructuring-bind (&key instance ((:type _)) ((:version _))) machine + (setf (slime-machine-instance) instance)) + (cl-destructuring-bind (&key coding-systems) encoding + (setf (slime-connection-coding-systems) coding-systems))) + (let ((args (let ((p (slime-inferior-process))) + (if p (slime-inferior-lisp-args p))))) + (let ((name (plist-get args ':name))) + (when name + (unless (string= (slime-lisp-implementation-name) name) + (setf (slime-connection-name) + (slime-generate-connection-name (symbol-name name)))))) + (slime-load-contribs) + (run-hooks 'slime-connected-hook) + (let ((fun (plist-get args ':init-function))) + (when fun (funcall fun)))) + (message "Connected. %s" (slime-random-words-of-encouragement)))) + +(defun slime-check-version (version conn) + (or (equal version slime-protocol-version) + (equal slime-protocol-version 'ignore) + (y-or-n-p + (format "Versions differ: %s (slime) vs. %s (swank). Continue? " + slime-protocol-version version)) + (slime-net-close conn) + (top-level))) + +(defun slime-generate-connection-name (lisp-name) + (cl-loop for i from 1 + for name = lisp-name then (format "%s<%d>" lisp-name i) + while (cl-find name slime-net-processes + :key #'slime-connection-name :test #'equal) + finally (cl-return name))) + +(defun slime-connection-close-hook (process) + (when (eq process slime-default-connection) + (when slime-net-processes + (slime-select-connection (car slime-net-processes)) + (message "Default connection closed; switched to #%S (%S)" + (slime-connection-number) + (slime-connection-name))))) + +(add-hook 'slime-net-process-close-hooks 'slime-connection-close-hook) + +;;;;; Commands on connections + +(defun slime-disconnect () + "Close the current connection." + (interactive) + (slime-net-close (slime-connection))) + +(defun slime-disconnect-all () + "Disconnect all connections." + (interactive) + (mapc #'slime-net-close slime-net-processes)) + +(defun slime-connection-port (connection) + "Return the remote port number of CONNECTION." + (cadr (process-contact connection))) + +(defun slime-process (&optional connection) + "Return the Lisp process for CONNECTION (default `slime-connection'). +Return nil if there's no process object for the connection." + (let ((proc (slime-inferior-process connection))) + (if (and proc + (memq (process-status proc) '(run stop))) + proc))) + +;; Non-macro version to keep the file byte-compilable. +(defun slime-set-inferior-process (connection process) + (setf (slime-inferior-process connection) process)) + +(defun slime-use-sigint-for-interrupt (&optional connection) + (let ((c (or connection (slime-connection)))) + (cl-ecase (slime-communication-style c) + ((:fd-handler nil) t) + ((:spawn :sigio) nil)))) + +(defvar slime-inhibit-pipelining t + "*If true, don't send background requests if Lisp is already busy.") + +(defun slime-background-activities-enabled-p () + (and (let ((con (slime-current-connection))) + (and con + (eq (process-status con) 'open))) + (or (not (slime-busy-p)) + (not slime-inhibit-pipelining)))) + + +;;;; Communication protocol + +;;;;; Emacs Lisp programming interface +;;; +;;; The programming interface for writing Emacs commands is based on +;;; remote procedure calls (RPCs). The basic operation is to ask Lisp +;;; to apply a named Lisp function to some arguments, then to do +;;; something with the result. +;;; +;;; Requests can be either synchronous (blocking) or asynchronous +;;; (with the result passed to a callback/continuation function). If +;;; an error occurs during the request then the debugger is entered +;;; before the result arrives -- for synchronous evaluations this +;;; requires a recursive edit. +;;; +;;; You should use asynchronous evaluations (`slime-eval-async') for +;;; most things. Reserve synchronous evaluations (`slime-eval') for +;;; the cases where blocking Emacs is really appropriate (like +;;; completion) and that shouldn't trigger errors (e.g. not evaluate +;;; user-entered code). +;;; +;;; We have the concept of the "current Lisp package". RPC requests +;;; always say what package the user is making them from and the Lisp +;;; side binds that package to *BUFFER-PACKAGE* to use as it sees +;;; fit. The current package is defined as the buffer-local value of +;;; `slime-buffer-package' if set, and otherwise the package named by +;;; the nearest IN-PACKAGE as found by text search (cl-first backwards, +;;; then forwards). +;;; +;;; Similarly we have the concept of the current thread, i.e. which +;;; thread in the Lisp process should handle the request. The current +;;; thread is determined solely by the buffer-local value of +;;; `slime-current-thread'. This is usually bound to t meaning "no +;;; particular thread", but can also be used to nominate a specific +;;; thread. The REPL and the debugger both use this feature to deal +;;; with specific threads. + +(make-variable-buffer-local + (defvar slime-current-thread t + "The id of the current thread on the Lisp side. +t means the \"current\" thread; +:repl-thread the thread that executes REPL requests; +fixnum a specific thread.")) + +(make-variable-buffer-local + (defvar slime-buffer-package nil + "The Lisp package associated with the current buffer. +This is set only in buffers bound to specific packages.")) + +;;; `slime-rex' is the RPC primitive which is used to implement both +;;; `slime-eval' and `slime-eval-async'. You can use it directly if +;;; you need to, but the others are usually more convenient. + +(cl-defmacro slime-rex ((&rest saved-vars) + (sexp &optional + (package '(slime-current-package)) + (thread 'slime-current-thread)) + &rest continuations) + "(slime-rex (VAR ...) (SEXP &optional PACKAGE THREAD) CLAUSES ...) + +Remote EXecute SEXP. + +VARs are a list of saved variables visible in the other forms. Each +VAR is either a symbol or a list (VAR INIT-VALUE). + +SEXP is evaluated and the princed version is sent to Lisp. + +PACKAGE is evaluated and Lisp binds *BUFFER-PACKAGE* to this package. +The default value is (slime-current-package). + +CLAUSES is a list of patterns with same syntax as +`slime-dcase'. The result of the evaluation of SEXP is +dispatched on CLAUSES. The result is either a sexp of the +form (:ok VALUE) or (:abort CONDITION). CLAUSES is executed +asynchronously. + +Note: don't use backquote syntax for SEXP, because various Emacs +versions cannot deal with that." + (declare (indent 2)) + (let ((result (cl-gensym))) + `(lexical-let ,(cl-loop for var in saved-vars + collect (cl-etypecase var + (symbol (list var var)) + (cons var))) + (slime-dispatch-event + (list :emacs-rex ,sexp ,package ,thread + (lambda (,result) + (slime-dcase ,result + ,@continuations))))))) + +;;; Interface +(defun slime-current-package () + "Return the Common Lisp package in the current context. +If `slime-buffer-package' has a value then return that, otherwise +search for and read an `in-package' form." + (or slime-buffer-package + (save-restriction + (widen) + (slime-find-buffer-package)))) + +(defvar slime-find-buffer-package-function 'slime-search-buffer-package + "*Function to use for `slime-find-buffer-package'. +The result should be the package-name (a string) +or nil if nothing suitable can be found.") + +(defun slime-find-buffer-package () + "Figure out which Lisp package the current buffer is associated with." + (funcall slime-find-buffer-package-function)) + +(make-variable-buffer-local + (defvar slime-package-cache nil + "Cons of the form (buffer-modified-tick . package)")) + +;; When modifing this code consider cases like: +;; (in-package #.*foo*) +;; (in-package #:cl) +;; (in-package :cl) +;; (in-package "CL") +;; (in-package |CL|) +;; (in-package #+ansi-cl :cl #-ansi-cl 'lisp) + +(defun slime-search-buffer-package () + (let ((case-fold-search t) + (regexp (concat "^(\\(cl:\\|common-lisp:\\)?in-package\\>[ \t']*" + "\\([^)]+\\)[ \t]*)"))) + (save-excursion + (when (or (re-search-backward regexp nil t) + (re-search-forward regexp nil t)) + (match-string-no-properties 2))))) + +;;; Synchronous requests are implemented in terms of asynchronous +;;; ones. We make an asynchronous request with a continuation function +;;; that `throw's its result up to a `catch' and then enter a loop of +;;; handling I/O until that happens. + +(defvar slime-stack-eval-tags nil + "List of stack-tags of continuations waiting on the stack.") + +(defun slime-eval (sexp &optional package) + "Evaluate EXPR on the superior Lisp and return the result." + (when (null package) (setq package (slime-current-package))) + (let* ((tag (cl-gensym (format "slime-result-%d-" + (1+ (slime-continuation-counter))))) + (slime-stack-eval-tags (cons tag slime-stack-eval-tags))) + (apply + #'funcall + (catch tag + (slime-rex (tag sexp) + (sexp package) + ((:ok value) + (unless (member tag slime-stack-eval-tags) + (error "Reply to canceled synchronous eval request tag=%S sexp=%S" + tag sexp)) + (throw tag (list #'identity value))) + ((:abort _condition) + (throw tag (list #'error "Synchronous Lisp Evaluation aborted")))) + (let ((debug-on-quit t) + (inhibit-quit nil) + (conn (slime-connection))) + (while t + (unless (eq (process-status conn) 'open) + (error "Lisp connection closed unexpectedly")) + (accept-process-output nil 0.01))))))) + +(defun slime-eval-async (sexp &optional cont package) + "Evaluate EXPR on the superior Lisp and call CONT with the result." + (declare (indent 1)) + (slime-rex (cont (buffer (current-buffer))) + (sexp (or package (slime-current-package))) + ((:ok result) + (when cont + (set-buffer buffer) + (funcall cont result))) + ((:abort condition) + (message "Evaluation aborted on %s." condition))) + ;; Guard against arbitrary return values which once upon a time + ;; showed up in the minibuffer spuriously (due to a bug in + ;; slime-autodoc.) If this ever happens again, returning the + ;; following will make debugging much easier: + :slime-eval-async) + +;;; These functions can be handy too: + +(defun slime-connected-p () + "Return true if the Swank connection is open." + (not (null slime-net-processes))) + +(defun slime-check-connected () + "Signal an error if we are not connected to Lisp." + (unless (slime-connected-p) + (error "Not connected. Use `%s' to start a Lisp." + (substitute-command-keys "\\[slime]")))) + +;; UNUSED +(defun slime-debugged-connection-p (conn) + ;; This previously was (AND (SLDB-DEBUGGED-CONTINUATIONS CONN) T), + ;; but an SLDB buffer may exist without having continuations + ;; attached to it, e.g. the one resulting from `slime-interrupt'. + (cl-loop for b in (sldb-buffers) + thereis (with-current-buffer b + (eq slime-buffer-connection conn)))) + +(defun slime-busy-p (&optional conn) + "True if Lisp has outstanding requests. +Debugged requests are ignored." + (let ((debugged (sldb-debugged-continuations (or conn (slime-connection))))) + (cl-remove-if (lambda (id) + (memq id debugged)) + (slime-rex-continuations) + :key #'car))) + +(defun slime-sync () + "Block until the most recent request has finished." + (when (slime-rex-continuations) + (let ((tag (caar (slime-rex-continuations)))) + (while (cl-find tag (slime-rex-continuations) :key #'car) + (accept-process-output nil 0.1))))) + +(defun slime-ping () + "Check that communication works." + (interactive) + (message "%s" (slime-eval "PONG"))) + +;;;;; Protocol event handler (cl-the guts) +;;; +;;; This is the protocol in all its glory. The input to this function +;;; is a protocol event that either originates within Emacs or arrived +;;; over the network from Lisp. +;;; +;;; Each event is a list beginning with a keyword and followed by +;;; arguments. The keyword identifies the type of event. Events +;;; originating from Emacs have names starting with :emacs- and events +;;; from Lisp don't. + +(slime-def-connection-var slime-rex-continuations '() + "List of (ID . FUNCTION) continuations waiting for RPC results.") + +(slime-def-connection-var slime-continuation-counter 0 + "Continuation serial number counter.") + +(defvar slime-event-hooks) + +(defun slime-dispatch-event (event &optional process) + (let ((slime-dispatching-connection (or process (slime-connection)))) + (or (run-hook-with-args-until-success 'slime-event-hooks event) + (slime-dcase event + ((:emacs-rex form package thread continuation) + (when (and (slime-use-sigint-for-interrupt) (slime-busy-p)) + (slime-display-oneliner "; pipelined request... %S" form)) + (let ((id (cl-incf (slime-continuation-counter)))) + (slime-send `(:emacs-rex ,form ,package ,thread ,id)) + (push (cons id continuation) (slime-rex-continuations)) + (slime--recompute-modelines))) + ((:return value id) + (let ((rec (assq id (slime-rex-continuations)))) + (cond (rec (setf (slime-rex-continuations) + (remove rec (slime-rex-continuations))) + (slime--recompute-modelines) + (funcall (cdr rec) value)) + (t + (error "Unexpected reply: %S %S" id value))))) + ((:debug-activate thread level &optional select) + (cl-assert thread) + (sldb-activate thread level select)) + ((:debug thread level condition restarts frames conts) + (cl-assert thread) + (sldb-setup thread level condition restarts frames conts)) + ((:debug-return thread level stepping) + (cl-assert thread) + (sldb-exit thread level stepping)) + ((:emacs-interrupt thread) + (slime-send `(:emacs-interrupt ,thread))) + ((:channel-send id msg) + (slime-channel-send (or (slime-find-channel id) + (error "Invalid channel id: %S %S" id msg)) + msg)) + ((:emacs-channel-send id msg) + (slime-send `(:emacs-channel-send ,id ,msg))) + ((:read-from-minibuffer thread tag prompt initial-value) + (slime-read-from-minibuffer-for-swank thread tag prompt + initial-value)) + ((:y-or-n-p thread tag question) + (slime-y-or-n-p thread tag question)) + ((:emacs-return-string thread tag string) + (slime-send `(:emacs-return-string ,thread ,tag ,string))) + ((:new-features features) + (setf (slime-lisp-features) features)) + ((:indentation-update info) + (slime-handle-indentation-update info)) + ((:eval-no-wait form) + (slime-check-eval-in-emacs-enabled) + (eval (read form))) + ((:eval thread tag form-string) + (slime-check-eval-in-emacs-enabled) + (slime-eval-for-lisp thread tag form-string)) + ((:ed-rpc-no-wait fn-name &rest args) + (let ((fn (intern-soft fn-name))) + (slime-check-rpc-allowed fn) + (apply fn args))) + ((:ed-rpc thread tag fn-name &rest args) + (slime-rpc-from-lisp thread tag (intern-soft fn-name) args)) + ((:emacs-return thread tag value) + (slime-send `(:emacs-return ,thread ,tag ,value))) + ((:ed what) + (slime-ed what)) + ((:inspect what thread tag) + (let ((hook (when (and thread tag) + (slime-curry #'slime-send + `(:emacs-return ,thread ,tag nil))))) + (slime-open-inspector what nil hook))) + ((:background-message message) + (slime-background-message "%s" message)) + ((:debug-condition thread message) + (cl-assert thread) + (message "%s" message)) + ((:ping thread tag) + (slime-send `(:emacs-pong ,thread ,tag))) + ((:reader-error packet condition) + (slime-with-popup-buffer ((slime-buffer-name :error)) + (princ (format "Invalid protocol message:\n%s\n\n%s" + condition packet)) + (goto-char (point-min))) + (error "Invalid protocol message")) + ((:invalid-rpc id message) + (setf (slime-rex-continuations) + (cl-remove id (slime-rex-continuations) :key #'car)) + (error "Invalid rpc: %s" message)) + ((:emacs-skipped-packet _pkg)) + ((:test-delay seconds) ; for testing only + (sit-for seconds)))))) + +(defun slime-send (sexp) + "Send SEXP directly over the wire on the current connection." + (slime-net-send sexp (slime-connection))) + +(defun slime-reset () + "Clear all pending continuations and erase connection buffer." + (interactive) + (setf (slime-rex-continuations) '()) + (mapc #'kill-buffer (sldb-buffers)) + (slime-with-connection-buffer () + (erase-buffer))) + +(defun slime-send-sigint () + (interactive) + (signal-process (slime-pid) 'SIGINT)) + +;;;;; Channels + +;;; A channel implements a set of operations. Those operations can be +;;; invoked by sending messages to the channel. Channels are used for +;;; protocols which can't be expressed naturally with RPCs, e.g. for +;;; streaming data over the wire. +;;; +;;; A channel can be "remote" or "local". Remote channels are +;;; represented by integers. Local channels are structures. Messages +;;; sent to a closed (remote) channel are ignored. + +(slime-def-connection-var slime-channels '() + "Alist of the form (ID . CHANNEL).") + +(slime-def-connection-var slime-channels-counter 0 + "Channel serial number counter.") + +(cl-defstruct (slime-channel (:conc-name slime-channel.) + (:constructor + slime-make-channel% (operations name id plist))) + operations name id plist) + +(defun slime-make-channel (operations &optional name) + (let* ((id (cl-incf (slime-channels-counter))) + (ch (slime-make-channel% operations name id nil))) + (push (cons id ch) (slime-channels)) + ch)) + +(defun slime-close-channel (channel) + (setf (slime-channel.operations channel) 'closed-channel) + (let ((probe (assq (slime-channel.id channel) (slime-channels)))) + (cond (probe (setf (slime-channels) (delete probe (slime-channels)))) + (t (error "Invalid channel: %s" channel))))) + +(defun slime-find-channel (id) + (cdr (assq id (slime-channels)))) + +(defun slime-channel-send (channel message) + (apply (or (gethash (car message) (slime-channel.operations channel)) + (error "Unsupported operation: %S %S" message channel)) + channel (cdr message))) + +(defun slime-channel-put (channel prop value) + (setf (slime-channel.plist channel) + (plist-put (slime-channel.plist channel) prop value))) + +(defun slime-channel-get (channel prop) + (plist-get (slime-channel.plist channel) prop)) + +(eval-and-compile + (defun slime-channel-method-table-name (type) + (intern (format "slime-%s-channel-methods" type)))) + +(defmacro slime-define-channel-type (name) + (declare (indent defun)) + (let ((tab (slime-channel-method-table-name name))) + `(progn + (defvar ,tab) + (setq ,tab (make-hash-table :size 10))))) + +(defmacro slime-define-channel-method (type method args &rest body) + (declare (indent 3) (debug (&define name sexp lambda-list + def-body))) + `(puthash ',method + (lambda (self . ,args) . ,body) + ,(slime-channel-method-table-name type))) + +(defun slime-send-to-remote-channel (channel-id msg) + (slime-dispatch-event `(:emacs-channel-send ,channel-id ,msg))) + +;;;;; Event logging to *slime-events* +;;; +;;; The *slime-events* buffer logs all protocol messages for debugging +;;; purposes. Optionally you can enable outline-mode in that buffer, +;;; which is convenient but slows things down significantly. + +(defvar slime-log-events t + "*Log protocol events to the *slime-events* buffer.") + +(defvar slime-outline-mode-in-events-buffer nil + "*Non-nil means use outline-mode in *slime-events*.") + +(defvar slime-event-buffer-name (slime-buffer-name :events) + "The name of the slime event buffer.") + +(defun slime-log-event (event) + "Record the fact that EVENT occurred." + (when slime-log-events + (with-current-buffer (slime-events-buffer) + ;; trim? + (when (> (buffer-size) 100000) + (goto-char (/ (buffer-size) 2)) + (re-search-forward "^(" nil t) + (delete-region (point-min) (point))) + (goto-char (point-max)) + (save-excursion + (slime-pprint-event event (current-buffer))) + (when (and (boundp 'outline-minor-mode) + outline-minor-mode) + (hide-entry)) + (goto-char (point-max))))) + +(defun slime-pprint-event (event buffer) + "Pretty print EVENT in BUFFER with limited depth and width." + (let ((print-length 20) + (print-level 6) + (pp-escape-newlines t)) + (pp event buffer))) + +(defun slime-events-buffer () + "Return or create the event log buffer." + (or (get-buffer slime-event-buffer-name) + (let ((buffer (get-buffer-create slime-event-buffer-name))) + (with-current-buffer buffer + (buffer-disable-undo) + (set (make-local-variable 'outline-regexp) "^(") + (set (make-local-variable 'comment-start) ";") + (set (make-local-variable 'comment-end) "") + (when slime-outline-mode-in-events-buffer + (outline-minor-mode))) + buffer))) + + +;;;;; Cleanup after a quit + +(defun slime-restart-inferior-lisp () + "Kill and restart the Lisp subprocess." + (interactive) + (cl-assert (slime-inferior-process) () "No inferior lisp process") + (slime-quit-lisp-internal (slime-connection) 'slime-restart-sentinel t)) + +(defun slime-restart-sentinel (process _message) + "Restart the inferior lisp process. +Also rearrange windows." + (cl-assert (process-status process) 'closed) + (let* ((proc (slime-inferior-process process)) + (args (slime-inferior-lisp-args proc)) + (buffer (buffer-name (process-buffer proc))) + ;;(buffer-window (get-buffer-window buffer)) + (new-proc (slime-start-lisp (plist-get args :program) + (plist-get args :program-args) + (plist-get args :env) + nil + buffer))) + (slime-net-close process) + (slime-inferior-connect new-proc args) + (switch-to-buffer buffer) + (goto-char (point-max)))) + + +;;;; Compilation and the creation of compiler-note annotations + +(defvar slime-highlight-compiler-notes t + "*When non-nil annotate buffers with compilation notes etc.") + +(defvar slime-before-compile-functions nil + "A list of function called before compiling a buffer or region. +The function receive two arguments: the beginning and the end of the +region that will be compiled.") + +;; FIXME: remove some of the options +(defcustom slime-compilation-finished-hook 'slime-maybe-show-compilation-log + "Hook called with a list of compiler notes after a compilation." + :group 'slime-mode + :type 'hook + :options '(slime-maybe-show-compilation-log + slime-create-compilation-log + slime-show-compilation-log + slime-maybe-list-compiler-notes + slime-list-compiler-notes + slime-maybe-show-xrefs-for-notes + slime-goto-first-note)) + +;; FIXME: I doubt that anybody uses this directly and it seems to be +;; only an ugly way to pass arguments. +(defvar slime-compilation-policy nil + "When non-nil compile with these optimization settings.") + +(defun slime-compute-policy (arg) + "Return the policy for the prefix argument ARG." + (let ((between (lambda (min n max) + (cond ((< n min) min) + ((> n max) max) + (t n))))) + (let ((n (prefix-numeric-value arg))) + (cond ((not arg) slime-compilation-policy) + ((cl-plusp n) `((cl:debug . ,(funcall between 0 n 3)))) + ((eq arg '-) `((cl:speed . 3))) + (t `((cl:speed . ,(funcall between 0 (abs n) 3)))))))) + +(cl-defstruct (slime-compilation-result + (:type list) + (:conc-name slime-compilation-result.) + (:constructor nil) + (:copier nil)) + tag notes successp duration loadp faslfile) + +(defvar slime-last-compilation-result nil + "The result of the most recently issued compilation.") + +(defun slime-compiler-notes () + "Return all compiler notes, warnings, and errors." + (slime-compilation-result.notes slime-last-compilation-result)) + +(defun slime-compile-and-load-file (&optional policy) + "Compile and load the buffer's file and highlight compiler notes. + +With (positive) prefix argument the file is compiled with maximal +debug settings (`C-u'). With negative prefix argument it is compiled for +speed (`M--'). If a numeric argument is passed set debug or speed settings +to it depending on its sign. + +Each source location that is the subject of a compiler note is +underlined and annotated with the relevant information. The commands +`slime-next-note' and `slime-previous-note' can be used to navigate +between compiler notes and to display their full details." + (interactive "P") + (slime-compile-file t (slime-compute-policy policy))) + +(defcustom slime-compile-file-options '() + "Plist of additional options that C-c C-k should pass to Lisp. +Currently only :fasl-directory is supported." + :group 'slime-lisp + :type '(plist :key-type symbol :value-type (file :must-match t))) + +(defun slime-compile-file (&optional load policy) + "Compile current buffer's file and highlight resulting compiler notes. + +See `slime-compile-and-load-file' for further details." + (interactive) + (unless buffer-file-name + (error "Buffer %s is not associated with a file." (buffer-name))) + (check-parens) + (slime--maybe-save-buffer) + (run-hook-with-args 'slime-before-compile-functions (point-min) (point-max)) + (let ((file (slime-to-lisp-filename (buffer-file-name))) + (options (slime-simplify-plist `(,@slime-compile-file-options + :policy ,policy)))) + (slime-eval-async + `(swank:compile-file-for-emacs ,file ,(if load t nil) + . ,(slime-hack-quotes options)) + #'slime-compilation-finished) + (message "Compiling %s..." file))) + +;; FIXME: compilation-save-buffers-predicate was introduced in 24.1 +(defun slime--maybe-save-buffer () + (let ((slime--this-buffer (current-buffer))) + (save-some-buffers (not compilation-ask-about-save) + (lambda () (eq (current-buffer) slime--this-buffer))))) + +(defun slime-hack-quotes (arglist) + ;; eval is the wrong primitive, we really want funcall + (cl-loop for arg in arglist collect `(quote ,arg))) + +(defun slime-simplify-plist (plist) + (cl-loop for (key val) on plist by #'cddr + append (cond ((null val) '()) + (t (list key val))))) + +(defun slime-compile-defun (&optional raw-prefix-arg) + "Compile the current toplevel form. + +With (positive) prefix argument the form is compiled with maximal +debug settings (`C-u'). With negative prefix argument it is compiled for +speed (`M--'). If a numeric argument is passed set debug or speed settings +to it depending on its sign." + (interactive "P") + (let ((slime-compilation-policy (slime-compute-policy raw-prefix-arg))) + (if (use-region-p) + (slime-compile-region (region-beginning) (region-end)) + (apply #'slime-compile-region (slime-region-for-defun-at-point))))) + +(defun slime-compile-region (start end) + "Compile the region." + (interactive "r") + ;; Check connection before running hooks things like + ;; slime-flash-region don't make much sense if there's no connection + (slime-connection) + (slime-flash-region start end) + (run-hook-with-args 'slime-before-compile-functions start end) + (slime-compile-string (buffer-substring-no-properties start end) start)) + +(defun slime-flash-region (start end &optional timeout) + "Temporarily highlight region from START to END." + (let ((overlay (make-overlay start end))) + (overlay-put overlay 'face 'secondary-selection) + (run-with-timer (or timeout 0.2) nil 'delete-overlay overlay))) + +(defun slime-compile-string (string start-offset) + (let* ((line (save-excursion + (goto-char start-offset) + (list (line-number-at-pos) (1+ (current-column))))) + (position `((:position ,start-offset) (:line ,@line)))) + (slime-eval-async + `(swank:compile-string-for-emacs + ,string + ,(buffer-name) + ',position + ,(if (buffer-file-name) (slime-to-lisp-filename (buffer-file-name))) + ',slime-compilation-policy) + #'slime-compilation-finished))) + +(defcustom slime-load-failed-fasl 'ask + "Which action to take when COMPILE-FILE set FAILURE-P to T. +NEVER doesn't load the fasl +ALWAYS loads the fasl +ASK asks the user." + :type '(choice (const never) + (const always) + (const ask))) + +(defun slime-load-failed-fasl-p () + (cl-ecase slime-load-failed-fasl + (never nil) + (always t) + (ask (y-or-n-p "Compilation failed. Load fasl file anyway? ")))) + +(defun slime-compilation-finished (result) + (with-struct (slime-compilation-result. notes duration successp + loadp faslfile) result + (setf slime-last-compilation-result result) + (slime-show-note-counts notes duration (cond ((not loadp) successp) + (t (and faslfile successp)))) + (when slime-highlight-compiler-notes + (slime-highlight-notes notes)) + (run-hook-with-args 'slime-compilation-finished-hook notes) + (when (and loadp faslfile + (or successp + (slime-load-failed-fasl-p))) + (slime-eval-async `(swank:load-file ,faslfile))))) + +(defun slime-show-note-counts (notes secs successp) + (message (concat + (cond (successp "Compilation finished") + (t (slime-add-face 'font-lock-warning-face + "Compilation failed"))) + (if (null notes) ". (No warnings)" ": ") + (mapconcat + (lambda (messages) + (cl-destructuring-bind (sev . notes) messages + (let ((len (length notes))) + (format "%d %s%s" len (slime-severity-label sev) + (if (= len 1) "" "s"))))) + (sort (slime-alistify notes #'slime-note.severity #'eq) + (lambda (x y) (slime-severity< (car y) (car x)))) + " ") + (if secs (format " [%.2f secs]" secs))))) + +(defun slime-highlight-notes (notes) + "Highlight compiler notes, warnings, and errors in the buffer." + (interactive (list (slime-compiler-notes))) + (with-temp-message "Highlighting notes..." + (save-excursion + (save-restriction + (widen) ; highlight notes on the whole buffer + (slime-remove-old-overlays) + (mapc #'slime-overlay-note (slime-merge-notes-for-display notes)))))) + +(defvar slime-note-overlays '() + "List of overlays created by `slime-make-note-overlay'") + +(defun slime-remove-old-overlays () + "Delete the existing note overlays." + (mapc #'delete-overlay slime-note-overlays) + (setq slime-note-overlays '())) + +(defun slime-filter-buffers (predicate) + "Return a list of where PREDICATE returns true. +PREDICATE is executed in the buffer to test." + (cl-remove-if-not (lambda (%buffer) + (with-current-buffer %buffer + (funcall predicate))) + (buffer-list))) + +;;;;; Recompilation. + +;; FIXME: This whole idea is questionable since it depends so +;; crucially on precise source-locs. + +(defun slime-recompile-location (location) + (save-excursion + (slime-goto-source-location location) + (slime-compile-defun))) + +(defun slime-recompile-locations (locations cont) + (slime-eval-async + `(swank:compile-multiple-strings-for-emacs + ',(cl-loop for loc in locations collect + (save-excursion + (slime-goto-source-location loc) + (cl-destructuring-bind (start end) + (slime-region-for-defun-at-point) + (list (buffer-substring-no-properties start end) + (buffer-name) + (slime-current-package) + start + (if (buffer-file-name) + (slime-to-lisp-filename (buffer-file-name)) + nil))))) + ',slime-compilation-policy) + cont)) + + +;;;;; Merging together compiler notes in the same location. + +(defun slime-merge-notes-for-display (notes) + "Merge together notes that refer to the same location. +This operation is \"lossy\" in the broad sense but not for display purposes." + (mapcar #'slime-merge-notes + (slime-group-similar 'slime-notes-in-same-location-p notes))) + +(defun slime-merge-notes (notes) + "Merge NOTES together. Keep the highest severity, concatenate the messages." + (let* ((new-severity (cl-reduce #'slime-most-severe notes + :key #'slime-note.severity)) + (new-message (mapconcat #'slime-note.message notes "\n"))) + (let ((new-note (cl-copy-list (car notes)))) + (setf (cl-getf new-note :message) new-message) + (setf (cl-getf new-note :severity) new-severity) + new-note))) + +(defun slime-notes-in-same-location-p (a b) + (equal (slime-note.location a) (slime-note.location b))) + + +;;;;; Compiler notes list + +(defun slime-one-line-ify (string) + "Return a single-line version of STRING. +Each newlines and following indentation is replaced by a single space." + (with-temp-buffer + (insert string) + (goto-char (point-min)) + (while (re-search-forward "\n[\n \t]*" nil t) + (replace-match " ")) + (buffer-string))) + +(defun slime-xrefs-for-notes (notes) + (let ((xrefs)) + (dolist (note notes) + (let* ((location (cl-getf note :location)) + (fn (cadr (assq :file (cdr location)))) + (file (assoc fn xrefs)) + (node + (list (format "%s: %s" + (cl-getf note :severity) + (slime-one-line-ify (cl-getf note :message))) + location))) + (when fn + (if file + (push node (cdr file)) + (setf xrefs (cl-acons fn (list node) xrefs)))))) + xrefs)) + +(defun slime-maybe-show-xrefs-for-notes (notes) + "Show the compiler notes NOTES if they come from more than one file." + (let ((xrefs (slime-xrefs-for-notes notes))) + (when (slime-length> xrefs 1) ; >1 file + (slime-show-xrefs + xrefs 'definition "Compiler notes" (slime-current-package))))) + +(defun slime-note-has-location-p (note) + (not (eq ':error (car (slime-note.location note))))) + +(defun slime-redefinition-note-p (note) + (eq (slime-note.severity note) :redefinition)) + +(defun slime-create-compilation-log (notes) + "Create a buffer for `next-error' to use." + (with-current-buffer (get-buffer-create (slime-buffer-name :compilation)) + (let ((inhibit-read-only t)) + (erase-buffer)) + (slime-insert-compilation-log notes) + (compilation-mode))) + +(defun slime-maybe-show-compilation-log (notes) + "Display the log on failed compilations or if NOTES is non-nil." + (slime-create-compilation-log notes) + (with-struct (slime-compilation-result. notes duration successp) + slime-last-compilation-result + (unless successp + (with-current-buffer (slime-buffer-name :compilation) + (let ((inhibit-read-only t)) + (goto-char (point-max)) + (insert "Compilation " (if successp "succeeded." "failed.")) + (goto-char (point-min)) + (display-buffer (current-buffer))))))) + +(defun slime-show-compilation-log (notes) + "Create and display the compilation log buffer." + (interactive (list (slime-compiler-notes))) + (slime-with-popup-buffer ((slime-buffer-name :compilation) + :mode 'compilation-mode) + (slime-insert-compilation-log notes))) + +(defun slime-insert-compilation-log (notes) + "Insert NOTES in format suitable for `compilation-mode'." + (cl-destructuring-bind (grouped-notes canonicalized-locs-table) + (slime-group-and-sort-notes notes) + (with-temp-message "Preparing compilation log..." + (let ((inhibit-read-only t) + (inhibit-modification-hooks t)) ; inefficient font-lock-hook + (insert (format "cd %s\n%d compiler notes:\n\n" + default-directory (length notes))) + (dolist (notes grouped-notes) + (let ((loc (gethash (cl-first notes) canonicalized-locs-table)) + (start (point))) + (insert (slime-canonicalized-location-to-string loc) ":") + (slime-insert-note-group notes) + (insert "\n") + (slime-make-note-overlay (cl-first notes) start (1- (point)))))) + (set (make-local-variable 'compilation-skip-threshold) 0) + (setq next-error-last-buffer (current-buffer))))) + +(defun slime-insert-note-group (notes) + "Insert a group of compiler messages." + (insert "\n") + (dolist (note notes) + (insert " " (slime-severity-label (slime-note.severity note)) ": ") + (let ((start (point))) + (insert (slime-note.message note)) + (let ((ctx (slime-note.source-context note))) + (if ctx (insert "\n" ctx))) + (slime-indent-block start 4)) + (insert "\n"))) + +(defun slime-indent-block (start column) + "If the region back to START isn't a one-liner indent it." + (when (< start (line-beginning-position)) + (save-excursion + (goto-char start) + (insert "\n")) + (slime-indent-rigidly start (point) column))) + +(defun slime-canonicalized-location (location) + "Return a list (FILE LINE COLUMN) for slime-location LOCATION. +This is quite an expensive operation so use carefully." + (save-excursion + (slime-goto-location-buffer (slime-location.buffer location)) + (save-excursion + (slime-goto-source-location location) + (list (or (buffer-file-name) (buffer-name)) + (save-restriction + (widen) + (line-number-at-pos)) + (1+ (current-column)))))) + +(defun slime-canonicalized-location-to-string (loc) + (if loc + (cl-destructuring-bind (filename line col) loc + (format "%s:%d:%d" + (cond ((not filename) "") + ((let ((rel (file-relative-name filename))) + (if (< (length rel) (length filename)) + rel))) + (t filename)) + line col)) + (format "Unknown location"))) + +(defun slime-goto-note-in-compilation-log (note) + "Find `note' in the compilation log and display it." + (with-current-buffer (get-buffer (slime-buffer-name :compilation)) + (let ((pos + (save-excursion + (goto-char (point-min)) + (cl-loop for overlay = (slime-find-next-note) + while overlay + for other-note = (overlay-get overlay 'slime-note) + when (slime-notes-in-same-location-p note other-note) + return (overlay-start overlay))))) + (when pos + (slime--display-position pos nil 0))))) + +(defun slime-group-and-sort-notes (notes) + "First sort, then group NOTES according to their canonicalized locs." + (let ((locs (make-hash-table :test #'eq))) + (mapc (lambda (note) + (let ((loc (slime-note.location note))) + (when (slime-location-p loc) + (puthash note (slime-canonicalized-location loc) locs)))) + notes) + (list (slime-group-similar + (lambda (n1 n2) + (equal (gethash n1 locs nil) (gethash n2 locs t))) + (let* ((bottom most-negative-fixnum) + (+default+ (list "" bottom bottom))) + (sort notes + (lambda (n1 n2) + (cl-destructuring-bind ((filename1 line1 col1) + (filename2 line2 col2)) + (list (gethash n1 locs +default+) + (gethash n2 locs +default+)) + (cond ((string-lessp filename1 filename2) t) + ((string-lessp filename2 filename1) nil) + ((< line1 line2) t) + ((> line1 line2) nil) + (t (< col1 col2)))))))) + locs))) + +(defun slime-note.severity (note) + (plist-get note :severity)) + +(defun slime-note.message (note) + (plist-get note :message)) + +(defun slime-note.source-context (note) + (plist-get note :source-context)) + +(defun slime-note.location (note) + (plist-get note :location)) + +(defun slime-severity-label (severity) + (cl-subseq (symbol-name severity) 1)) + + +;;;;; Adding a single compiler note + +(defun slime-overlay-note (note) + "Add a compiler note to the buffer as an overlay. +If an appropriate overlay for a compiler note in the same location +already exists then the new information is merged into it. Otherwise a +new overlay is created." + (cl-multiple-value-bind (start end) (slime-choose-overlay-region note) + (when start + (goto-char start) + (let ((severity (plist-get note :severity)) + (message (plist-get note :message)) + (overlay (slime-note-at-point))) + (if overlay + (slime-merge-note-into-overlay overlay severity message) + (slime-create-note-overlay note start end severity message)))))) + +(defun slime-make-note-overlay (note start end) + (let ((overlay (make-overlay start end))) + (overlay-put overlay 'slime-note note) + (push overlay slime-note-overlays) + overlay)) + +(defun slime-create-note-overlay (note start end severity message) + "Create an overlay representing a compiler note. +The overlay has several properties: + FACE - to underline the relevant text. + SEVERITY - for future reference :NOTE, :STYLE-WARNING, :WARNING, or :ERROR. + MOUSE-FACE - highlight the note when the mouse passes over. + HELP-ECHO - a string describing the note, both for future reference + and for display as a tooltip (due to the special + property name)." + (let ((overlay (slime-make-note-overlay note start end))) + (cl-macrolet ((putp (name value) `(overlay-put overlay ,name ,value))) + (putp 'face (slime-severity-face severity)) + (putp 'severity severity) + (putp 'mouse-face 'highlight) + (putp 'help-echo message) + overlay))) + +;; XXX Obsolete due to `slime-merge-notes-for-display' doing the +;; work already -- unless we decide to put several sets of notes on a +;; buffer without clearing in between, which only this handles. +(defun slime-merge-note-into-overlay (overlay severity message) + "Merge another compiler note into an existing overlay. +The help text describes both notes, and the highest of the severities +is kept." + (cl-macrolet ((putp (name value) `(overlay-put overlay ,name ,value)) + (getp (name) `(overlay-get overlay ,name))) + (putp 'severity (slime-most-severe severity (getp 'severity))) + (putp 'face (slime-severity-face (getp 'severity))) + (putp 'help-echo (concat (getp 'help-echo) "\n" message)))) + +(defun slime-choose-overlay-region (note) + "Choose the start and end points for an overlay over NOTE. +If the location's sexp is a list spanning multiple lines, then the +region around the first element is used. +Return nil if there's no useful source location." + (let ((location (slime-note.location note))) + (when location + (slime-dcase location + ((:error _)) ; do nothing + ((:location file pos _hints) + (cond ((eq (car file) ':source-form) nil) + ((eq (slime-note.severity note) :read-error) + (slime-choose-overlay-for-read-error location)) + ((equal pos '(:eof)) + (cl-values (1- (point-max)) (point-max))) + (t + (slime-choose-overlay-for-sexp location)))))))) + +(defun slime-choose-overlay-for-read-error (location) + (let ((pos (slime-location-offset location))) + (save-excursion + (goto-char pos) + (cond ((slime-symbol-at-point) + ;; package not found, &c. + (cl-values (slime-symbol-start-pos) (slime-symbol-end-pos))) + (t + (cl-values pos (1+ pos))))))) + +(defun slime-choose-overlay-for-sexp (location) + (slime-goto-source-location location) + (skip-chars-forward "'#`") + (let ((start (point))) + (ignore-errors (slime-forward-sexp)) + (if (slime-same-line-p start (point)) + (cl-values start (point)) + (cl-values (1+ start) + (progn (goto-char (1+ start)) + (ignore-errors (forward-sexp 1)) + (point)))))) + +(defun slime-same-line-p (pos1 pos2) + "Return t if buffer positions POS1 and POS2 are on the same line." + (save-excursion (goto-char (min pos1 pos2)) + (<= (max pos1 pos2) (line-end-position)))) + +(defvar slime-severity-face-plist + '(:error slime-error-face + :read-error slime-error-face + :warning slime-warning-face + :redefinition slime-style-warning-face + :style-warning slime-style-warning-face + :early-deprecation-warning slime-early-deprecation-warning-face + :late-deprecation-warning slime-late-deprecation-warning-face + :final-deprecation-warning slime-final-deprecation-warning-face + :note slime-note-face)) + +(defun slime-severity-face (severity) + "Return the name of the font-lock face representing SEVERITY." + (or (plist-get slime-severity-face-plist severity) + (error "No face for: %S" severity))) + +(defvar slime-severity-order + '(:note + :early-deprecation-warning :style-warning :redefinition + :late-deprecation-warning :final-deprecation-warning + :warning :error :read-error)) + +(defun slime-severity< (sev1 sev2) + "Return true if SEV1 is less severe than SEV2." + (< (cl-position sev1 slime-severity-order) + (cl-position sev2 slime-severity-order))) + +(defun slime-most-severe (sev1 sev2) + "Return the most servere of two conditions." + (if (slime-severity< sev1 sev2) sev2 sev1)) + +;; XXX: unused function +(defun slime-visit-source-path (source-path) + "Visit a full source path including the top-level form." + (goto-char (point-min)) + (slime-forward-source-path source-path)) + +(defun slime-forward-positioned-source-path (source-path) + "Move forward through a sourcepath from a fixed position. +The point is assumed to already be at the outermost sexp, making the +first element of the source-path redundant." + (ignore-errors + (slime-forward-sexp) + (beginning-of-defun)) + (let ((source-path (cdr source-path))) + (when source-path + (down-list 1) + (slime-forward-source-path source-path)))) + +(defun slime-forward-source-path (source-path) + (let ((origin (point))) + (condition-case nil + (progn + (cl-loop for (count . more) on source-path + do (progn + (slime-forward-sexp count) + (when more (down-list 1)))) + ;; Align at beginning + (slime-forward-sexp) + (beginning-of-sexp)) + (error (goto-char origin))))) + + +;; FIXME: really fix this mess +;; FIXME: the check shouln't be done here anyway but by M-. itself. + +(defun slime-filesystem-toplevel-directory () + ;; Windows doesn't have a true toplevel root directory, and all + ;; filenames look like "c:/foo/bar/quux.baz" from an Emacs + ;; perspective anyway. + (if (memq system-type '(ms-dos windows-nt)) + "" + (file-name-as-directory "/"))) + +(defun slime-file-name-merge-source-root (target-filename buffer-filename) + "Returns a filename where the source root directory of TARGET-FILENAME +is replaced with the source root directory of BUFFER-FILENAME. + +If no common source root could be determined, return NIL. + +E.g. (slime-file-name-merge-source-root + \"/usr/local/src/joe/upstream/sbcl/code/late-extensions.lisp\" + \"/usr/local/src/joe/hacked/sbcl/compiler/deftype.lisp\") + + ==> \"/usr/local/src/joe/hacked/sbcl/code/late-extensions.lisp\" +" + (let ((target-dirs (split-string (file-name-directory target-filename) + "/" t)) + (buffer-dirs (split-string (file-name-directory buffer-filename) + "/" t))) + ;; Starting from the end, we look if one of the TARGET-DIRS exists + ;; in BUFFER-FILENAME---if so, it and everything left from that dirname + ;; is considered to be the source root directory of BUFFER-FILENAME. + (cl-loop with target-suffix-dirs = nil + with buffer-dirs* = (reverse buffer-dirs) + with target-dirs* = (reverse target-dirs) + for target-dir in target-dirs* + do (let ((concat-dirs (lambda (dirs) + (apply #'concat + (mapcar #'file-name-as-directory + dirs)))) + (pos (cl-position target-dir buffer-dirs* + :test #'equal))) + (if (not pos) ; TARGET-DIR not in BUFFER-FILENAME? + (push target-dir target-suffix-dirs) + (let* ((target-suffix + ; PUSH reversed for us! + (funcall concat-dirs target-suffix-dirs)) + (buffer-root + (funcall concat-dirs + (reverse (nthcdr pos buffer-dirs*))))) + (cl-return (concat (slime-filesystem-toplevel-directory) + buffer-root + target-suffix + (file-name-nondirectory + target-filename))))))))) + +(defun slime-highlight-differences-in-dirname (base-dirname contrast-dirname) + "Returns a copy of BASE-DIRNAME where all differences between +BASE-DIRNAME and CONTRAST-DIRNAME are propertized with a +highlighting face." + (setq base-dirname (file-name-as-directory base-dirname)) + (setq contrast-dirname (file-name-as-directory contrast-dirname)) + (let ((base-dirs (split-string base-dirname "/" t)) + (contrast-dirs (split-string contrast-dirname "/" t))) + (with-temp-buffer + (cl-loop initially (insert (slime-filesystem-toplevel-directory)) + for base-dir in base-dirs do + (let ((pos (cl-position base-dir contrast-dirs :test #'equal))) + (cond ((not pos) + (slime-insert-propertized '(face highlight) base-dir) + (insert "/")) + (t + (insert (file-name-as-directory base-dir)) + (setq contrast-dirs + (nthcdr (1+ pos) contrast-dirs)))))) + (buffer-substring (point-min) (point-max))))) + +(defvar slime-warn-when-possibly-tricked-by-M-. t + "When working on multiple source trees simultaneously, the way +`slime-edit-definition' (M-.) works can sometimes be confusing: + +`M-.' visits locations that are present in the current Lisp image, +which works perfectly well as long as the image reflects the source +tree that one is currently looking at. + +In the other case, however, one can easily end up visiting a file +in a different source root directory (cl-the one corresponding to +the Lisp image), and is thus easily tricked to modify the wrong +source files---which can lead to quite some stressfull cursing. + +If this variable is T, a warning message is issued to raise the +user's attention whenever `M-.' is about opening a file in a +different source root that also exists in the source root +directory of the user's current buffer. + +There's no guarantee that all possible cases are covered, but +if you encounter such a warning, it's a strong indication that +you should check twice before modifying.") + +(defun slime-maybe-warn-for-different-source-root (target-filename + buffer-filename) + (let ((guessed-target (slime-file-name-merge-source-root target-filename + buffer-filename))) + (when (and guessed-target + (not (equal guessed-target target-filename)) + (file-exists-p guessed-target)) + (slime-message "Attention: This is `%s'." + (concat (slime-highlight-differences-in-dirname + (file-name-directory target-filename) + (file-name-directory guessed-target)) + (file-name-nondirectory target-filename)))))) + +(defun slime-check-location-filename-sanity (filename) + (when slime-warn-when-possibly-tricked-by-M-. + (cl-macrolet ((truename-safe (file) `(and ,file (file-truename ,file)))) + (let ((target-filename (truename-safe filename)) + (buffer-filename (truename-safe (buffer-file-name)))) + (when (and target-filename + buffer-filename) + (slime-maybe-warn-for-different-source-root + target-filename buffer-filename)))))) + +(defun slime-check-location-buffer-name-sanity (buffer-name) + (slime-check-location-filename-sanity + (buffer-file-name (get-buffer buffer-name)))) + + + +(defun slime-goto-location-buffer (buffer) + (slime-dcase buffer + ((:file filename) + (let ((filename (slime-from-lisp-filename filename))) + (slime-check-location-filename-sanity filename) + (set-buffer (or (get-file-buffer filename) + (let ((find-file-suppress-same-file-warnings t)) + (find-file-noselect filename)))))) + ((:buffer buffer-name) + (slime-check-location-buffer-name-sanity buffer-name) + (set-buffer buffer-name)) + ((:buffer-and-file buffer filename) + (slime-goto-location-buffer + (if (get-buffer buffer) + (list :buffer buffer) + (list :file filename)))) + ((:source-form string) + (set-buffer (get-buffer-create (slime-buffer-name :source))) + (erase-buffer) + (lisp-mode) + (insert string) + (goto-char (point-min))) + ((:zip file entry) + (require 'arc-mode) + (set-buffer (find-file-noselect file t)) + (goto-char (point-min)) + (re-search-forward (concat " " entry "$")) + (let ((buffer (save-window-excursion + (archive-extract) + (current-buffer)))) + (set-buffer buffer) + (goto-char (point-min)))))) + +(defun slime-goto-location-position (position) + (slime-dcase position + ((:position pos) + (goto-char 1) + (forward-char (- (1- pos) (slime-eol-conversion-fixup (1- pos))))) + ((:offset start offset) + (goto-char start) + (forward-char offset)) + ((:line start &optional column) + (goto-char (point-min)) + (beginning-of-line start) + (cond (column (move-to-column column)) + (t (skip-chars-forward " \t")))) + ((:function-name name) + (let ((case-fold-search t) + (name (regexp-quote name))) + (goto-char (point-min)) + (when (or + (re-search-forward + (format "\\s *(def\\(\\s_\\|\\sw\\)*\\s +(*%s\\S_" + (regexp-quote name)) nil t) + (re-search-forward + (format "[( \t]%s\\>\\(\\s \\|$\\)" name) nil t)) + (goto-char (match-beginning 0))))) + ((:method name specializers &rest qualifiers) + (slime-search-method-location name specializers qualifiers)) + ((:source-path source-path start-position) + (cond (start-position + (goto-char start-position) + (slime-forward-positioned-source-path source-path)) + (t + (slime-forward-source-path source-path)))) + ((:eof) + (goto-char (point-max))))) + +(defun slime-eol-conversion-fixup (n) + ;; Return the number of \r\n eol markers that we need to cross when + ;; moving N chars forward. N is the number of chars but \r\n are + ;; counted as 2 separate chars. + (cl-case (coding-system-eol-type buffer-file-coding-system) + ((1) + (save-excursion + (cl-do ((pos (+ (point) n)) + (count 0 (1+ count))) + ((>= (point) pos) (1- count)) + (forward-line) + (cl-decf pos)))) + (t 0))) + +(defun slime-search-method-location (name specializers qualifiers) + ;; Look for a sequence of words (def method name + ;; qualifers specializers don't look for "T" since it isn't requires + ;; (arg without t) as class is taken as such. + (let* ((case-fold-search t) + (name (regexp-quote name)) + (qualifiers (mapconcat (lambda (el) (concat ".+?\\<" el "\\>")) + qualifiers "")) + (specializers (mapconcat + (lambda (el) + (if (eql (aref el 0) ?\() + (let ((spec (read el))) + (if (eq (car spec) 'EQL) + (concat + ".*?\\n\\{0,1\\}.*?(EQL.*?'\\{0,1\\}" + (format "%s" (cl-second spec)) ")") + (error "don't understand specializer: %s,%s" + el (car spec)))) + (concat ".+?\n\\{0,1\\}.+?\\<" el "\\>"))) + (remove "T" specializers) "")) + (regexp (format "\\s *(def\\(\\s_\\|\\sw\\)*\\s +%s\\s +%s%s" name + qualifiers specializers))) + (or (and (re-search-forward regexp nil t) + (goto-char (match-beginning 0))) + ;; (slime-goto-location-position `(:function-name ,name)) + ))) + +(defun slime-search-call-site (fname) + "Move to the place where FNAME called. +Don't move if there are multiple or no calls in the current defun." + (save-restriction + (narrow-to-defun) + (let ((start (point)) + (regexp (concat "(" fname "[)\n \t]")) + (case-fold-search t)) + (cond ((and (re-search-forward regexp nil t) + (not (re-search-forward regexp nil t))) + (goto-char (match-beginning 0))) + (t (goto-char start)))))) + +(defun slime-search-edit-path (edit-path) + "Move to EDIT-PATH starting at the current toplevel form." + (when edit-path + (unless (and (= (current-column) 0) + (looking-at "(")) + (beginning-of-defun)) + (slime-forward-source-path edit-path))) + +(defun slime-goto-source-location (location &optional noerror) + "Move to the source location LOCATION. Several kinds of locations +are supported: + + ::= (:location ) + | (:error ) + + ::= (:file ) + | (:buffer ) + | (:buffer-and-file ) + | (:source-form ) + | (:zip ) + + ::= (:position ) ; 1 based (for files) + | (:offset ) ; start+offset (for C-c C-c) + | (:line []) + | (:function-name ) + | (:source-path ) + | (:method . )" + (slime-dcase location + ((:location buffer _position _hints) + (slime-goto-location-buffer buffer) + (let ((pos (slime-location-offset location))) + (cond ((and (<= (point-min) pos) (<= pos (point-max)))) + (widen-automatically (widen)) + (t + (error "Location is outside accessible part of buffer"))) + (goto-char pos))) + ((:error message) + (if noerror + (slime-message "%s" message) + (error "%s" message))))) + +(defun slime-location-offset (location) + "Return the position, as character number, of LOCATION." + (save-restriction + (widen) + (condition-case nil + (slime-goto-location-position + (slime-location.position location)) + (error (goto-char 0))) + (cl-destructuring-bind (&key snippet edit-path call-site align) + (slime-location.hints location) + (when snippet (slime-isearch snippet)) + (when edit-path (slime-search-edit-path edit-path)) + (when call-site (slime-search-call-site call-site)) + (when align + (slime-forward-sexp) + (beginning-of-sexp))) + (point))) + + +;;;;; Incremental search +;; +;; Search for the longest match of a string in either direction. +;; +;; This is for locating text that is expected to be near the point and +;; may have been modified (but hopefully not near the beginning!) + +(defun slime-isearch (string) + "Find the longest occurence of STRING either backwards of forwards. +If multiple matches exist the choose the one nearest to point." + (goto-char + (let* ((start (point)) + (len1 (slime-isearch-with-function 'search-forward string)) + (pos1 (point))) + (goto-char start) + (let* ((len2 (slime-isearch-with-function 'search-backward string)) + (pos2 (point))) + (cond ((and len1 len2) + ;; Have a match in both directions + (cond ((= len1 len2) + ;; Both are full matches -- choose the nearest. + (if (< (abs (- start pos1)) + (abs (- start pos2))) + pos1 pos2)) + ((> len1 len2) pos1) + ((> len2 len1) pos2))) + (len1 pos1) + (len2 pos2) + (t start)))))) + +(defun slime-isearch-with-function (search-fn string) + "Search for the longest substring of STRING using SEARCH-FN. +SEARCH-FN is either the symbol `search-forward' or `search-backward'." + (unless (string= string "") + (cl-loop for i from 1 to (length string) + while (funcall search-fn (substring string 0 i) nil t) + for match-data = (match-data) + do (cl-case search-fn + (search-forward (goto-char (match-beginning 0))) + (search-backward (goto-char (1+ (match-end 0))))) + finally (cl-return (if (null match-data) + nil + ;; Finish based on the last successful match + (store-match-data match-data) + (goto-char (match-beginning 0)) + (- (match-end 0) (match-beginning 0))))))) + + +;;;;; Visiting and navigating the overlays of compiler notes + +(defun slime-next-note () + "Go to and describe the next compiler note in the buffer." + (interactive) + (let ((here (point)) + (note (slime-find-next-note))) + (if note + (slime-show-note note) + (goto-char here) + (message "No next note.")))) + +(defun slime-previous-note () + "Go to and describe the previous compiler note in the buffer." + (interactive) + (let ((here (point)) + (note (slime-find-previous-note))) + (if note + (slime-show-note note) + (goto-char here) + (message "No previous note.")))) + +(defun slime-goto-first-note (&rest _) + "Go to the first note in the buffer." + (let ((point (point))) + (goto-char (point-min)) + (cond ((slime-find-next-note) + (slime-show-note (slime-note-at-point))) + (t (goto-char point))))) + +(defun slime-remove-notes () + "Remove compiler-note annotations from the current buffer." + (interactive) + (slime-remove-old-overlays)) + +(defun slime-show-note (overlay) + "Present the details of a compiler note to the user." + (slime-temporarily-highlight-note overlay) + (if (get-buffer-window (slime-buffer-name :compilation) t) + (slime-goto-note-in-compilation-log (overlay-get overlay 'slime-note)) + (let ((message (get-char-property (point) 'help-echo))) + (slime-message "%s" (if (zerop (length message)) "\"\"" message))))) + +;; FIXME: could probably use flash region +(defun slime-temporarily-highlight-note (overlay) + "Temporarily highlight a compiler note's overlay. +The highlighting is designed to both make the relevant source more +visible, and to highlight any further notes that are nested inside the +current one. + +The highlighting is automatically undone with a timer." + (run-with-timer 0.2 nil + #'overlay-put overlay 'face (overlay-get overlay 'face)) + (overlay-put overlay 'face 'slime-highlight-face)) + + +;;;;; Overlay lookup operations + +(defun slime-note-at-point () + "Return the overlay for a note starting at point, otherwise NIL." + (cl-find (point) (slime-note-overlays-at-point) + :key 'overlay-start)) + +(defun slime-note-overlay-p (overlay) + "Return true if OVERLAY represents a compiler note." + (overlay-get overlay 'slime-note)) + +(defun slime-note-overlays-at-point () + "Return a list of all note overlays that are under the point." + (cl-remove-if-not 'slime-note-overlay-p (overlays-at (point)))) + +(defun slime-find-next-note () + "Go to the next position with the `slime-note' text property. +Retuns the note overlay if such a position is found, otherwise nil." + (slime-search-property 'slime-note nil #'slime-note-at-point)) + +(defun slime-find-previous-note () + "Go to the next position with the `slime-note' text property. +Retuns the note overlay if such a position is found, otherwise nil." + (slime-search-property 'slime-note t #'slime-note-at-point)) + + +;;;; Arglist Display + +(defun slime-space (n) + "Insert a space and print some relevant information (function arglist). +Designed to be bound to the SPC key. Prefix argument can be used to insert +more than one space." + (interactive "p") + (self-insert-command n) + (slime-echo-arglist)) + +(put 'slime-space 'delete-selection t) ; for delete-section-mode & CUA + +(defun slime-echo-arglist () + (when (slime-background-activities-enabled-p) + (let ((op (slime-operator-before-point))) + (when op + (slime-eval-async `(swank:operator-arglist ,op + ,(slime-current-package)) + (lambda (arglist) + (when arglist + (slime-message "%s" arglist)))))))) + +(defvar slime-operator-before-point-function 'slime-lisp-operator-before-point) + +(defun slime-operator-before-point () + (funcall slime-operator-before-point-function)) + +(defun slime-lisp-operator-before-point () + (ignore-errors + (save-excursion + (backward-up-list 1) + (down-list 1) + (slime-symbol-at-point)))) + +;;;; Completion + +;; FIXME: use this in Emacs 24 +;;(define-obsolete-function-alias slime-complete-symbol completion-at-point) + +(defalias 'slime-complete-symbol #'completion-at-point) +(make-obsolete 'slime-complete-symbol #'completion-at-point "2015-10-17") + +;; This is the function that we add to +;; `completion-at-point-functions'. For backward-compatibilty we look +;; at `slime-complete-symbol-function' first. The indirection through +;; `slime-completion-at-point-functions' is used so that users don't +;; have to set `completion-at-point-functions' in every slime-like +;; buffer. +(defun slime--completion-at-point () + (cond (slime-complete-symbol-function + slime-complete-symbol-function) + (t + (run-hook-with-args-until-success + 'slime-completion-at-point-functions)))) + +(defun slime-setup-completion () + (add-hook 'completion-at-point-functions #'slime--completion-at-point nil t)) + +(defun slime-simple-completion-at-point () + "Complete the symbol at point. +Perform completion similar to `elisp-completion-at-point'." + (let* ((end (point)) + (beg (slime-symbol-start-pos))) + (list beg end (completion-table-dynamic #'slime-simple-completions)))) + +(defun slime-filename-completion () + "If point is at a string starting with \", complete it as filename. +Return nil if point is not at filename." + (when (save-excursion (re-search-backward "\"[^ \t\n]+\\=" + (max (point-min) (- (point) 1000)) + t)) + (let ((comint-completion-addsuffix '("/" . "\""))) + (comint-filename-completion)))) + +;; FIXME: for backward compatibility. Remove it one day +;; together with slime-complete-symbol-function. +(defun slime-simple-complete-symbol () + (let ((completion-at-point-functions '(slime-maybe-complete-as-filename + slime-simple-completion-at-point))) + (completion-at-point))) + +;; NOTE: the original idea was to bind this to TAB but that no longer +;; works as `completion-at-point' sets a transient keymap that +;; overrides TAB. So this is rather useless now. +(defun slime-indent-and-complete-symbol () + "Indent the current line and perform symbol completion. +First indent the line. If indenting doesn't move point, complete +the symbol. If there's no symbol at the point, show the arglist +for the most recently enclosed macro or function." + (interactive) + (let ((pos (point))) + (unless (get-text-property (line-beginning-position) 'slime-repl-prompt) + (lisp-indent-line)) + (when (= pos (point)) + (cond ((save-excursion (re-search-backward "[^() \n\t\r]+\\=" nil t)) + (completion-at-point)) + ((memq (char-before) '(?\t ?\ )) + (slime-echo-arglist)))))) + +(make-obsolete 'slime-indent-and-complete-symbol + "Set tab-always-indent to 'complete." + "2015-10-18") + +(defvar slime-minibuffer-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map minibuffer-local-map) + (define-key map "\t" #'completion-at-point) + (define-key map "\M-\t" #'completion-at-point) + map) + "Minibuffer keymap used for reading CL expressions.") + +(defvar slime-minibuffer-history '() + "History list of expressions read from the minibuffer.") + +(defun slime-minibuffer-setup-hook () + (cons (lexical-let ((package (slime-current-package)) + (connection (slime-connection))) + (lambda () + (setq slime-buffer-package package) + (setq slime-buffer-connection connection) + (set-syntax-table lisp-mode-syntax-table) + (slime-setup-completion))) + minibuffer-setup-hook)) + +(defun slime-read-from-minibuffer (prompt &optional initial-value history) + "Read a string from the minibuffer, prompting with PROMPT. +If INITIAL-VALUE is non-nil, it is inserted into the minibuffer before +reading input. The result is a string (\"\" if no input was given)." + (let ((minibuffer-setup-hook (slime-minibuffer-setup-hook))) + (read-from-minibuffer prompt initial-value slime-minibuffer-map + nil (or history 'slime-minibuffer-history)))) + +(defun slime-bogus-completion-alist (list) + "Make an alist out of list. +The same elements go in the CAR, and nil in the CDR. To support the +apparently very stupid `try-completions' interface, that wants an +alist but ignores CDRs." + (mapcar (lambda (x) (cons x nil)) list)) + +(defun slime-simple-completions (prefix) + (cl-destructuring-bind (completions _partial) + (let ((slime-current-thread t)) + (slime-eval + `(swank:simple-completions ,(substring-no-properties prefix) + ',(slime-current-package)))) + completions)) + + +;;;; Edit definition + +(defun slime-push-definition-stack () + "Add point to find-tag-marker-ring." + (require 'etags) + (ring-insert find-tag-marker-ring (point-marker))) + +(defun slime-pop-find-definition-stack () + "Pop the edit-definition stack and goto the location." + (interactive) + (pop-tag-mark)) + +(cl-defstruct (slime-xref (:conc-name slime-xref.) (:type list)) + dspec location) + +(cl-defstruct (slime-location (:conc-name slime-location.) (:type list) + (:constructor nil) + (:copier nil)) + tag buffer position hints) + +(defun slime-location-p (o) (and (consp o) (eq (car o) :location))) + +(defun slime-xref-has-location-p (xref) + (slime-location-p (slime-xref.location xref))) + +(defun make-slime-buffer-location (buffer-name position &optional hints) + `(:location (:buffer ,buffer-name) (:position ,position) + ,(when hints `(:hints ,hints)))) + +(defun make-slime-file-location (file-name position &optional hints) + `(:location (:file ,file-name) (:position ,position) + ,(when hints `(:hints ,hints)))) + +;;; The hooks are tried in order until one succeeds, otherwise the +;;; default implementation involving `slime-find-definitions-function' +;;; is used. The hooks are called with the same arguments as +;;; `slime-edit-definition'. +(defvar slime-edit-definition-hooks) + +(defun slime-edit-definition (&optional name where) + "Lookup the definition of the name at point. +If there's no name at point, or a prefix argument is given, then the +function name is prompted." + (interactive (list (or (and (not current-prefix-arg) + (slime-symbol-at-point)) + (slime-read-symbol-name "Edit Definition of: ")))) + ;; The hooks might search for a name in a different manner, so don't + ;; ask the user if it's missing before the hooks are run + (or (run-hook-with-args-until-success 'slime-edit-definition-hooks + name where) + (slime-edit-definition-cont (slime-find-definitions name) + name where))) + +(defun slime-edit-definition-cont (xrefs name where) + (cl-destructuring-bind (1loc file-alist) (slime-analyze-xrefs xrefs) + (cond ((null xrefs) + (error "No known definition for: %s (in %s)" + name (slime-current-package))) + (1loc + (slime-push-definition-stack) + (slime-pop-to-location (slime-xref.location (car xrefs)) where)) + ((slime-length= xrefs 1) ; ((:error "...")) + (error "%s" (cadr (slime-xref.location (car xrefs))))) + (t + (slime-push-definition-stack) + (slime-show-xrefs file-alist 'definition name + (slime-current-package)))))) + +(defvar slime-edit-uses-xrefs + '(:calls :macroexpands :binds :references :sets :specializes)) + +;;; FIXME. TODO: Would be nice to group the symbols (in each +;;; type-group) by their home-package. +(defun slime-edit-uses (symbol) + "Lookup all the uses of SYMBOL." + (interactive (list (slime-read-symbol-name "Edit Uses of: "))) + (slime-xrefs slime-edit-uses-xrefs + symbol + (lambda (xrefs type symbol package) + (cond + ((null xrefs) + (message "No xref information found for %s." symbol)) + ((and (slime-length= xrefs 1) ; one group + (slime-length= (cdar xrefs) 1)) ; one ref in group + (cl-destructuring-bind (_ (_ loc)) (cl-first xrefs) + (slime-push-definition-stack) + (slime-pop-to-location loc))) + (t + (slime-push-definition-stack) + (slime-show-xref-buffer xrefs type symbol package)))))) + +(defun slime-analyze-xrefs (xrefs) + "Find common filenames in XREFS. +Return a list (SINGLE-LOCATION FILE-ALIST). +SINGLE-LOCATION is true if all xrefs point to the same location. +FILE-ALIST is an alist of the form ((FILENAME . (XREF ...)) ...)." + (list (and xrefs + (let ((loc (slime-xref.location (car xrefs)))) + (and (slime-location-p loc) + (cl-every (lambda (x) (equal (slime-xref.location x) loc)) + (cdr xrefs))))) + (slime-alistify xrefs #'slime-xref-group #'equal))) + +(defun slime-xref-group (xref) + (cond ((slime-xref-has-location-p xref) + (slime-dcase (slime-location.buffer (slime-xref.location xref)) + ((:file filename) filename) + ((:buffer bufname) + (let ((buffer (get-buffer bufname))) + (if buffer + (format "%S" buffer) ; "#" + (format "%s (previously existing buffer)" bufname)))) + ((:buffer-and-file _buffer filename) filename) + ((:source-form _) "(S-Exp)") + ((:zip _zip entry) entry))) + (t + "(No location)"))) + +(defun slime-pop-to-location (location &optional where) + (slime-goto-source-location location) + (let ((point (point))) + (cl-ecase where + ((nil) (switch-to-buffer (current-buffer))) + (window (pop-to-buffer (current-buffer) t)) + (frame (let ((pop-up-frames t)) (pop-to-buffer (current-buffer) t)))) + (goto-char point))) + +(defun slime-postprocess-xref (original-xref) + "Process (for normalization purposes) an Xref comming directly +from SWANK before the rest of Slime sees it. In particular, +convert ETAGS based xrefs to actual file+position based +locations." + (if (not (slime-xref-has-location-p original-xref)) + (list original-xref) + (let ((loc (slime-xref.location original-xref))) + (slime-dcase (slime-location.buffer loc) + ((:etags-file tags-file) + (slime-dcase (slime-location.position loc) + ((:tag &rest tags) + (visit-tags-table tags-file) + (mapcar (lambda (xref) + (let ((old-dspec (slime-xref.dspec original-xref)) + (new-dspec (slime-xref.dspec xref))) + (setf (slime-xref.dspec xref) + (format "%s: %s" old-dspec new-dspec)) + xref)) + (cl-mapcan #'slime-etags-definitions tags))))) + (t + (list original-xref)))))) + +(defun slime-postprocess-xrefs (xrefs) + (cl-mapcan #'slime-postprocess-xref xrefs)) + +(defun slime-find-definitions (name) + "Find definitions for NAME." + (slime-postprocess-xrefs (funcall slime-find-definitions-function name))) + +(defun slime-find-definitions-rpc (name) + (slime-eval `(swank:find-definitions-for-emacs ,name))) + +(defun slime-edit-definition-other-window (name) + "Like `slime-edit-definition' but switch to the other window." + (interactive (list (slime-read-symbol-name "Symbol: "))) + (slime-edit-definition name 'window)) + +(defun slime-edit-definition-other-frame (name) + "Like `slime-edit-definition' but switch to the other window." + (interactive (list (slime-read-symbol-name "Symbol: "))) + (slime-edit-definition name 'frame)) + +(defun slime-edit-definition-with-etags (name) + (interactive (list (slime-read-symbol-name "Symbol: "))) + (let ((xrefs (slime-etags-definitions name))) + (cond (xrefs + (message "Using tag file...") + (slime-edit-definition-cont xrefs name nil)) + (t + (error "No known definition for: %s" name))))) + +(defun slime-etags-to-locations (name) + "Search for definitions matching `name' in the currently active +tags table. Return a possibly empty list of slime-locations." + (let ((locs '())) + (save-excursion + (let ((first-time t)) + (while (visit-tags-table-buffer (not first-time)) + (setq first-time nil) + (goto-char (point-min)) + (while (search-forward name nil t) + (beginning-of-line) + (cl-destructuring-bind (hint line &rest pos) (etags-snarf-tag) + (unless (eq hint t) ; hint==t if we are in a filename line + (push `(:location (:file ,(expand-file-name (file-of-tag))) + (:line ,line) + (:snippet ,hint)) + locs)))))) + (nreverse locs)))) + +(defun slime-etags-definitions (name) + "Search definitions matching NAME in the tags file. +The result is a (possibly empty) list of definitions." + (mapcar (lambda (loc) + (make-slime-xref :dspec (cl-second (slime-location.hints loc)) + :location loc)) + (slime-etags-to-locations name))) + +;;;;; first-change-hook + +(defun slime-first-change-hook () + "Notify Lisp that a source file's buffer has been modified." + ;; Be careful not to disturb anything! + ;; In particular if we muck up the match-data then query-replace + ;; breaks. -luke (26/Jul/2004) + (save-excursion + (save-match-data + (when (and (buffer-file-name) + (file-exists-p (buffer-file-name)) + (slime-background-activities-enabled-p)) + (let ((filename (slime-to-lisp-filename (buffer-file-name)))) + (slime-eval-async `(swank:buffer-first-change ,filename))))))) + +(defun slime-setup-first-change-hook () + (add-hook (make-local-variable 'first-change-hook) + 'slime-first-change-hook)) + +(add-hook 'slime-mode-hook 'slime-setup-first-change-hook) + + +;;;; Eval for Lisp + +(defun slime-lisp-readable-p (x) + (or (stringp x) + (memq x '(nil t)) + (integerp x) + (keywordp x) + (and (consp x) + (let ((l x)) + (while (consp l) + (slime-lisp-readable-p (car x)) + (setq l (cdr l))) + (slime-lisp-readable-p l))))) + +(defun slime--funcall-and-dispatch-result (thread tag fn &rest args) + (let ((ok nil) + (value nil) + (error nil)) + (unwind-protect + (condition-case err + (progn + (setq value (apply fn args)) + (setq ok t)) + ((debug error) + (setq error err))) + (let ((result (cond ((and ok + (not (slime-lisp-readable-p value))) + `(:unreadable ,(slime-prin1-to-string value))) + (ok `(:ok ,value)) + (error `(:error ,(symbol-name (car error)) + . ,(mapcar #'slime-prin1-to-string + (cdr error)))) + (t `(:abort))))) + (slime-dispatch-event `(:emacs-return ,thread ,tag ,result)))))) + +(defun slime-eval-for-lisp (thread tag form-string) + (slime--funcall-and-dispatch-result thread tag + (lambda (s) (eval (read s))) + form-string)) + +(defun slime-check-eval-in-emacs-enabled () + "Raise an error if `slime-enable-evaluate-in-emacs' isn't true." + (unless slime-enable-evaluate-in-emacs + (error (concat "slime-eval-in-emacs disabled for security. " + "Set `slime-enable-evaluate-in-emacs' true to enable it.")))) + + +;;;; RPC from Lisp + +(defmacro defslimefun (name arglist &rest body) + "Define a function via `cl-defun' that can be invoked from SWANK." + `(progn + (put ',name 'slime-rpc t) + (cl-defun ,name ,arglist ,@body))) + +(defun slime-rpc-allowed-p (fn) + (get fn 'slime-rpc)) + +(defun slime-check-rpc-allowed (fn) + "Raise an error if FN does not denote a function defined via +`defslimefun'." + (unless (slime-rpc-allowed-p fn) + (error "Lisp tried to RPC `%s', but it wasn't defined via `defslimefun'." + fn))) + +(defun slime-rpc-from-lisp (thread tag fn args) + (if (not (slime-rpc-allowed-p fn)) + (slime-dispatch-event '(:ed-rpc-forbidden ,thread ,tag ,fn)) + (apply #'slime--funcall-and-dispatch-result thread tag fn args))) + + +;;;; `ED' + +(defvar slime-ed-frame nil + "The frame used by `slime-ed'.") + +(defcustom slime-ed-use-dedicated-frame t + "*When non-nil, `slime-ed' will create and reuse a dedicated frame." + :type 'boolean + :group 'slime-mode) + +(defun slime-ed (what) + "Edit WHAT. + +WHAT can be: + A filename (string), + A list (:filename FILENAME &key LINE COLUMN POSITION), + A function name (:function-name STRING) + nil. + +This is for use in the implementation of COMMON-LISP:ED." + (when slime-ed-use-dedicated-frame + (unless (and slime-ed-frame (frame-live-p slime-ed-frame)) + (setq slime-ed-frame (make-frame))) + (select-frame slime-ed-frame)) + (when what + (slime-dcase what + ((:filename file &key line column position bytep) + (find-file (slime-from-lisp-filename file)) + (when line (slime-goto-line line)) + (when column (move-to-column column)) + (when position + (goto-char (if bytep + (byte-to-position position) + position)))) + ((:function-name name) + (slime-edit-definition name))))) + +(defun slime-goto-line (line-number) + "Move to line LINE-NUMBER (1-based). +This is similar to `goto-line' but without pushing the mark and +the display stuff that we neither need nor want." + (cl-assert (= (buffer-size) (- (point-max) (point-min))) () + "slime-goto-line in narrowed buffer") + (goto-char (point-min)) + (forward-line (1- line-number))) + +(defun slime-y-or-n-p (thread tag question) + (slime-dispatch-event `(:emacs-return ,thread ,tag ,(y-or-n-p question)))) + +(defun slime-read-from-minibuffer-for-swank (thread tag prompt initial-value) + (let ((answer (condition-case nil + (slime-read-from-minibuffer prompt initial-value) + (quit nil)))) + (slime-dispatch-event `(:emacs-return ,thread ,tag ,answer)))) + +;;;; Interactive evaluation. + +(defun slime-interactive-eval (string) + "Read and evaluate STRING and print value in minibuffer. + +Note: If a prefix argument is in effect then the result will be +inserted in the current buffer." + (interactive (list (slime-read-from-minibuffer "Slime Eval: "))) + (cl-case current-prefix-arg + ((nil) + (slime-eval-with-transcript `(swank:interactive-eval ,string))) + ((-) + (slime-eval-save string)) + (t + (slime-eval-print string)))) + +(defvar slime-transcript-start-hook nil + "Hook run before start an evalution.") +(defvar slime-transcript-stop-hook nil + "Hook run after finishing a evalution.") + +(defun slime-display-eval-result (value) + (slime-message "%s" value)) + +(defun slime-eval-with-transcript (form) + "Eval FORM in Lisp. Display output, if any." + (run-hooks 'slime-transcript-start-hook) + (slime-rex () (form) + ((:ok value) + (run-hooks 'slime-transcript-stop-hook) + (slime-display-eval-result value)) + ((:abort condition) + (run-hooks 'slime-transcript-stop-hook) + (message "Evaluation aborted on %s." condition)))) + +(defun slime-eval-print (string) + "Eval STRING in Lisp; insert any output and the result at point." + (slime-eval-async `(swank:eval-and-grab-output ,string) + (lambda (result) + (cl-destructuring-bind (output value) result + (push-mark) + (insert output value))))) + +(defun slime-eval-save (string) + "Evaluate STRING in Lisp and save the result in the kill ring." + (slime-eval-async `(swank:eval-and-grab-output ,string) + (lambda (result) + (cl-destructuring-bind (output value) result + (let ((string (concat output value))) + (kill-new string) + (message "Evaluation finished; pushed result to kill ring.")))))) + +(defun slime-eval-describe (form) + "Evaluate FORM in Lisp and display the result in a new buffer." + (slime-eval-async form (slime-rcurry #'slime-show-description + (slime-current-package)))) + +(defvar slime-description-autofocus nil + "If non-nil select description windows on display.") + +(defun slime-show-description (string package) + ;; So we can have one description buffer open per connection. Useful + ;; for comparing the output of DISASSEMBLE across implementations. + ;; FIXME: could easily be achieved with M-x rename-buffer + (let ((bufname (slime-buffer-name :description))) + (slime-with-popup-buffer (bufname :package package + :connection t + :select slime-description-autofocus) + (princ string) + (goto-char (point-min))))) + +(defun slime-last-expression () + (buffer-substring-no-properties + (save-excursion (backward-sexp) (point)) + (point))) + +(defun slime-eval-last-expression () + "Evaluate the expression preceding point." + (interactive) + (slime-interactive-eval (slime-last-expression))) + +(defun slime-eval-defun () + "Evaluate the current toplevel form. +Use `slime-re-evaluate-defvar' if the from starts with '(defvar'" + (interactive) + (let ((form (slime-defun-at-point))) + (cond ((string-match "^(defvar " form) + (slime-re-evaluate-defvar form)) + (t + (slime-interactive-eval form))))) + +(defun slime-eval-region (start end) + "Evaluate region." + (interactive "r") + (slime-eval-with-transcript + `(swank:interactive-eval-region + ,(buffer-substring-no-properties start end)))) + +(defun slime-pprint-eval-region (start end) + "Evaluate region; pprint the value in a buffer." + (interactive "r") + (slime-eval-describe + `(swank:pprint-eval + ,(buffer-substring-no-properties start end)))) + +(defun slime-eval-buffer () + "Evaluate the current buffer. +The value is printed in the echo area." + (interactive) + (slime-eval-region (point-min) (point-max))) + +(defun slime-re-evaluate-defvar (form) + "Force the re-evaluaton of the defvar form before point. + +First make the variable unbound, then evaluate the entire form." + (interactive (list (slime-last-expression))) + (slime-eval-with-transcript `(swank:re-evaluate-defvar ,form))) + +(defun slime-pprint-eval-last-expression () + "Evaluate the form before point; pprint the value in a buffer." + (interactive) + (slime-eval-describe `(swank:pprint-eval ,(slime-last-expression)))) + +(defun slime-eval-print-last-expression (string) + "Evaluate sexp before point; print value into the current buffer" + (interactive (list (slime-last-expression))) + (insert "\n") + (slime-eval-print string)) + +;;;; Edit Lisp value +;;; +(defun slime-edit-value (form-string) + "\\\ +Edit the value of a setf'able form in a new buffer. +The value is inserted into a temporary buffer for editing and then set +in Lisp when committed with \\[slime-edit-value-commit]." + (interactive + (list (slime-read-from-minibuffer "Edit value (evaluated): " + (slime-sexp-at-point)))) + (slime-eval-async `(swank:value-for-editing ,form-string) + (lexical-let ((form-string form-string) + (package (slime-current-package))) + (lambda (result) + (slime-edit-value-callback form-string result + package))))) + +(make-variable-buffer-local + (defvar slime-edit-form-string nil + "The form being edited by `slime-edit-value'.")) + +(define-minor-mode slime-edit-value-mode + "Mode for editing a Lisp value." + nil + " Edit-Value" + '(("\C-c\C-c" . slime-edit-value-commit))) + +(defun slime-edit-value-callback (form-string current-value package) + (let* ((name (generate-new-buffer-name (format "*Edit %s*" form-string))) + (buffer (slime-with-popup-buffer (name :package package + :connection t + :select t + :mode 'lisp-mode) + (slime-popup-buffer-mode -1) ; don't want binding of 'q' + (slime-mode 1) + (slime-edit-value-mode 1) + (setq slime-edit-form-string form-string) + (insert current-value) + (current-buffer)))) + (with-current-buffer buffer + (setq buffer-read-only nil) + (message "Type C-c C-c when done")))) + +(defun slime-edit-value-commit () + "Commit the edited value to the Lisp image. +\\(See `slime-edit-value'.)" + (interactive) + (if (null slime-edit-form-string) + (error "Not editing a value.") + (let ((value (buffer-substring-no-properties (point-min) (point-max)))) + (lexical-let ((buffer (current-buffer))) + (slime-eval-async `(swank:commit-edited-value ,slime-edit-form-string + ,value) + (lambda (_) + (with-current-buffer buffer + (quit-window t)))))))) + +;;;; Tracing + +(defun slime-untrace-all () + "Untrace all functions." + (interactive) + (slime-eval `(swank:untrace-all))) + +(defun slime-toggle-trace-fdefinition (spec) + "Toggle trace." + (interactive (list (slime-read-from-minibuffer + "(Un)trace: " (slime-symbol-at-point)))) + (message "%s" (slime-eval `(swank:swank-toggle-trace ,spec)))) + + + +(defun slime-disassemble-symbol (symbol-name) + "Display the disassembly for SYMBOL-NAME." + (interactive (list (slime-read-symbol-name "Disassemble: "))) + (slime-eval-describe `(swank:disassemble-form ,(concat "'" symbol-name)))) + +(defun slime-undefine-function (symbol-name) + "Unbind the function slot of SYMBOL-NAME." + (interactive (list (slime-read-symbol-name "fmakunbound: " t))) + (slime-eval-async `(swank:undefine-function ,symbol-name) + (lambda (result) (message "%s" result)))) + +(defun slime-unintern-symbol (symbol-name package) + "Unintern the symbol given with SYMBOL-NAME PACKAGE." + (interactive (list (slime-read-symbol-name "Unintern symbol: " t) + (slime-read-package-name "from package: " + (slime-current-package)))) + (slime-eval-async `(swank:unintern-symbol ,symbol-name ,package) + (lambda (result) (message "%s" result)))) + +(defun slime-delete-package (package-name) + "Delete the package with name PACKAGE-NAME." + (interactive (list (slime-read-package-name "Delete package: " + (slime-current-package)))) + (slime-eval-async `(cl:delete-package + (swank::guess-package ,package-name)))) + +(defun slime-load-file (filename) + "Load the Lisp file FILENAME." + (interactive (list + (read-file-name "Load file: " nil nil + nil (if (buffer-file-name) + (file-name-nondirectory + (buffer-file-name)))))) + (let ((lisp-filename (slime-to-lisp-filename (expand-file-name filename)))) + (slime-eval-with-transcript `(swank:load-file ,lisp-filename)))) + +(defvar slime-change-directory-hooks nil + "Hook run by `slime-change-directory'. +The functions are called with the new (absolute) directory.") + +(defun slime-change-directory (directory) + "Make DIRECTORY become Lisp's current directory. +Return whatever swank:set-default-directory returns." + (let ((dir (expand-file-name directory))) + (prog1 (slime-eval `(swank:set-default-directory + ,(slime-to-lisp-filename dir))) + (slime-with-connection-buffer nil (cd-absolute dir)) + (run-hook-with-args 'slime-change-directory-hooks dir)))) + +(defun slime-cd (directory) + "Make DIRECTORY become Lisp's current directory. +Return whatever swank:set-default-directory returns." + (interactive (list (read-directory-name "Directory: " nil nil t))) + (message "default-directory: %s" (slime-change-directory directory))) + +(defun slime-pwd () + "Show Lisp's default directory." + (interactive) + (message "Directory %s" (slime-eval `(swank:default-directory)))) + + +;;;; Profiling + +(defun slime-toggle-profile-fdefinition (fname-string) + "Toggle profiling for FNAME-STRING." + (interactive (list (slime-read-from-minibuffer + "(Un)Profile: " + (slime-symbol-at-point)))) + (slime-eval-async `(swank:toggle-profile-fdefinition ,fname-string) + (lambda (r) (message "%s" r)))) + +(defun slime-unprofile-all () + "Unprofile all functions." + (interactive) + (slime-eval-async '(swank:unprofile-all) + (lambda (r) (message "%s" r)))) + +(defun slime-profile-report () + "Print profile report." + (interactive) + (slime-eval-with-transcript '(swank:profile-report))) + +(defun slime-profile-reset () + "Reset profile counters." + (interactive) + (slime-eval-async (slime-eval `(swank:profile-reset)) + (lambda (r) (message "%s" r)))) + +(defun slime-profiled-functions () + "Return list of names of currently profiled functions." + (interactive) + (slime-eval-async `(swank:profiled-functions) + (lambda (r) (message "%s" r)))) + +(defun slime-profile-package (package callers methods) + "Profile all functions in PACKAGE. +If CALLER is non-nil names have counts of the most common calling +functions recorded. +If METHODS is non-nil, profile all methods of all generic function +having names in the given package." + (interactive (list (slime-read-package-name "Package: ") + (y-or-n-p "Record the most common callers? ") + (y-or-n-p "Profile methods? "))) + (slime-eval-async `(swank:swank-profile-package ,package ,callers ,methods) + (lambda (r) (message "%s" r)))) + +(defun slime-profile-by-substring (substring &optional package) + "Profile all functions which names contain SUBSTRING. +If PACKAGE is NIL, then search in all packages." + (interactive (list + (slime-read-from-minibuffer + "Profile by matching substring: " + (slime-symbol-at-point)) + (slime-read-package-name "Package (RET for all packages): "))) + (let ((package (unless (equal package "") package))) + (slime-eval-async `(swank:profile-by-substring ,substring ,package) + (lambda (r) (message "%s" r)) ))) + +;;;; Documentation + +(defvar slime-documentation-lookup-function + 'slime-hyperspec-lookup) + +(defun slime-documentation-lookup () + "Generalized documentation lookup. Defaults to hyperspec lookup." + (interactive) + (call-interactively slime-documentation-lookup-function)) + +(defun slime-hyperspec-lookup (symbol-name) + "A wrapper for `hyperspec-lookup'" + (interactive (list (common-lisp-hyperspec-read-symbol-name + (slime-symbol-at-point)))) + (hyperspec-lookup symbol-name)) + +(defun slime-describe-symbol (symbol-name) + "Describe the symbol at point." + (interactive (list (slime-read-symbol-name "Describe symbol: "))) + (when (not symbol-name) + (error "No symbol given")) + (slime-eval-describe `(swank:describe-symbol ,symbol-name))) + +(defun slime-documentation (symbol-name) + "Display function- or symbol-documentation for SYMBOL-NAME." + (interactive (list (slime-read-symbol-name "Documentation for symbol: "))) + (when (not symbol-name) + (error "No symbol given")) + (slime-eval-describe + `(swank:documentation-symbol ,symbol-name))) + +(defun slime-describe-function (symbol-name) + (interactive (list (slime-read-symbol-name "Describe symbol's function: "))) + (when (not symbol-name) + (error "No symbol given")) + (slime-eval-describe `(swank:describe-function ,symbol-name))) + +(defface slime-apropos-symbol + '((t (:inherit bold))) + "Face for the symbol name in Apropos output." + :group 'slime) + +(defface slime-apropos-label + '((t (:inherit italic))) + "Face for label (`Function', `Variable' ...) in Apropos output." + :group 'slime) + +(defun slime-apropos-summary (string case-sensitive-p package only-external-p) + "Return a short description for the performed apropos search." + (concat (if case-sensitive-p "Case-sensitive " "") + "Apropos for " + (format "%S" string) + (if package (format " in package %S" package) "") + (if only-external-p " (external symbols only)" ""))) + +(defun slime-apropos (string &optional only-external-p package + case-sensitive-p) + "Show all bound symbols whose names match STRING. With prefix +arg, you're interactively asked for parameters of the search." + (interactive + (if current-prefix-arg + (list (read-string "SLIME Apropos: ") + (y-or-n-p "External symbols only? ") + (let ((pkg (slime-read-package-name "Package: "))) + (if (string= pkg "") nil pkg)) + (y-or-n-p "Case-sensitive? ")) + (list (read-string "SLIME Apropos: ") t nil nil))) + (let ((buffer-package (or package (slime-current-package)))) + (slime-eval-async + `(swank:apropos-list-for-emacs ,string ,only-external-p + ,case-sensitive-p ',package) + (slime-rcurry #'slime-show-apropos string buffer-package + (slime-apropos-summary string case-sensitive-p + package only-external-p))))) + +(defun slime-apropos-all () + "Shortcut for (slime-apropos nil nil)" + (interactive) + (slime-apropos (read-string "SLIME Apropos: ") nil nil)) + +(defun slime-apropos-package (package &optional internal) + "Show apropos listing for symbols in PACKAGE. +With prefix argument include internal symbols." + (interactive (list (let ((pkg (slime-read-package-name "Package: "))) + (if (string= pkg "") (slime-current-package) pkg)) + current-prefix-arg)) + (slime-apropos "" (not internal) package)) + +(autoload 'apropos-mode "apropos") +(defun slime-show-apropos (plists string package summary) + (if (null plists) + (message "No apropos matches for %S" string) + (slime-with-popup-buffer ((slime-buffer-name :apropos) + :package package :connection t + :mode 'apropos-mode) + (if (boundp 'header-line-format) + (setq header-line-format summary) + (insert summary "\n\n")) + (slime-set-truncate-lines) + (slime-print-apropos plists) + (set-syntax-table lisp-mode-syntax-table) + (goto-char (point-min))))) + +(defvar slime-apropos-namespaces + '((:variable "Variable") + (:function "Function") + (:generic-function "Generic Function") + (:macro "Macro") + (:special-operator "Special Operator") + (:setf "Setf") + (:type "Type") + (:class "Class") + (:alien-type "Alien type") + (:alien-struct "Alien struct") + (:alien-union "Alien type") + (:alien-enum "Alien enum"))) + +(defun slime-print-apropos (plists) + (dolist (plist plists) + (let ((designator (plist-get plist :designator))) + (cl-assert designator) + (slime-insert-propertized `(face slime-apropos-symbol) designator)) + (terpri) + (cl-loop for (prop value) on plist by #'cddr + unless (eq prop :designator) do + (let ((namespace (cadr (or (assq prop slime-apropos-namespaces) + (error "Unknown property: %S" prop)))) + (start (point))) + (princ " ") + (slime-insert-propertized `(face slime-apropos-label) namespace) + (princ ": ") + (princ (cl-etypecase value + (string value) + ((member nil :not-documented) "(not documented)"))) + (add-text-properties + start (point) + (list 'type prop 'action 'slime-call-describer + 'button t 'apropos-label namespace + 'item (plist-get plist :designator))) + (terpri))))) + +(defun slime-call-describer (arg) + (let* ((pos (if (markerp arg) arg (point))) + (type (get-text-property pos 'type)) + (item (get-text-property pos 'item))) + (slime-eval-describe `(swank:describe-definition-for-emacs ,item ,type)))) + +(defun slime-info () + "Open Slime manual" + (interactive) + (let ((file (expand-file-name "doc/slime.info" slime-path))) + (if (file-exists-p file) + (info file) + (message "No slime.info, run `make slime.info' in %s" + (expand-file-name "doc/" slime-path))))) + + +;;;; XREF: cross-referencing + +(defvar slime-xref-mode-map) + +(define-derived-mode slime-xref-mode lisp-mode "Xref" + "slime-xref-mode: Major mode for cross-referencing. +\\\ +The most important commands: +\\[slime-xref-quit] - Dismiss buffer. +\\[slime-show-xref] - Display referenced source and keep xref window. +\\[slime-goto-xref] - Jump to referenced source and dismiss xref window. + +\\{slime-xref-mode-map} +\\{slime-popup-buffer-mode-map} +" + (slime-popup-buffer-mode) + (setq font-lock-defaults nil) + (setq delayed-mode-hooks nil) + (slime-mode -1)) + +(slime-define-keys slime-xref-mode-map + ((kbd "RET") 'slime-goto-xref) + ((kbd "SPC") 'slime-goto-xref) + ("v" 'slime-show-xref) + ("n" 'slime-xref-next-line) + ("p" 'slime-xref-prev-line) + ("." 'slime-xref-next-line) + ("," 'slime-xref-prev-line) + ("\C-c\C-c" 'slime-recompile-xref) + ("\C-c\C-k" 'slime-recompile-all-xrefs) + ("\M-," 'slime-xref-retract) + ([remap next-line] 'slime-xref-next-line) + ([remap previous-line] 'slime-xref-prev-line) + ) + + +;;;;; XREF results buffer and window management + +(cl-defmacro slime-with-xref-buffer ((_xref-type _symbol &optional package) + &body body) + "Execute BODY in a xref buffer, then show that buffer." + (declare (indent 1)) + `(slime-with-popup-buffer ((slime-buffer-name :xref) + :package ,package + :connection t + :select t + :mode 'slime-xref-mode) + (slime-set-truncate-lines) + ,@body)) + +(defun slime-insert-xrefs (xref-alist) + "Insert XREF-ALIST in the current-buffer. +XREF-ALIST is of the form ((GROUP . ((LABEL LOCATION) ...)) ...). +GROUP and LABEL are for decoration purposes. LOCATION is a +source-location." + (cl-loop for (group . refs) in xref-alist do + (slime-insert-propertized '(face bold) group "\n") + (cl-loop for (label location) in refs do + (slime-insert-propertized + (list 'slime-location location + 'face 'font-lock-keyword-face) + " " (slime-one-line-ify label) "\n"))) + ;; Remove the final newline to prevent accidental window-scrolling + (backward-delete-char 1)) + +(defun slime-xref-next-line () + (interactive) + (slime-xref-show-location (slime-search-property 'slime-location))) + +(defun slime-xref-prev-line () + (interactive) + (slime-xref-show-location (slime-search-property 'slime-location t))) + +(defun slime-xref-show-location (loc) + (cl-ecase (car loc) + (:location (slime-show-source-location loc nil 1)) + (:error (message "%s" (cadr loc))) + ((nil)))) + +(defvar slime-next-location-function nil + "Function to call for going to the next location.") + +(defvar slime-previous-location-function nil + "Function to call for going to the previous location.") + +(defvar slime-xref-last-buffer nil + "The most recent XREF results buffer. +This is used by `slime-goto-next-xref'") + +(defun slime-show-xref-buffer (xrefs _type _symbol package) + (slime-with-xref-buffer (_type _symbol package) + (slime-insert-xrefs xrefs) + (setq slime-next-location-function 'slime-goto-next-xref) + (setq slime-previous-location-function 'slime-goto-previous-xref) + (setq slime-xref-last-buffer (current-buffer)) + (goto-char (point-min)))) + +(defun slime-show-xrefs (xrefs type symbol package) + "Show the results of an XREF query." + (if (null xrefs) + (message "No references found for %s." symbol) + (slime-show-xref-buffer xrefs type symbol package))) + + +;;;;; XREF commands + +(defun slime-who-calls (symbol) + "Show all known callers of the function SYMBOL." + (interactive (list (slime-read-symbol-name "Who calls: " t))) + (slime-xref :calls symbol)) + +(defun slime-calls-who (symbol) + "Show all known functions called by the function SYMBOL." + (interactive (list (slime-read-symbol-name "Who calls: " t))) + (slime-xref :calls-who symbol)) + +(defun slime-who-references (symbol) + "Show all known referrers of the global variable SYMBOL." + (interactive (list (slime-read-symbol-name "Who references: " t))) + (slime-xref :references symbol)) + +(defun slime-who-binds (symbol) + "Show all known binders of the global variable SYMBOL." + (interactive (list (slime-read-symbol-name "Who binds: " t))) + (slime-xref :binds symbol)) + +(defun slime-who-sets (symbol) + "Show all known setters of the global variable SYMBOL." + (interactive (list (slime-read-symbol-name "Who sets: " t))) + (slime-xref :sets symbol)) + +(defun slime-who-macroexpands (symbol) + "Show all known expanders of the macro SYMBOL." + (interactive (list (slime-read-symbol-name "Who macroexpands: " t))) + (slime-xref :macroexpands symbol)) + +(defun slime-who-specializes (symbol) + "Show all known methods specialized on class SYMBOL." + (interactive (list (slime-read-symbol-name "Who specializes: " t))) + (slime-xref :specializes symbol)) + +(defun slime-list-callers (symbol-name) + "List the callers of SYMBOL-NAME in a xref window." + (interactive (list (slime-read-symbol-name "List callers: "))) + (slime-xref :callers symbol-name)) + +(defun slime-list-callees (symbol-name) + "List the callees of SYMBOL-NAME in a xref window." + (interactive (list (slime-read-symbol-name "List callees: "))) + (slime-xref :callees symbol-name)) + +;; FIXME: whats the call (slime-postprocess-xrefs result) good for? +(defun slime-xref (type symbol &optional continuation) + "Make an XREF request to Lisp." + (slime-eval-async + `(swank:xref ',type ',symbol) + (slime-rcurry (lambda (result type symbol package cont) + (slime-check-xref-implemented type result) + (let* ((_xrefs (slime-postprocess-xrefs result)) + (file-alist (cadr (slime-analyze-xrefs result)))) + (funcall (or cont 'slime-show-xrefs) + file-alist type symbol package))) + type + symbol + (slime-current-package) + continuation))) + +(defun slime-check-xref-implemented (type xrefs) + (when (eq xrefs :not-implemented) + (error "%s is not implemented yet on %s." + (slime-xref-type type) + (slime-lisp-implementation-name)))) + +(defun slime-xref-type (type) + (format "who-%s" (slime-cl-symbol-name type))) + +(defun slime-xrefs (types symbol &optional continuation) + "Make multiple XREF requests at once." + (slime-eval-async + `(swank:xrefs ',types ',symbol) + #'(lambda (result) + (funcall (or continuation + #'slime-show-xrefs) + (cl-loop for (key . val) in result + collect (cons (slime-xref-type key) val)) + types symbol (slime-current-package))))) + + +;;;;; XREF navigation + +(defun slime-xref-location-at-point () + (save-excursion + ;; When the end of the last line is at (point-max) we can't find + ;; the text property there. Going to bol avoids this problem. + (beginning-of-line 1) + (or (get-text-property (point) 'slime-location) + (error "No reference at point.")))) + +(defun slime-xref-dspec-at-point () + (save-excursion + (beginning-of-line 1) + (with-syntax-table lisp-mode-syntax-table + (forward-sexp) ; skip initial whitespaces + (backward-sexp) + (slime-sexp-at-point)))) + +(defun slime-all-xrefs () + (let ((xrefs nil)) + (save-excursion + (goto-char (point-min)) + (while (zerop (forward-line 1)) + (let ((loc (get-text-property (point) 'slime-location))) + (when loc + (let* ((dspec (slime-xref-dspec-at-point)) + (xref (make-slime-xref :dspec dspec :location loc))) + (push xref xrefs)))))) + (nreverse xrefs))) + +(defun slime-goto-xref () + "Goto the cross-referenced location at point." + (interactive) + (slime-show-xref) + (quit-window)) + +(defun slime-show-xref () + "Display the xref at point in the other window." + (interactive) + (let ((location (slime-xref-location-at-point))) + (slime-show-source-location location t 1))) + +(defun slime-goto-next-xref (&optional backward) + "Goto the next cross-reference location." + (if (not (buffer-live-p slime-xref-last-buffer)) + (error "No XREF buffer alive.") + (cl-destructuring-bind (location pos) + (with-current-buffer slime-xref-last-buffer + (list (slime-search-property 'slime-location backward) + (point))) + (cond ((slime-location-p location) + (slime-pop-to-location location) + ;; We do this here because changing the location can take + ;; a while when Emacs needs to read a file from disk. + (with-current-buffer slime-xref-last-buffer + (goto-char pos) + (slime-highlight-line 0.35))) + ((null location) + (message (if backward "No previous xref" "No next xref."))) + (t ; error location + (slime-goto-next-xref backward)))))) + +(defun slime-goto-previous-xref () + "Goto the previous cross-reference location." + (slime-goto-next-xref t)) + +(defun slime-search-property (prop &optional backward prop-value-fn) + "Search the next text range where PROP is non-nil. +Return the value of PROP. +If BACKWARD is non-nil, search backward. +If PROP-VALUE-FN is non-nil use it to extract PROP's value." + (let ((next-candidate (if backward + #'previous-single-char-property-change + #'next-single-char-property-change)) + (prop-value-fn (or prop-value-fn + (lambda () + (get-text-property (point) prop)))) + (start (point)) + (prop-value)) + (while (progn + (goto-char (funcall next-candidate (point) prop)) + (not (or (setq prop-value (funcall prop-value-fn)) + (eobp) + (bobp))))) + (cond (prop-value) + (t (goto-char start) nil)))) + +(defun slime-next-location () + "Go to the next location, depending on context. +When displaying XREF information, this goes to the next reference." + (interactive) + (when (null slime-next-location-function) + (error "No context for finding locations.")) + (funcall slime-next-location-function)) + +(defun slime-previous-location () + "Go to the previous location, depending on context. +When displaying XREF information, this goes to the previous reference." + (interactive) + (when (null slime-previous-location-function) + (error "No context for finding locations.")) + (funcall slime-previous-location-function)) + +(defun slime-recompile-xref (&optional raw-prefix-arg) + (interactive "P") + (let ((slime-compilation-policy (slime-compute-policy raw-prefix-arg))) + (let ((location (slime-xref-location-at-point)) + (dspec (slime-xref-dspec-at-point))) + (slime-recompile-locations + (list location) + (slime-rcurry #'slime-xref-recompilation-cont + (list dspec) (current-buffer)))))) + +(defun slime-recompile-all-xrefs (&optional raw-prefix-arg) + (interactive "P") + (let ((slime-compilation-policy (slime-compute-policy raw-prefix-arg))) + (let ((dspecs) (locations)) + (dolist (xref (slime-all-xrefs)) + (when (slime-xref-has-location-p xref) + (push (slime-xref.dspec xref) dspecs) + (push (slime-xref.location xref) locations))) + (slime-recompile-locations + locations + (slime-rcurry #'slime-xref-recompilation-cont + dspecs (current-buffer)))))) + +(defun slime-xref-recompilation-cont (results dspecs buffer) + ;; Extreme long-windedness to insert status of recompilation; + ;; sometimes Elisp resembles more of an Ewwlisp. + + ;; FIXME: Should probably throw out the whole recompilation cruft + ;; anyway. -- helmut + ;; TODO: next iteration of fixme cleanup this is going in a contrib -- jt + (with-current-buffer buffer + (slime-compilation-finished (slime-aggregate-compilation-results results)) + (save-excursion + (slime-xref-insert-recompilation-flags + dspecs (cl-loop for r in results collect + (or (slime-compilation-result.successp r) + (and (slime-compilation-result.notes r) + :complained))))))) + +(defun slime-aggregate-compilation-results (results) + `(:compilation-result + ,(cl-reduce #'append (mapcar #'slime-compilation-result.notes results)) + ,(cl-every #'slime-compilation-result.successp results) + ,(cl-reduce #'+ (mapcar #'slime-compilation-result.duration results)))) + +(defun slime-xref-insert-recompilation-flags (dspecs compilation-results) + (let* ((buffer-read-only nil) + (max-column (slime-column-max))) + (goto-char (point-min)) + (cl-loop for dspec in dspecs + for result in compilation-results + do (save-excursion + (cl-loop for dspec2 = (progn (search-forward dspec) + (slime-xref-dspec-at-point)) + until (equal dspec2 dspec)) + (end-of-line) ; skip old status information. + (insert-char ?\ (1+ (- max-column (current-column)))) + (insert (format "[%s]" + (cl-case result + ((t) :success) + ((nil) :failure) + (t result)))))))) + + +;;;; Macroexpansion + +(define-minor-mode slime-macroexpansion-minor-mode + "SLIME mode for macroexpansion" + nil + " Macroexpand" + '(("g" . slime-macroexpand-again))) + +(cl-macrolet ((remap (from to) + `(dolist (mapping + (where-is-internal ,from slime-mode-map)) + (define-key slime-macroexpansion-minor-mode-map + mapping ,to)))) + (remap 'slime-macroexpand-1 'slime-macroexpand-1-inplace) + (remap 'slime-macroexpand-all 'slime-macroexpand-all-inplace) + (remap 'slime-compiler-macroexpand-1 'slime-compiler-macroexpand-1-inplace) + (remap 'slime-expand-1 + 'slime-expand-1-inplace) + (remap 'advertised-undo 'slime-macroexpand-undo) + (remap 'undo 'slime-macroexpand-undo)) + +(defun slime-macroexpand-undo (&optional arg) + (interactive) + ;; Emacs 22.x introduced `undo-only' which + ;; works by binding `undo-no-redo' to t. We do + ;; it this way so we don't break prior Emacs + ;; versions. + (cl-macrolet ((undo-only (arg) `(let ((undo-no-redo t)) (undo ,arg)))) + (let ((inhibit-read-only t)) + (when (fboundp 'slime-remove-edits) + (slime-remove-edits (point-min) (point-max))) + (undo-only arg)))) + +(defvar slime-eval-macroexpand-expression nil + "Specifies the last macroexpansion preformed. +This variable specifies both what was expanded and how.") + +(defun slime-eval-macroexpand (expander &optional string) + (let ((string (or string (slime-sexp-at-point-or-error)))) + (setq slime-eval-macroexpand-expression `(,expander ,string)) + (slime-eval-async slime-eval-macroexpand-expression + #'slime-initialize-macroexpansion-buffer))) + +(defun slime-macroexpand-again () + "Reperform the last macroexpansion." + (interactive) + (slime-eval-async slime-eval-macroexpand-expression + (slime-rcurry #'slime-initialize-macroexpansion-buffer + (current-buffer)))) + +(defun slime-initialize-macroexpansion-buffer (expansion &optional buffer) + (pop-to-buffer (or buffer (slime-create-macroexpansion-buffer))) + (setq buffer-undo-list nil) ; Get rid of undo information from + ; previous expansions. + (let ((inhibit-read-only t) + (buffer-undo-list t)) ; Make the initial insertion not be undoable. + (erase-buffer) + (insert expansion) + (goto-char (point-min)) + (font-lock-fontify-buffer))) + +(defun slime-create-macroexpansion-buffer () + (let ((name (slime-buffer-name :macroexpansion))) + (slime-with-popup-buffer (name :package t :connection t + :mode 'lisp-mode) + (slime-mode 1) + (slime-macroexpansion-minor-mode 1) + (setq font-lock-keywords-case-fold-search t) + (current-buffer)))) + +(defun slime-eval-macroexpand-inplace (expander) + "Substitute the sexp at point with its macroexpansion. + +NB: Does not affect slime-eval-macroexpand-expression" + (interactive) + (let* ((bounds (or (slime-bounds-of-sexp-at-point) + (user-error "No sexp at point")))) + (lexical-let* ((start (copy-marker (car bounds))) + (end (copy-marker (cdr bounds))) + (point (point)) + (package (slime-current-package)) + (buffer (current-buffer))) + (slime-eval-async + `(,expander ,(buffer-substring-no-properties start end)) + (lambda (expansion) + (with-current-buffer buffer + (let ((buffer-read-only nil)) + (when (fboundp 'slime-remove-edits) + (slime-remove-edits (point-min) (point-max))) + (goto-char start) + (delete-region start end) + (slime-insert-indented expansion) + (goto-char point)))))))) + +(defun slime-macroexpand-1 (&optional repeatedly) + "Display the macro expansion of the form starting at point. +The form is expanded with CL:MACROEXPAND-1 or, if a prefix +argument is given, with CL:MACROEXPAND." + (interactive "P") + (slime-eval-macroexpand + (if repeatedly 'swank:swank-macroexpand 'swank:swank-macroexpand-1))) + +(defun slime-macroexpand-1-inplace (&optional repeatedly) + (interactive "P") + (slime-eval-macroexpand-inplace + (if repeatedly 'swank:swank-macroexpand 'swank:swank-macroexpand-1))) + +(defun slime-macroexpand-all () + "Display the recursively macro expanded sexp starting at +point." + (interactive) + (slime-eval-macroexpand 'swank:swank-macroexpand-all)) + +(defun slime-macroexpand-all-inplace () + "Display the recursively macro expanded sexp starting at point." + (interactive) + (slime-eval-macroexpand-inplace 'swank:swank-macroexpand-all)) + +(defun slime-compiler-macroexpand-1 (&optional repeatedly) + "Display the compiler-macro expansion of sexp starting at point." + (interactive "P") + (slime-eval-macroexpand + (if repeatedly + 'swank:swank-compiler-macroexpand + 'swank:swank-compiler-macroexpand-1))) + +(defun slime-compiler-macroexpand-1-inplace (&optional repeatedly) + "Display the compiler-macro expansion of sexp starting at point." + (interactive "P") + (slime-eval-macroexpand-inplace + (if repeatedly + 'swank:swank-compiler-macroexpand + 'swank:swank-compiler-macroexpand-1))) + +(defun slime-expand-1 (&optional repeatedly) + "Display the macro expansion of the form starting at point. +The form is expanded with CL:MACROEXPAND-1 or, if a prefix +argument is given, with CL:MACROEXPAND. If the form denotes a +compiler macro, SWANK/BACKEND:COMPILER-MACROEXPAND or +SWANK/BACKEND:COMPILER-MACROEXPAND-1 are used instead." + (interactive "P") + (slime-eval-macroexpand + (if repeatedly + 'swank:swank-expand + 'swank:swank-expand-1))) + +(defun slime-expand-1-inplace (&optional repeatedly) + "Display the macro expansion of the form at point. +The form is expanded with CL:MACROEXPAND-1 or, if a prefix +argument is given, with CL:MACROEXPAND." + (interactive "P") + (slime-eval-macroexpand-inplace + (if repeatedly + 'swank:swank-expand + 'swank:swank-expand-1))) + +(defun slime-format-string-expand (&optional string) + "Expand the format-string at point and display it." + (interactive (list (or (and (not current-prefix-arg) + (slime-string-at-point)) + (slime-read-from-minibuffer "Expand format: " + (slime-string-at-point))))) + (slime-eval-macroexpand 'swank:swank-format-string-expand string)) + + +;;;; Subprocess control + +(defun slime-interrupt () + "Interrupt Lisp." + (interactive) + (cond ((slime-use-sigint-for-interrupt) (slime-send-sigint)) + (t (slime-dispatch-event `(:emacs-interrupt ,slime-current-thread))))) + +(defun slime-quit () + (error "Not implemented properly. Use `slime-interrupt' instead.")) + +(defun slime-quit-lisp (&optional kill) + "Quit lisp, kill the inferior process and associated buffers." + (interactive "P") + (slime-quit-lisp-internal (slime-connection) 'slime-quit-sentinel kill)) + +(defun slime-quit-lisp-internal (connection sentinel kill) + (let ((slime-dispatching-connection connection)) + (slime-eval-async '(swank:quit-lisp)) + (let* ((process (slime-inferior-process connection))) + (set-process-filter connection nil) + (set-process-sentinel connection sentinel) + (when (and kill process) + (sleep-for 0.2) + (unless (memq (process-status process) '(exit signal)) + (kill-process process)))))) + +(defun slime-quit-sentinel (process _message) + (cl-assert (process-status process) 'closed) + (let* ((inferior (slime-inferior-process process)) + (inferior-buffer (if inferior (process-buffer inferior)))) + (when inferior (delete-process inferior)) + (when inferior-buffer (kill-buffer inferior-buffer)) + (slime-net-close process) + (message "Connection closed."))) + + +;;;; Debugger (SLDB) + +(defvar sldb-hook nil + "Hook run on entry to the debugger.") + +(defcustom sldb-initial-restart-limit 6 + "Maximum number of restarts to display initially." + :group 'slime-debugger + :type 'integer) + + +;;;;; Local variables in the debugger buffer + +;; Small helper. +(defun slime-make-variables-buffer-local (&rest variables) + (mapcar #'make-variable-buffer-local variables)) + +(slime-make-variables-buffer-local + (defvar sldb-condition nil + "A list (DESCRIPTION TYPE) describing the condition being debugged.") + + (defvar sldb-restarts nil + "List of (NAME DESCRIPTION) for each available restart.") + + (defvar sldb-level nil + "Current debug level (recursion depth) displayed in buffer.") + + (defvar sldb-backtrace-start-marker nil + "Marker placed at the first frame of the backtrace.") + + (defvar sldb-restart-list-start-marker nil + "Marker placed at the first restart in the restart list.") + + (defvar sldb-continuations nil + "List of ids for pending continuation.")) + +;;;;; SLDB macros + +;; some macros that we need to define before the first use + +(defmacro sldb-in-face (name string) + "Return STRING propertised with face sldb-NAME-face." + (declare (indent 1)) + (let ((facename (intern (format "sldb-%s-face" (symbol-name name)))) + (var (cl-gensym "string"))) + `(let ((,var ,string)) + (slime-add-face ',facename ,var) + ,var))) + + +;;;;; sldb-mode + +(defvar sldb-mode-syntax-table + (let ((table (copy-syntax-table lisp-mode-syntax-table))) + ;; We give < and > parenthesis syntax, so that #< ... > is treated + ;; as a balanced expression. This enables autodoc-mode to match + ;; # actual arguments in the backtraces with formal + ;; arguments of the function. (For Lisp mode, this is not + ;; desirable, since we do not wish to get a mismatched paren + ;; highlighted everytime we type < or >.) + (modify-syntax-entry ?< "(" table) + (modify-syntax-entry ?> ")" table) + table) + "Syntax table for SLDB mode.") + +(define-derived-mode sldb-mode fundamental-mode "sldb" + "Superior lisp debugger mode. +In addition to ordinary SLIME commands, the following are +available:\\ + +Commands to examine the selected frame: + \\[sldb-toggle-details] - toggle details (local bindings, CATCH tags) + \\[sldb-show-source] - view source for the frame + \\[sldb-eval-in-frame] - eval in frame + \\[sldb-pprint-eval-in-frame] - eval in frame, pretty-print result + \\[sldb-disassemble] - disassemble + \\[sldb-inspect-in-frame] - inspect + +Commands to invoke restarts: + \\[sldb-quit] - quit + \\[sldb-abort] - abort + \\[sldb-continue] - continue + \\[sldb-invoke-restart-0]-\\[sldb-invoke-restart-9] - restart shortcuts + \\[sldb-invoke-restart-by-name] - invoke restart by name + +Commands to navigate frames: + \\[sldb-down] - down + \\[sldb-up] - up + \\[sldb-details-down] - down, with details + \\[sldb-details-up] - up, with details + \\[sldb-cycle] - cycle between restarts & backtrace + \\[sldb-beginning-of-backtrace] - beginning of backtrace + \\[sldb-end-of-backtrace] - end of backtrace + +Miscellaneous commands: + \\[sldb-restart-frame] - restart frame + \\[sldb-return-from-frame] - return from frame + \\[sldb-step] - step + \\[sldb-break-with-default-debugger] - switch to native debugger + \\[sldb-break-with-system-debugger] - switch to system debugger (gdb) + \\[slime-interactive-eval] - eval + \\[sldb-inspect-condition] - inspect signalled condition + +Full list of commands: + +\\{sldb-mode-map}" + (erase-buffer) + (set-syntax-table sldb-mode-syntax-table) + (slime-set-truncate-lines) + ;; Make original slime-connection "sticky" for SLDB commands in this buffer + (setq slime-buffer-connection (slime-connection))) + +(set-keymap-parent sldb-mode-map slime-parent-map) + +(slime-define-keys sldb-mode-map + + ((kbd "RET") 'sldb-default-action) + ("\C-m" 'sldb-default-action) + ([return] 'sldb-default-action) + ([mouse-2] 'sldb-default-action/mouse) + ([follow-link] 'mouse-face) + ("\C-i" 'sldb-cycle) + ("h" 'describe-mode) + ("v" 'sldb-show-source) + ("e" 'sldb-eval-in-frame) + ("d" 'sldb-pprint-eval-in-frame) + ("D" 'sldb-disassemble) + ("i" 'sldb-inspect-in-frame) + ("n" 'sldb-down) + ("p" 'sldb-up) + ("\M-n" 'sldb-details-down) + ("\M-p" 'sldb-details-up) + ("<" 'sldb-beginning-of-backtrace) + (">" 'sldb-end-of-backtrace) + ("t" 'sldb-toggle-details) + ("r" 'sldb-restart-frame) + ("I" 'sldb-invoke-restart-by-name) + ("R" 'sldb-return-from-frame) + ("c" 'sldb-continue) + ("s" 'sldb-step) + ("x" 'sldb-next) + ("o" 'sldb-out) + ("b" 'sldb-break-on-return) + ("a" 'sldb-abort) + ("q" 'sldb-quit) + ("A" 'sldb-break-with-system-debugger) + ("B" 'sldb-break-with-default-debugger) + ("P" 'sldb-print-condition) + ("C" 'sldb-inspect-condition) + (":" 'slime-interactive-eval) + ("\C-c\C-c" 'sldb-recompile-frame-source)) + +;; Keys 0-9 are shortcuts to invoke particular restarts. +(dotimes (number 10) + (let ((fname (intern (format "sldb-invoke-restart-%S" number))) + (docstring (format "Invoke restart numbered %S." number))) + (eval `(defun ,fname () + ,docstring + (interactive) + (sldb-invoke-restart ,number))) + (define-key sldb-mode-map (number-to-string number) fname))) + + +;;;;; SLDB buffer creation & update + +(defun sldb-buffers (&optional connection) + "Return a list of all sldb buffers (belonging to CONNECTION.)" + (if connection + (slime-filter-buffers (lambda () + (and (eq slime-buffer-connection connection) + (eq major-mode 'sldb-mode)))) + (slime-filter-buffers (lambda () (eq major-mode 'sldb-mode))))) + +(defun sldb-find-buffer (thread &optional connection) + (let ((connection (or connection (slime-connection)))) + (cl-find-if (lambda (buffer) + (with-current-buffer buffer + (and (eq slime-buffer-connection connection) + (eq slime-current-thread thread)))) + (sldb-buffers)))) + +(defun sldb-get-default-buffer () + "Get a sldb buffer. +The chosen buffer the default connection's it if exists." + (car (sldb-buffers slime-default-connection))) + +(defun sldb-get-buffer (thread &optional connection) + "Find or create a sldb-buffer for THREAD." + (let ((connection (or connection (slime-connection)))) + (or (sldb-find-buffer thread connection) + (let ((name (format "*sldb %s/%s*" (slime-connection-name) thread))) + (with-current-buffer (generate-new-buffer name) + (setq slime-buffer-connection connection + slime-current-thread thread) + (current-buffer)))))) + +(defun sldb-debugged-continuations (connection) + "Return the all debugged continuations for CONNECTION across SLDB buffers." + (cl-loop for b in (sldb-buffers) + append (with-current-buffer b + (and (eq slime-buffer-connection connection) + sldb-continuations)))) + +(defun sldb--display-buffer-reuse-last-window (buffer _alist) + (let ((window + (get-window-with-predicate (lambda (w) + (window-parameter w 'sldb-last-window))))) + (when (and window + (not (with-current-buffer (window-buffer window) + (derived-mode-p 'sldb-mode)))) + (display-buffer-record-window 'reuse window buffer) + (set-window-buffer window buffer) + window))) + +(defun sldb-display-buffer (buffer) + "Pop to BUFFER reusing the last SLDB window, if any." + (pop-to-buffer buffer '(sldb--display-buffer-reuse-last-window))) + +(defun sldb-setup (thread level condition restarts frames conts) + "Setup a new SLDB buffer. +CONDITION is a string describing the condition to debug. +RESTARTS is a list of strings (NAME DESCRIPTION) for each available restart. +FRAMES is a list (NUMBER DESCRIPTION &optional PLIST) describing the initial +portion of the backtrace. Frames are numbered from 0. +CONTS is a list of pending Emacs continuations." + (with-current-buffer (sldb-get-buffer thread) + (cl-assert (if (equal sldb-level level) + (equal sldb-condition condition) + t) + () "Bug: sldb-level is equal but condition differs\n%s\n%s" + sldb-condition condition) + (unless (equal sldb-level level) + (setq buffer-read-only nil) + (sldb-mode) + (setq slime-current-thread thread) + (setq sldb-level level) + (setq mode-name (format "sldb[%d]" sldb-level)) + (setq sldb-condition condition) + (setq sldb-restarts restarts) + (setq sldb-continuations conts) + (sldb-insert-condition condition) + (insert "\n\n" (sldb-in-face section "Restarts:") "\n") + (setq sldb-restart-list-start-marker (point-marker)) + (sldb-insert-restarts restarts 0 sldb-initial-restart-limit) + (insert "\n" (sldb-in-face section "Backtrace:") "\n") + (setq sldb-backtrace-start-marker (point-marker)) + (save-excursion + (if frames + (sldb-insert-frames (sldb-prune-initial-frames frames) t) + (insert "[No backtrace]"))) + (run-hooks 'sldb-hook) + (set-syntax-table lisp-mode-syntax-table)) + ;; FIXME: remove when dropping Emacs23 support + (let ((saved (selected-window))) + (sldb-display-buffer (current-buffer)) + (set-window-parameter (selected-window) 'sldb-restore saved)) + (unless noninteractive ; needed for tests in batch-mode + (slime--display-region (point-min) (point))) + (setq buffer-read-only t) + (when (and slime-stack-eval-tags + ;; (y-or-n-p "Enter recursive edit? ") + ) + (message "Entering recursive edit..") + (recursive-edit)))) + +(defun sldb-activate (thread level select) + "Display the debugger buffer for THREAD. +If LEVEL isn't the same as in the buffer reinitialize the buffer." + (or (let ((buffer (sldb-find-buffer thread))) + (when buffer + (with-current-buffer buffer + (when (equal sldb-level level) + (when select (pop-to-buffer (current-buffer))) + t)))) + (sldb-reinitialize thread level))) + +(defun sldb-reinitialize (thread level) + (slime-rex (thread level) + ('(swank:debugger-info-for-emacs 0 10) + nil thread) + ((:ok result) + (apply #'sldb-setup thread level result)))) + +(defun sldb--mark-last-window (window) + (dolist (window (window-list)) + (when (window-parameter window 'sldb-last-window) + (set-window-parameter window 'sldb-last-window nil))) + (set-window-parameter (selected-window) 'sldb-last-window t)) + +(defun sldb-exit (thread _level &optional stepping) + "Exit from the debug level LEVEL." + (let ((sldb (sldb-find-buffer thread))) + (when sldb + (with-current-buffer sldb + (cond (stepping + (setq sldb-level nil) + (run-with-timer 0.4 nil 'sldb-close-step-buffer sldb)) + ((not (eq sldb (window-buffer (selected-window)))) + ;; A different window selection means an indirect, + ;; non-interactive exit, we just kill the sldb buffer. + (kill-buffer)) + (t + (sldb--mark-last-window (selected-window)) + ;; An interactive exit should restore configuration per + ;; `quit-window's protocol. FIXME: remove + ;; `previous-window' hack when dropping Emacs23 support + (let ((previous-window (window-parameter (selected-window) + 'sldb-restore))) + (quit-window t) + (if (and (not (>= emacs-major-version 24)) + (window-live-p previous-window)) + (select-window previous-window))))))))) + +(defun sldb-close-step-buffer (buffer) + (when (buffer-live-p buffer) + (with-current-buffer buffer + (when (not sldb-level) + (quit-window t))))) + + +;;;;;; SLDB buffer insertion + +(defun sldb-insert-condition (condition) + "Insert the text for CONDITION. +CONDITION should be a list (MESSAGE TYPE EXTRAS). +EXTRAS is currently used for the stepper." + (cl-destructuring-bind (message type extras) condition + (slime-insert-propertized '(sldb-default-action sldb-inspect-condition) + (sldb-in-face topline message) + "\n" + (sldb-in-face condition type)) + (sldb-dispatch-extras extras))) + +(defvar sldb-extras-hooks) + +(defun sldb-dispatch-extras (extras) + ;; this is (mis-)used for the stepper + (dolist (extra extras) + (slime-dcase extra + ((:show-frame-source n) + (sldb-show-frame-source n)) + (t + (or (run-hook-with-args-until-success 'sldb-extras-hooks extra) + ;;(error "Unhandled extra element:" extra) + ))))) + +(defun sldb-insert-restarts (restarts start count) + "Insert RESTARTS and add the needed text props +RESTARTS should be a list ((NAME DESCRIPTION) ...)." + (let* ((len (length restarts)) + (end (if count (min (+ start count) len) len))) + (cl-loop for (name string) in (cl-subseq restarts start end) + for number from start + do (slime-insert-propertized + `(,@nil restart ,number + sldb-default-action sldb-invoke-restart + mouse-face highlight) + " " (sldb-in-face restart-number (number-to-string number)) + ": [" (sldb-in-face restart-type name) "] " + (sldb-in-face restart string)) + (insert "\n")) + (when (< end len) + (let ((pos (point))) + (slime-insert-propertized + (list 'sldb-default-action + (slime-rcurry #'sldb-insert-more-restarts restarts pos end)) + " --more--\n"))))) + +(defun sldb-insert-more-restarts (restarts position start) + (goto-char position) + (let ((inhibit-read-only t)) + (delete-region position (1+ (line-end-position))) + (sldb-insert-restarts restarts start nil))) + +(defun sldb-frame.string (frame) + (cl-destructuring-bind (_ str &optional _) frame str)) + +(defun sldb-frame.number (frame) + (cl-destructuring-bind (n _ &optional _) frame n)) + +(defun sldb-frame.plist (frame) + (cl-destructuring-bind (_ _ &optional plist) frame plist)) + +(defun sldb-frame-restartable-p (frame) + (and (plist-get (sldb-frame.plist frame) :restartable) t)) + +(defun sldb-prune-initial-frames (frames) + "Return the prefix of FRAMES to initially present to the user. +Regexp heuristics are used to avoid showing SWANK-internal frames." + (let* ((case-fold-search t) + (rx "^\\([() ]\\|lambda\\)*swank\\>")) + (or (cl-loop for frame in frames + until (string-match rx (sldb-frame.string frame)) + collect frame) + frames))) + +(defun sldb-insert-frames (frames more) + "Insert FRAMES into buffer. +If MORE is non-nil, more frames are on the Lisp stack." + (mapc #'sldb-insert-frame frames) + (when more + (slime-insert-propertized + `(,@nil sldb-default-action sldb-fetch-more-frames + sldb-previous-frame-number + ,(sldb-frame.number (cl-first (last frames))) + point-entered sldb-fetch-more-frames + start-open t + face sldb-section-face + mouse-face highlight) + " --more--") + (insert "\n"))) + +(defun sldb-compute-frame-face (frame) + (if (sldb-frame-restartable-p frame) + 'sldb-restartable-frame-line-face + 'sldb-frame-line-face)) + +(defun sldb-insert-frame (frame &optional face) + "Insert FRAME with FACE at point. +If FACE is nil, `sldb-compute-frame-face' is used to determine the face." + (setq face (or face (sldb-compute-frame-face frame))) + (let ((number (sldb-frame.number frame)) + (string (sldb-frame.string frame)) + (props `(frame ,frame sldb-default-action sldb-toggle-details))) + (slime-propertize-region props + (slime-propertize-region '(mouse-face highlight) + (insert " " (sldb-in-face frame-label (format "%2d:" number)) " ") + (slime-insert-indented + (slime-add-face face string))) + (insert "\n")))) + +(defun sldb-fetch-more-frames (&rest _) + "Fetch more backtrace frames. +Called on the `point-entered' text-property hook." + (let ((inhibit-point-motion-hooks t) + (inhibit-read-only t) + (prev (get-text-property (point) 'sldb-previous-frame-number))) + ;; we may be called twice, PREV is nil the second time + (when prev + (let* ((count 40) + (from (1+ prev)) + (to (+ from count)) + (frames (slime-eval `(swank:backtrace ,from ,to))) + (more (slime-length= frames count)) + (pos (point))) + (delete-region (line-beginning-position) (point-max)) + (sldb-insert-frames frames more) + (goto-char pos))))) + + +;;;;;; SLDB examining text props + +(defun sldb-restart-at-point () + (or (get-text-property (point) 'restart) + (error "No restart at point"))) + +(defun sldb-frame-number-at-point () + (let ((frame (get-text-property (point) 'frame))) + (cond (frame (car frame)) + (t (error "No frame at point"))))) + +(defun sldb-var-number-at-point () + (let ((var (get-text-property (point) 'var))) + (cond (var var) + (t (error "No variable at point"))))) + +(defun sldb-previous-frame-number () + (save-excursion + (sldb-backward-frame) + (sldb-frame-number-at-point))) + +(defun sldb-frame-details-visible-p () + (and (get-text-property (point) 'frame) + (get-text-property (point) 'details-visible-p))) + +(defun sldb-frame-region () + (slime-property-bounds 'frame)) + +(defun sldb-forward-frame () + (goto-char (next-single-char-property-change (point) 'frame))) + +(defun sldb-backward-frame () + (when (> (point) sldb-backtrace-start-marker) + (goto-char (previous-single-char-property-change + (if (get-text-property (point) 'frame) + (car (sldb-frame-region)) + (point)) + 'frame + nil sldb-backtrace-start-marker)))) + +(defun sldb-goto-last-frame () + (goto-char (point-max)) + (while (not (get-text-property (point) 'frame)) + (goto-char (previous-single-property-change (point) 'frame)) + ;; Recenter to bottom of the window; -2 to account for the + ;; empty last line displayed in sldb buffers. + (recenter -2))) + +(defun sldb-beginning-of-backtrace () + "Goto the first frame." + (interactive) + (goto-char sldb-backtrace-start-marker)) + + +;;;;;; SLDB recenter & redisplay +;; not sure yet, whether this is a good idea. +;; +;; jt: seconded. Only `sldb-show-frame-details' and +;; `sldb-hide-frame-details' use this. They could avoid it by not +;; removing and reinserting the frame's name line. +(defmacro slime-save-coordinates (origin &rest body) + "Restore line and column relative to ORIGIN, after executing BODY. + +This is useful if BODY deletes and inserts some text but we want to +preserve the current row and column as closely as possible." + (let ((base (make-symbol "base")) + (goal (make-symbol "goal")) + (mark (make-symbol "mark"))) + `(let* ((,base ,origin) + (,goal (slime-coordinates ,base)) + (,mark (point-marker))) + (set-marker-insertion-type ,mark t) + (prog1 (save-excursion ,@body) + (slime-restore-coordinate ,base ,goal ,mark))))) + +(put 'slime-save-coordinates 'lisp-indent-function 1) + +(defun slime-coordinates (origin) + ;; Return a pair (X . Y) for the column and line distance to ORIGIN. + (let ((y (slime-count-lines origin (point))) + (x (save-excursion + (- (current-column) + (progn (goto-char origin) (current-column)))))) + (cons x y))) + +(defun slime-restore-coordinate (base goal limit) + ;; Move point to GOAL. Coordinates are relative to BASE. + ;; Don't move beyond LIMIT. + (save-restriction + (narrow-to-region base limit) + (goto-char (point-min)) + (let ((col (current-column))) + (forward-line (cdr goal)) + (when (and (eobp) (bolp) (not (bobp))) + (backward-char)) + (move-to-column (+ col (car goal)))))) + +(defun slime-count-lines (start end) + "Return the number of lines between START and END. +This is 0 if START and END at the same line." + (- (count-lines start end) + (if (save-excursion (goto-char end) (bolp)) 0 1))) + + +;;;;; SLDB commands + +(defun sldb-default-action () + "Invoke the action at point." + (interactive) + (let ((fn (get-text-property (point) 'sldb-default-action))) + (if fn (funcall fn)))) + +(defun sldb-default-action/mouse (event) + "Invoke the action pointed at by the mouse." + (interactive "e") + (cl-destructuring-bind (_mouse-1 (_w pos &rest ignore)) event + (save-excursion + (goto-char pos) + (let ((fn (get-text-property (point) 'sldb-default-action))) + (if fn (funcall fn)))))) + +(defun sldb-cycle () + "Cycle between restart list and backtrace." + (interactive) + (let ((pt (point))) + (cond ((< pt sldb-restart-list-start-marker) + (goto-char sldb-restart-list-start-marker)) + ((< pt sldb-backtrace-start-marker) + (goto-char sldb-backtrace-start-marker)) + (t + (goto-char sldb-restart-list-start-marker))))) + +(defun sldb-end-of-backtrace () + "Fetch the entire backtrace and go to the last frame." + (interactive) + (sldb-fetch-all-frames) + (sldb-goto-last-frame)) + +(defun sldb-fetch-all-frames () + (let ((inhibit-read-only t) + (inhibit-point-motion-hooks t)) + (sldb-goto-last-frame) + (let ((last (sldb-frame-number-at-point))) + (goto-char (next-single-char-property-change (point) 'frame)) + (delete-region (point) (point-max)) + (save-excursion + (sldb-insert-frames (slime-eval `(swank:backtrace ,(1+ last) nil)) + nil))))) + + +;;;;;; SLDB show source + +(defun sldb-show-source () + "Highlight the frame at point's expression in a source code buffer." + (interactive) + (sldb-show-frame-source (sldb-frame-number-at-point))) + +(defun sldb-show-frame-source (frame-number) + (slime-eval-async + `(swank:frame-source-location ,frame-number) + (lambda (source-location) + (slime-dcase source-location + ((:error message) + (message "%s" message) + (ding)) + (t + (slime-show-source-location source-location t nil)))))) + +(defun slime-show-source-location (source-location + &optional highlight recenter-arg) + "Go to SOURCE-LOCATION and display the buffer in the other window." + (slime-goto-source-location source-location) + ;; show the location, but don't hijack focus. + (slime--display-position (point) t recenter-arg) + (when highlight (slime-highlight-sexp))) + +(defun slime--display-position (pos other-window recenter-arg) + (with-selected-window (display-buffer (current-buffer) other-window) + (goto-char pos) + (recenter recenter-arg))) + +;; Set window-start so that the region from START to END becomes visible. +;; START is inclusive; END is exclusive. +(defun slime--adjust-window-start (start end) + (let* ((last (max start (1- end))) + (window-height (window-text-height)) + (region-height (count-screen-lines start last t))) + ;; if needed, make the region visible + (when (or (not (pos-visible-in-window-p start)) + (not (pos-visible-in-window-p last))) + (let* ((nlines (cond ((or (< start (window-start)) + (>= region-height window-height)) + 0) + (t + (- region-height))))) + (goto-char start) + (recenter nlines))) + (cl-assert (pos-visible-in-window-p start)) + (cl-assert (or (pos-visible-in-window-p last) + (> region-height window-height))) + (cl-assert (pos-visible-in-window-p (1- (window-end nil t)) nil t)))) + +;; move POS to visible region +(defun slime--adjust-window-point (pos) + (cond ((pos-visible-in-window-p pos) + (goto-char pos)) + ((< pos (window-start)) + (goto-char (window-start))) + (t + (goto-char (1- (window-end nil t))) + (move-to-column 0))) + (cl-assert (pos-visible-in-window-p (point) nil t))) + +(defun slime--display-region (start end) + "Make the region from START to END visible. +Minimize point motion." + (cl-assert (<= start end)) + (cl-assert (eq (window-buffer (selected-window)) + (current-buffer))) + (let ((pos (point))) + (slime--adjust-window-start start end) + (slime--adjust-window-point pos))) + +(defun slime-highlight-sexp (&optional start end) + "Highlight the first sexp after point." + (let ((start (or start (point))) + (end (or end (save-excursion (ignore-errors (forward-sexp)) (point))))) + (slime-flash-region start end))) + +(defun slime-highlight-line (&optional timeout) + (slime-flash-region (+ (line-beginning-position) (current-indentation)) + (line-end-position) + timeout)) + + +;;;;;; SLDB toggle details + +(defun sldb-toggle-details (&optional on) + "Toggle display of details for the current frame. +The details include local variable bindings and CATCH-tags." + (interactive) + (cl-assert (sldb-frame-number-at-point)) + (let ((inhibit-read-only t) + (inhibit-point-motion-hooks t)) + (if (or on (not (sldb-frame-details-visible-p))) + (sldb-show-frame-details) + (sldb-hide-frame-details)))) + +(defun sldb-show-frame-details () + ;; fetch and display info about local variables and catch tags + (cl-destructuring-bind (start end frame locals catches) (sldb-frame-details) + (slime-save-coordinates start + (delete-region start end) + (slime-propertize-region `(frame ,frame details-visible-p t) + (sldb-insert-frame frame (if (sldb-frame-restartable-p frame) + 'sldb-restartable-frame-line-face + ;; FIXME: can we somehow merge the two? + 'sldb-detailed-frame-line-face)) + (let ((indent1 " ") + (indent2 " ")) + (insert indent1 (sldb-in-face section + (if locals "Locals:" "[No Locals]")) "\n") + (sldb-insert-locals locals indent2 frame) + (when catches + (insert indent1 (sldb-in-face section "Catch-tags:") "\n") + (dolist (tag catches) + (slime-propertize-region `(catch-tag ,tag) + (insert indent2 (sldb-in-face catch-tag (format "%s" tag)) + "\n")))) + (setq end (point))))) + (slime--display-region (point) end))) + +(defun sldb-frame-details () + ;; Return a list (START END FRAME LOCALS CATCHES) for frame at point. + (let* ((frame (get-text-property (point) 'frame)) + (num (car frame))) + (cl-destructuring-bind (start end) (sldb-frame-region) + (cl-list* start end frame + (slime-eval `(swank:frame-locals-and-catch-tags ,num)))))) + +(defvar sldb-insert-frame-variable-value-function + 'sldb-insert-frame-variable-value) + +(defun sldb-insert-locals (vars prefix frame) + "Insert VARS and add PREFIX at the beginning of each inserted line. +VAR should be a plist with the keys :name, :id, and :value." + (cl-loop for i from 0 + for var in vars do + (cl-destructuring-bind (&key name id value) var + (slime-propertize-region + (list 'sldb-default-action 'sldb-inspect-var 'var i) + (insert prefix + (sldb-in-face local-name + (concat name (if (zerop id) "" (format "#%d" id)))) + " = ") + (funcall sldb-insert-frame-variable-value-function + value frame i) + (insert "\n"))))) + +(defun sldb-insert-frame-variable-value (value _frame _index) + (insert (sldb-in-face local-value value))) + +(defun sldb-hide-frame-details () + ;; delete locals and catch tags, but keep the function name and args. + (cl-destructuring-bind (start end) (sldb-frame-region) + (let ((frame (get-text-property (point) 'frame))) + (slime-save-coordinates start + (delete-region start end) + (slime-propertize-region '(details-visible-p nil) + (sldb-insert-frame frame)))))) + +(defun sldb-disassemble () + "Disassemble the code for the current frame." + (interactive) + (let ((frame (sldb-frame-number-at-point))) + (slime-eval-async `(swank:sldb-disassemble ,frame) + (lambda (result) + (slime-show-description result nil))))) + + +;;;;;; SLDB eval and inspect + +(defun sldb-eval-in-frame (frame string package) + "Prompt for an expression and evaluate it in the selected frame." + (interactive (sldb-read-form-for-frame "Eval in frame (%s)> ")) + (slime-eval-async `(swank:eval-string-in-frame ,string ,frame ,package) + (if current-prefix-arg + 'slime-write-string + 'slime-display-eval-result))) + +(defun sldb-pprint-eval-in-frame (frame string package) + "Prompt for an expression, evaluate in selected frame, pretty-print result." + (interactive (sldb-read-form-for-frame "Eval in frame (%s)> ")) + (slime-eval-async + `(swank:pprint-eval-string-in-frame ,string ,frame ,package) + (lambda (result) + (slime-show-description result nil)))) + +(defun sldb-read-form-for-frame (fstring) + (let* ((frame (sldb-frame-number-at-point)) + (pkg (slime-eval `(swank:frame-package-name ,frame)))) + (list frame + (let ((slime-buffer-package pkg)) + (slime-read-from-minibuffer (format fstring pkg))) + pkg))) + +(defun sldb-inspect-in-frame (string) + "Prompt for an expression and inspect it in the selected frame." + (interactive (list (slime-read-from-minibuffer + "Inspect in frame (evaluated): " + (slime-sexp-at-point)))) + (let ((number (sldb-frame-number-at-point))) + (slime-eval-async `(swank:inspect-in-frame ,string ,number) + 'slime-open-inspector))) + +(defun sldb-inspect-var () + (let ((frame (sldb-frame-number-at-point)) + (var (sldb-var-number-at-point))) + (slime-eval-async `(swank:inspect-frame-var ,frame ,var) + 'slime-open-inspector))) + +(defun sldb-inspect-condition () + "Inspect the current debugger condition." + (interactive) + (slime-eval-async '(swank:inspect-current-condition) + 'slime-open-inspector)) + +(defun sldb-print-condition () + (interactive) + (slime-eval-describe `(swank:sdlb-print-condition))) + + +;;;;;; SLDB movement + +(defun sldb-down () + "Select next frame." + (interactive) + (sldb-forward-frame)) + +(defun sldb-up () + "Select previous frame." + (interactive) + (sldb-backward-frame) + (when (= (point) sldb-backtrace-start-marker) + (recenter (1+ (count-lines (point-min) (point)))))) + +(defun sldb-sugar-move (move-fn) + (let ((inhibit-read-only t)) + (when (sldb-frame-details-visible-p) (sldb-hide-frame-details)) + (funcall move-fn) + (sldb-show-source) + (sldb-toggle-details t))) + +(defun sldb-details-up () + "Select previous frame and show details." + (interactive) + (sldb-sugar-move 'sldb-up)) + +(defun sldb-details-down () + "Select next frame and show details." + (interactive) + (sldb-sugar-move 'sldb-down)) + + +;;;;;; SLDB restarts + +(defun sldb-quit () + "Quit to toplevel." + (interactive) + (cl-assert sldb-restarts () "sldb-quit called outside of sldb buffer") + (slime-rex () ('(swank:throw-to-toplevel)) + ((:ok x) (error "sldb-quit returned [%s]" x)) + ((:abort _)))) + +(defun sldb-continue () + "Invoke the \"continue\" restart." + (interactive) + (cl-assert sldb-restarts () "sldb-continue called outside of sldb buffer") + (slime-rex () + ('(swank:sldb-continue)) + ((:ok _) + (message "No restart named continue") + (ding)) + ((:abort _)))) + +(defun sldb-abort () + "Invoke the \"abort\" restart." + (interactive) + (slime-eval-async '(swank:sldb-abort) + (lambda (v) (message "Restart returned: %S" v)))) + +(defun sldb-invoke-restart (&optional number) + "Invoke a restart. +Optional NUMBER (index into `sldb-restarts') specifies the +restart to invoke, otherwise use the restart at point." + (interactive) + (let ((restart (or number (sldb-restart-at-point)))) + (slime-rex () + ((list 'swank:invoke-nth-restart-for-emacs sldb-level restart)) + ((:ok value) (message "Restart returned: %s" value)) + ((:abort _))))) + +(defun sldb-invoke-restart-by-name (restart-name) + (interactive (list (let ((completion-ignore-case t)) + (completing-read "Restart: " sldb-restarts nil t + "" + 'sldb-invoke-restart-by-name)))) + (sldb-invoke-restart (cl-position restart-name sldb-restarts + :test 'string= :key 'first))) + +(defun sldb-break-with-default-debugger (&optional dont-unwind) + "Enter default debugger." + (interactive "P") + (slime-rex () + ((list 'swank:sldb-break-with-default-debugger + (not (not dont-unwind))) + nil slime-current-thread) + ((:abort _)))) + +(defun sldb-break-with-system-debugger (&optional lightweight) + "Enter system debugger (gdb)." + (interactive "P") + (slime-attach-gdb slime-buffer-connection lightweight)) + +(defun slime-attach-gdb (connection &optional lightweight) + "Run `gud-gdb'on the connection with PID `pid'. + +If `lightweight' is given, do not send any request to the +inferior Lisp (e.g. to obtain default gdb config) but only +operate from the Emacs side; intended for cases where the Lisp is +truly screwed up." + (interactive + (list (slime-read-connection "Attach gdb to: " (slime-connection)) "P")) + (let ((pid (slime-pid connection)) + (file (slime-lisp-implementation-program connection)) + (commands (unless lightweight + (let ((slime-dispatching-connection connection)) + (slime-eval `(swank:gdb-initial-commands)))))) + (gud-gdb (format "gdb -p %d %s" pid (or file ""))) + (with-current-buffer gud-comint-buffer + (dolist (cmd commands) + ;; First wait until gdb was initialized, then wait until current + ;; command was processed. + (while (not (looking-back comint-prompt-regexp nil)) + (sit-for 0.01)) + ;; We do not use `gud-call' because we want the initial commands + ;; to be displayed by the user so he knows what he's got. + (insert cmd) + (comint-send-input))))) + +(defun slime-read-connection (prompt &optional initial-value) + "Read a connection from the minibuffer. +Return the net process, or nil." + (cl-assert (memq initial-value slime-net-processes)) + (let* ((to-string (lambda (p) + (format "%s (pid %d)" + (slime-connection-name p) (slime-pid p)))) + (candidates (mapcar (lambda (p) (cons (funcall to-string p) p)) + slime-net-processes))) + (cdr (assoc (completing-read prompt candidates + nil t (funcall to-string initial-value)) + candidates)))) + +(defun sldb-step () + "Step to next basic-block boundary." + (interactive) + (let ((frame (sldb-frame-number-at-point))) + (slime-eval-async `(swank:sldb-step ,frame)))) + +(defun sldb-next () + "Step over call." + (interactive) + (let ((frame (sldb-frame-number-at-point))) + (slime-eval-async `(swank:sldb-next ,frame)))) + +(defun sldb-out () + "Resume stepping after returning from this function." + (interactive) + (let ((frame (sldb-frame-number-at-point))) + (slime-eval-async `(swank:sldb-out ,frame)))) + +(defun sldb-break-on-return () + "Set a breakpoint at the current frame. +The debugger is entered when the frame exits." + (interactive) + (let ((frame (sldb-frame-number-at-point))) + (slime-eval-async `(swank:sldb-break-on-return ,frame) + (lambda (msg) (message "%s" msg))))) + +(defun sldb-break (name) + "Set a breakpoint at the start of the function NAME." + (interactive (list (slime-read-symbol-name "Function: " t))) + (slime-eval-async `(swank:sldb-break ,name) + (lambda (msg) (message "%s" msg)))) + +(defun sldb-return-from-frame (string) + "Reads an expression in the minibuffer and causes the function to +return that value, evaluated in the context of the frame." + (interactive (list (slime-read-from-minibuffer "Return from frame: "))) + (let* ((number (sldb-frame-number-at-point))) + (slime-rex () + ((list 'swank:sldb-return-from-frame number string)) + ((:ok value) (message "%s" value)) + ((:abort _))))) + +(defun sldb-restart-frame () + "Causes the frame to restart execution with the same arguments as it +was called originally." + (interactive) + (let* ((number (sldb-frame-number-at-point))) + (slime-rex () + ((list 'swank:restart-frame number)) + ((:ok value) (message "%s" value)) + ((:abort _))))) + +(defun slime-toggle-break-on-signals () + "Toggle the value of *break-on-signals*." + (interactive) + (slime-eval-async `(swank:toggle-break-on-signals) + (lambda (msg) (message "%s" msg)))) + + +;;;;;; SLDB recompilation commands + +(defun sldb-recompile-frame-source (&optional raw-prefix-arg) + (interactive "P") + (slime-eval-async + `(swank:frame-source-location ,(sldb-frame-number-at-point)) + (lexical-let ((policy (slime-compute-policy raw-prefix-arg))) + (lambda (source-location) + (slime-dcase source-location + ((:error message) + (message "%s" message) + (ding)) + (t + (let ((slime-compilation-policy policy)) + (slime-recompile-location source-location)))))))) + + +;;;; Thread control panel + +(defvar slime-threads-buffer-name (slime-buffer-name :threads)) +(defvar slime-threads-buffer-timer nil) + +(defcustom slime-threads-update-interval nil + "Interval at which the list of threads will be updated." + :type '(choice + (number :value 0.5) + (const nil)) + :group 'slime-ui) + +(defun slime-list-threads () + "Display a list of threads." + (interactive) + (let ((name slime-threads-buffer-name)) + (slime-with-popup-buffer (name :connection t + :mode 'slime-thread-control-mode) + (slime-update-threads-buffer) + (goto-char (point-min)) + (when slime-threads-update-interval + (when slime-threads-buffer-timer + (cancel-timer slime-threads-buffer-timer)) + (setq slime-threads-buffer-timer + (run-with-timer + slime-threads-update-interval + slime-threads-update-interval + 'slime-update-threads-buffer)))))) + +(defun slime-quit-threads-buffer () + (when slime-threads-buffer-timer + (cancel-timer slime-threads-buffer-timer)) + (quit-window t) + (slime-eval-async `(swank:quit-thread-browser))) + +(defun slime-update-threads-buffer () + (interactive) + (with-current-buffer slime-threads-buffer-name + (slime-eval-async '(swank:list-threads) + 'slime-display-threads))) + +(defun slime-move-point (position) + "Move point in the current buffer and in the window the buffer is displayed." + (let ((window (get-buffer-window (current-buffer) t))) + (goto-char position) + (when window + (set-window-point window position)))) + +(defun slime-display-threads (threads) + (with-current-buffer slime-threads-buffer-name + (let* ((inhibit-read-only t) + (old-thread-id (get-text-property (point) 'thread-id)) + (old-line (line-number-at-pos)) + (old-column (current-column))) + (erase-buffer) + (slime-insert-threads threads) + (let ((new-position (cl-position old-thread-id (cdr threads) + :key #'car :test #'equal))) + (goto-char (point-min)) + (forward-line (or new-position (1- old-line))) + (move-to-column old-column) + (slime-move-point (point)))))) + +(defun slime-transpose-lists (list-of-lists) + (let ((ncols (length (car list-of-lists)))) + (cl-loop for col-index below ncols + collect (cl-loop for row in list-of-lists + collect (elt row col-index))))) + +(defun slime-insert-table-row (line line-props col-props col-widths) + (slime-propertize-region line-props + (cl-loop for string in line + for col-prop in col-props + for width in col-widths do + (slime-insert-propertized col-prop string) + (insert-char ?\ (- width (length string)))))) + +(defun slime-insert-table (rows header row-properties column-properties) + "Insert a \"table\" so that the columns are nicely aligned." + (let* ((ncols (length header)) + (lines (cons header rows)) + (widths (cl-loop for columns in (slime-transpose-lists lines) + collect (1+ (cl-loop for cell in columns + maximize (length cell))))) + (header-line (with-temp-buffer + (slime-insert-table-row + header nil (make-list ncols nil) widths) + (buffer-string)))) + (cond ((boundp 'header-line-format) + (setq header-line-format header-line)) + (t (insert header-line "\n"))) + (cl-loop for line in rows for line-props in row-properties do + (slime-insert-table-row line line-props column-properties widths) + (insert "\n")))) + +(defvar slime-threads-table-properties + '(nil (face bold))) + +(defun slime-insert-threads (threads) + (let* ((labels (car threads)) + (threads (cdr threads)) + (header (cl-loop for label in labels collect + (capitalize (substring (symbol-name label) 1)))) + (rows (cl-loop for thread in threads collect + (cl-loop for prop in thread collect + (format "%s" prop)))) + (line-props (cl-loop for (id) in threads for i from 0 + collect `(thread-index ,i thread-id ,id))) + (col-props (cl-loop for nil in labels for i from 0 collect + (nth i slime-threads-table-properties)))) + (slime-insert-table rows header line-props col-props))) + + +;;;;; Major mode + +(define-derived-mode slime-thread-control-mode fundamental-mode + "Threads" + "SLIME Thread Control Panel Mode. + +\\{slime-thread-control-mode-map} +\\{slime-popup-buffer-mode-map}" + (when slime-truncate-lines + (set (make-local-variable 'truncate-lines) t)) + (setq buffer-undo-list t)) + +(slime-define-keys slime-thread-control-mode-map + ("a" 'slime-thread-attach) + ("d" 'slime-thread-debug) + ("g" 'slime-update-threads-buffer) + ("k" 'slime-thread-kill) + ("q" 'slime-quit-threads-buffer)) + +(defun slime-thread-kill () + (interactive) + (slime-eval `(cl:mapc 'swank:kill-nth-thread + ',(slime-get-properties 'thread-index))) + (call-interactively 'slime-update-threads-buffer)) + +(defun slime-get-region-properties (prop start end) + (cl-loop for position = (if (get-text-property start prop) + start + (next-single-property-change start prop)) + then (next-single-property-change position prop) + while (<= position end) + collect (get-text-property position prop))) + +(defun slime-get-properties (prop) + (if (use-region-p) + (slime-get-region-properties prop + (region-beginning) + (region-end)) + (let ((value (get-text-property (point) prop))) + (when value + (list value))))) + +(defun slime-thread-attach () + (interactive) + (let ((id (get-text-property (point) 'thread-index)) + (file (slime-swank-port-file))) + (slime-eval-async `(swank:start-swank-server-in-thread ,id ,file))) + (slime-read-port-and-connect nil)) + +(defun slime-thread-debug () + (interactive) + (let ((id (get-text-property (point) 'thread-index))) + (slime-eval-async `(swank:debug-nth-thread ,id)))) + + +;;;;; Connection listing + +(define-derived-mode slime-connection-list-mode fundamental-mode + "Slime-Connections" + "SLIME Connection List Mode. + +\\{slime-connection-list-mode-map} +\\{slime-popup-buffer-mode-map}" + (when slime-truncate-lines + (set (make-local-variable 'truncate-lines) t))) + +(slime-define-keys slime-connection-list-mode-map + ("d" 'slime-connection-list-make-default) + ("g" 'slime-update-connection-list) + ((kbd "C-k") 'slime-quit-connection-at-point) + ("R" 'slime-restart-connection-at-point)) + +(defun slime-connection-at-point () + (or (get-text-property (point) 'slime-connection) + (error "No connection at point"))) + +(defun slime-quit-connection-at-point (connection) + (interactive (list (slime-connection-at-point))) + (let ((slime-dispatching-connection connection) + (end (time-add (current-time) (seconds-to-time 3)))) + (slime-quit-lisp t) + (while (memq connection slime-net-processes) + (when (time-less-p end (current-time)) + (message "Quit timeout expired. Disconnecting.") + (delete-process connection)) + (sit-for 0 100))) + (slime-update-connection-list)) + +(defun slime-restart-connection-at-point (connection) + (interactive (list (slime-connection-at-point))) + (let ((slime-dispatching-connection connection)) + (slime-restart-inferior-lisp))) + +(defun slime-connection-list-make-default () + "Make the connection at point the default connection." + (interactive) + (slime-select-connection (slime-connection-at-point)) + (slime-update-connection-list)) + +(defvar slime-connections-buffer-name (slime-buffer-name :connections)) + +(defun slime-list-connections () + "Display a list of all connections." + (interactive) + (slime-with-popup-buffer (slime-connections-buffer-name + :mode 'slime-connection-list-mode) + (slime-draw-connection-list))) + +(defun slime-update-connection-list () + "Display a list of all connections." + (interactive) + (let ((pos (point)) + (inhibit-read-only t)) + (erase-buffer) + (slime-draw-connection-list) + (goto-char pos))) + +(defun slime-draw-connection-list () + (let ((default-pos nil) + (default slime-default-connection) + (fstring "%s%2s %-10s %-17s %-7s %-s\n")) + (insert (format fstring " " "Nr" "Name" "Port" "Pid" "Type") + (format fstring " " "--" "----" "----" "---" "----")) + (dolist (p (reverse slime-net-processes)) + (when (eq default p) (setf default-pos (point))) + (slime-insert-propertized + (list 'slime-connection p) + (format fstring + (if (eq default p) "*" " ") + (slime-connection-number p) + (slime-connection-name p) + (or (process-id p) (process-contact p)) + (slime-pid p) + (slime-lisp-implementation-type p)))) + (when default-pos + (goto-char default-pos)))) + + +;;;; Inspector + +(defgroup slime-inspector nil + "Inspector faces." + :prefix "slime-inspector-" + :group 'slime) + +(defface slime-inspector-topline-face + '((t ())) + "Face for top line describing object." + :group 'slime-inspector) + +(defface slime-inspector-label-face + '((t (:inherit font-lock-constant-face))) + "Face for labels in the inspector." + :group 'slime-inspector) + +(defface slime-inspector-value-face + '((t (:inherit font-lock-builtin-face))) + "Face for things which can themselves be inspected." + :group 'slime-inspector) + +(defface slime-inspector-action-face + '((t (:inherit font-lock-warning-face))) + "Face for labels of inspector actions." + :group 'slime-inspector) + +(defface slime-inspector-type-face + '((t (:inherit font-lock-type-face))) + "Face for type description in inspector." + :group 'slime-inspector) + +(defvar slime-inspector-mark-stack '()) + +(defun slime-inspect (string) + "Eval an expression and inspect the result." + (interactive + (list (slime-read-from-minibuffer "Inspect value (evaluated): " + (slime-sexp-at-point)))) + (slime-eval-async `(swank:init-inspector ,string) 'slime-open-inspector)) + +(define-derived-mode slime-inspector-mode fundamental-mode + "Slime-Inspector" + " +\\{slime-inspector-mode-map} +\\{slime-popup-buffer-mode-map}" + (set-syntax-table lisp-mode-syntax-table) + (slime-set-truncate-lines) + (setq buffer-read-only t)) + +(defun slime-inspector-buffer () + (or (get-buffer (slime-buffer-name :inspector)) + (slime-with-popup-buffer ((slime-buffer-name :inspector) + :mode 'slime-inspector-mode) + (setq slime-inspector-mark-stack '()) + (buffer-disable-undo) + (current-buffer)))) + +(defmacro slime-inspector-fontify (face string) + `(slime-add-face ',(intern (format "slime-inspector-%s-face" face)) ,string)) + +(defvar slime-inspector-insert-ispec-function 'slime-inspector-insert-ispec) + +(defun slime-open-inspector (inspected-parts &optional point hook) + "Display INSPECTED-PARTS in a new inspector window. +Optionally set point to POINT. If HOOK is provided, it is added to local +KILL-BUFFER hooks for the inspector buffer." + (with-current-buffer (slime-inspector-buffer) + (when hook + (add-hook 'kill-buffer-hook hook t t)) + (setq slime-buffer-connection (slime-current-connection)) + (let ((inhibit-read-only t)) + (erase-buffer) + (pop-to-buffer (current-buffer)) + (cl-destructuring-bind (&key id title content) inspected-parts + (cl-macrolet ((fontify (face string) + `(slime-inspector-fontify ,face ,string))) + (slime-propertize-region + (list 'slime-part-number id + 'mouse-face 'highlight + 'face 'slime-inspector-value-face) + (insert title)) + (while (eq (char-before) ?\n) + (backward-delete-char 1)) + (insert "\n" (fontify label "--------------------") "\n") + (save-excursion + (slime-inspector-insert-content content)) + (when point + (cl-check-type point cons) + (ignore-errors + (goto-char (point-min)) + (forward-line (1- (car point))) + (move-to-column (cdr point))))))))) + +(defvar slime-inspector-limit 500) + +(defun slime-inspector-insert-content (content) + (slime-inspector-fetch-chunk + content nil + (lambda (chunk) + (let ((inhibit-read-only t)) + (slime-inspector-insert-chunk chunk t t))))) + +(defun slime-inspector-insert-chunk (chunk prev next) + "Insert CHUNK at point. +If PREV resp. NEXT are true insert more-buttons as needed." + (cl-destructuring-bind (ispecs len start end) chunk + (when (and prev (> start 0)) + (slime-inspector-insert-more-button start t)) + (mapc slime-inspector-insert-ispec-function ispecs) + (when (and next (< end len)) + (slime-inspector-insert-more-button end nil)))) + +(defun slime-inspector-insert-ispec (ispec) + (if (stringp ispec) + (insert ispec) + (slime-dcase ispec + ((:value string id) + (slime-propertize-region + (list 'slime-part-number id + 'mouse-face 'highlight + 'face 'slime-inspector-value-face) + (insert string))) + ((:label string) + (insert (slime-inspector-fontify label string))) + ((:action string id) + (slime-insert-propertized (list 'slime-action-number id + 'mouse-face 'highlight + 'face 'slime-inspector-action-face) + string))))) + +(defun slime-inspector-position () + "Return a pair (Y-POSITION X-POSITION) representing the +position of point in the current buffer." + ;; We make sure we return absolute coordinates even if the user has + ;; narrowed the buffer. + ;; FIXME: why would somebody narrow the buffer? + (save-restriction + (widen) + (cons (line-number-at-pos) + (current-column)))) + +(defun slime-inspector-property-at-point () + (let* ((properties '(slime-part-number slime-range-button + slime-action-number)) + (find-property + (lambda (point) + (cl-loop for property in properties + for value = (get-text-property point property) + when value + return (list property value))))) + (or (funcall find-property (point)) + (funcall find-property (1- (point)))))) + +(defun slime-inspector-operate-on-point () + "Invoke the command for the text at point. +1. If point is on a value then recursivly call the inspector on +that value. +2. If point is on an action then call that action. +3. If point is on a range-button fetch and insert the range." + (interactive) + (let ((opener (lexical-let ((point (slime-inspector-position))) + (lambda (parts) + (when parts + (slime-open-inspector parts point))))) + (new-opener (lambda (parts) + (when parts + (slime-open-inspector parts))))) + (cl-destructuring-bind (&optional property value) + (slime-inspector-property-at-point) + (cl-case property + (slime-part-number + (slime-eval-async `(swank:inspect-nth-part ,value) + new-opener) + (push (slime-inspector-position) slime-inspector-mark-stack)) + (slime-range-button + (slime-inspector-fetch-more value)) + (slime-action-number + (slime-eval-async `(swank:inspector-call-nth-action ,value) + opener)) + (t (error "No object at point")))))) + +(defun slime-inspector-operate-on-click (event) + "Move to events' position and operate the part." + (interactive "@e") + (let ((point (posn-point (event-end event)))) + (cond ((and point + (or (get-text-property point 'slime-part-number) + (get-text-property point 'slime-range-button) + (get-text-property point 'slime-action-number))) + (goto-char point) + (slime-inspector-operate-on-point)) + (t + (error "No clickable part here"))))) + +(defun slime-inspector-pop () + "Reinspect the previous object." + (interactive) + (slime-eval-async + `(swank:inspector-pop) + (lambda (result) + (cond (result + (slime-open-inspector result (pop slime-inspector-mark-stack))) + (t + (message "No previous object") + (ding)))))) + +(defun slime-inspector-next () + "Inspect the next object in the history." + (interactive) + (let ((result (slime-eval `(swank:inspector-next)))) + (cond (result + (push (slime-inspector-position) slime-inspector-mark-stack) + (slime-open-inspector result)) + (t (message "No next object") + (ding))))) + +(defun slime-inspector-quit () + "Quit the inspector and kill the buffer." + (interactive) + (slime-eval-async `(swank:quit-inspector)) + (quit-window t)) + +;; FIXME: first return value is just point. +;; FIXME: could probably use slime-search-property. +(defun slime-find-inspectable-object (direction limit) + "Find the next/previous inspectable object. +DIRECTION can be either 'next or 'prev. +LIMIT is the maximum or minimum position in the current buffer. + +Return a list of two values: If an object could be found, the +starting position of the found object and T is returned; +otherwise LIMIT and NIL is returned." + (let ((finder (cl-ecase direction + (next 'next-single-property-change) + (prev 'previous-single-property-change)))) + (let ((prop nil) (curpos (point))) + (while (and (not prop) (not (= curpos limit))) + (let ((newpos (funcall finder curpos 'slime-part-number nil limit))) + (setq prop (get-text-property newpos 'slime-part-number)) + (setq curpos newpos))) + (list curpos (and prop t))))) + +(defun slime-inspector-next-inspectable-object (arg) + "Move point to the next inspectable object. +With optional ARG, move across that many objects. +If ARG is negative, move backwards." + (interactive "p") + (let ((maxpos (point-max)) (minpos (point-min)) + (previously-wrapped-p nil)) + ;; Forward. + (while (> arg 0) + (cl-destructuring-bind (pos foundp) + (slime-find-inspectable-object 'next maxpos) + (if foundp + (progn (goto-char pos) (setq arg (1- arg)) + (setq previously-wrapped-p nil)) + (if (not previously-wrapped-p) ; cycle detection + (progn (goto-char minpos) (setq previously-wrapped-p t)) + (error "No inspectable objects"))))) + ;; Backward. + (while (< arg 0) + (cl-destructuring-bind (pos foundp) + (slime-find-inspectable-object 'prev minpos) + ;; SLIME-OPEN-INSPECTOR inserts the title of an inspector page + ;; as a presentation at the beginning of the buffer; skip + ;; that. (Notice how this problem can not arise in ``Forward.'') + (if (and foundp (/= pos minpos)) + (progn (goto-char pos) (setq arg (1+ arg)) + (setq previously-wrapped-p nil)) + (if (not previously-wrapped-p) ; cycle detection + (progn (goto-char maxpos) (setq previously-wrapped-p t)) + (error "No inspectable objects"))))))) + +(defun slime-inspector-previous-inspectable-object (arg) + "Move point to the previous inspectable object. +With optional ARG, move across that many objects. +If ARG is negative, move forwards." + (interactive "p") + (slime-inspector-next-inspectable-object (- arg))) + +(defun slime-inspector-describe () + (interactive) + (slime-eval-describe `(swank:describe-inspectee))) + +(defun slime-inspector-pprint (part) + (interactive (list (or (get-text-property (point) 'slime-part-number) + (error "No part at point")))) + (slime-eval-describe `(swank:pprint-inspector-part ,part))) + +(defun slime-inspector-eval (string) + "Eval an expression in the context of the inspected object. +The `*' variable will be bound to the inspected object." + (interactive (list (slime-read-from-minibuffer "Inspector eval: "))) + (slime-eval-with-transcript `(swank:inspector-eval ,string))) + +(defun slime-inspector-history () + "Show the previously inspected objects." + (interactive) + (slime-eval-describe `(swank:inspector-history))) + +(defun slime-inspector-show-source (part) + (interactive (list (or (get-text-property (point) 'slime-part-number) + (error "No part at point")))) + (slime-eval-async + `(swank:find-source-location-for-emacs '(:inspector ,part)) + #'slime-show-source-location)) + +(defun slime-inspector-reinspect () + (interactive) + (slime-eval-async `(swank:inspector-reinspect) + (lexical-let ((point (slime-inspector-position))) + (lambda (parts) + (slime-open-inspector parts point))))) + +(defun slime-inspector-toggle-verbose () + (interactive) + (slime-eval-async `(swank:inspector-toggle-verbose) + (lexical-let ((point (slime-inspector-position))) + (lambda (parts) + (slime-open-inspector parts point))))) + +(defun slime-inspector-insert-more-button (index previous) + (slime-insert-propertized + (list 'slime-range-button (list index previous) + 'mouse-face 'highlight + 'face 'slime-inspector-action-face) + (if previous " [--more--]\n" " [--more--]"))) + +(defun slime-inspector-fetch-all () + "Fetch all inspector contents and go to the end." + (interactive) + (goto-char (1- (point-max))) + (let ((button (get-text-property (point) 'slime-range-button))) + (when button + (let (slime-inspector-limit) + (slime-inspector-fetch-more button))))) + +(defun slime-inspector-fetch-more (button) + (cl-destructuring-bind (index prev) button + (slime-inspector-fetch-chunk + (list '() (1+ index) index index) prev + (slime-rcurry + (lambda (chunk prev) + (let ((inhibit-read-only t)) + (apply #'delete-region (slime-property-bounds 'slime-range-button)) + (slime-inspector-insert-chunk chunk prev (not prev)))) + prev)))) + +(defun slime-inspector-fetch-chunk (chunk prev cont) + (slime-inspector-fetch chunk slime-inspector-limit prev cont)) + +(defun slime-inspector-fetch (chunk limit prev cont) + (cl-destructuring-bind (from to) + (slime-inspector-next-range chunk limit prev) + (cond ((and from to) + (slime-eval-async + `(swank:inspector-range ,from ,to) + (slime-rcurry (lambda (chunk2 chunk1 limit prev cont) + (slime-inspector-fetch + (slime-inspector-join-chunks chunk1 chunk2) + limit prev cont)) + chunk limit prev cont))) + (t (funcall cont chunk))))) + +(defun slime-inspector-next-range (chunk limit prev) + (cl-destructuring-bind (_ len start end) chunk + (let ((count (- end start))) + (cond ((and prev (< 0 start) (or (not limit) (< count limit))) + (list (if limit (max (- end limit) 0) 0) start)) + ((and (not prev) (< end len) (or (not limit) (< count limit))) + (list end (if limit (+ start limit) most-positive-fixnum))) + (t '(nil nil)))))) + +(defun slime-inspector-join-chunks (chunk1 chunk2) + (cl-destructuring-bind (i1 _l1 s1 e1) chunk1 + (cl-destructuring-bind (i2 l2 s2 e2) chunk2 + (cond ((= e1 s2) + (list (append i1 i2) l2 s1 e2)) + ((= e2 s1) + (list (append i2 i1) l2 s2 e1)) + (t (error "Invalid chunks")))))) + +(set-keymap-parent slime-inspector-mode-map slime-parent-map) + +(slime-define-keys slime-inspector-mode-map + ([return] 'slime-inspector-operate-on-point) + ("\C-m" 'slime-inspector-operate-on-point) + ([mouse-1] 'slime-inspector-operate-on-click) + ([mouse-2] 'slime-inspector-operate-on-click) + ([mouse-6] 'slime-inspector-pop) + ([mouse-7] 'slime-inspector-next) + ("l" 'slime-inspector-pop) + ("n" 'slime-inspector-next) + (" " 'slime-inspector-next) + ("d" 'slime-inspector-describe) + ("p" 'slime-inspector-pprint) + ("e" 'slime-inspector-eval) + ("h" 'slime-inspector-history) + ("g" 'slime-inspector-reinspect) + ("v" 'slime-inspector-toggle-verbose) + ("\C-i" 'slime-inspector-next-inspectable-object) + ([(shift tab)] + 'slime-inspector-previous-inspectable-object) ; Emacs translates S-TAB + ([backtab] 'slime-inspector-previous-inspectable-object) ; to BACKTAB on X. + ("." 'slime-inspector-show-source) + (">" 'slime-inspector-fetch-all) + ("q" 'slime-inspector-quit)) + + +;;;; Buffer selector + +(defvar slime-selector-methods nil + "List of buffer-selection methods for the `slime-select' command. +Each element is a list (KEY DESCRIPTION FUNCTION). +DESCRIPTION is a one-line description of what the key selects.") + +(defvar slime-selector-other-window nil + "If non-nil use switch-to-buffer-other-window.") + +(defun slime-selector (&optional other-window) + "Select a new buffer by type, indicated by a single character. +The user is prompted for a single character indicating the method by +which to choose a new buffer. The `?' character describes the +available methods. + +See `def-slime-selector-method' for defining new methods." + (interactive) + (message "Select [%s]: " + (apply #'string (mapcar #'car slime-selector-methods))) + (let* ((slime-selector-other-window other-window) + (sequence (save-window-excursion + (select-window (minibuffer-window)) + (key-description (read-key-sequence nil)))) + (ch (cond ((equal sequence "C-g") + (keyboard-quit)) + ((equal sequence "TAB") + ?i) + ((= (length sequence) 1) + (elt sequence 0)) + ((= (length sequence) 3) + (elt sequence 2)))) + (method (cl-find ch slime-selector-methods :key #'car))) + (cond (method + (funcall (cl-third method))) + (t + (message "No method for character: ?\\%c" ch) + (ding) + (sleep-for 1) + (discard-input) + (slime-selector))))) + +(defmacro def-slime-selector-method (key description &rest body) + "Define a new `slime-select' buffer selection method. + +KEY is the key the user will enter to choose this method. + +DESCRIPTION is a one-line sentence describing how the method +selects a buffer. + +BODY is a series of forms which are evaluated when the selector +is chosen. The returned buffer is selected with +switch-to-buffer." + (let ((method `(lambda () + (let ((buffer (progn ,@body))) + (cond ((not (get-buffer buffer)) + (message "No such buffer: %S" buffer) + (ding)) + ((get-buffer-window buffer) + (select-window (get-buffer-window buffer))) + (slime-selector-other-window + (switch-to-buffer-other-window buffer)) + (t + (switch-to-buffer buffer))))))) + `(setq slime-selector-methods + (cl-sort (cons (list ,key ,description ,method) + (cl-remove ,key slime-selector-methods :key #'car)) + #'< :key #'car)))) + +(def-slime-selector-method ?? "Selector help buffer." + (ignore-errors (kill-buffer "*Select Help*")) + (with-current-buffer (get-buffer-create "*Select Help*") + (insert "Select Methods:\n\n") + (cl-loop for (key line nil) in slime-selector-methods + do (insert (format "%c:\t%s\n" key line))) + (goto-char (point-min)) + (help-mode) + (display-buffer (current-buffer) t)) + (slime-selector) + (current-buffer)) + +(cl-pushnew (list ?4 "Select in other window" (lambda () (slime-selector t))) + slime-selector-methods :key #'car) + +(def-slime-selector-method ?q "Abort." + (top-level)) + +(def-slime-selector-method ?i + "*inferior-lisp* buffer." + (cond ((and (slime-connected-p) (slime-process)) + (process-buffer (slime-process))) + (t + "*inferior-lisp*"))) + +(def-slime-selector-method ?v + "*slime-events* buffer." + slime-event-buffer-name) + +(def-slime-selector-method ?l + "most recently visited lisp-mode buffer." + (slime-recently-visited-buffer 'lisp-mode)) + +(def-slime-selector-method ?d + "*sldb* buffer for the current connection." + (or (sldb-get-default-buffer) + (error "No debugger buffer"))) + +(def-slime-selector-method ?e + "most recently visited emacs-lisp-mode buffer." + (slime-recently-visited-buffer 'emacs-lisp-mode)) + +(def-slime-selector-method ?c + "SLIME connections buffer." + (slime-list-connections) + slime-connections-buffer-name) + +(def-slime-selector-method ?n + "Cycle to the next Lisp connection." + (slime-next-connection) + (concat "*slime-repl " + (slime-connection-name (slime-current-connection)) + "*")) + +(def-slime-selector-method ?p + "Cycle to the previous Lisp connection." + (slime-prev-connection) + (concat "*slime-repl " + (slime-connection-name (slime-current-connection)) + "*")) + +(def-slime-selector-method ?t + "SLIME threads buffer." + (slime-list-threads) + slime-threads-buffer-name) + +(defun slime-recently-visited-buffer (mode) + "Return the most recently visited buffer whose major-mode is MODE. +Only considers buffers that are not already visible." + (cl-loop for buffer in (buffer-list) + when (and (with-current-buffer buffer (eq major-mode mode)) + (not (string-match "^ " (buffer-name buffer))) + (null (get-buffer-window buffer 'visible))) + return buffer + finally (error "Can't find unshown buffer in %S" mode))) + + +;;;; Indentation + +(defun slime-update-indentation () + "Update indentation for all macros defined in the Lisp system." + (interactive) + (slime-eval-async '(swank:update-indentation-information))) + +(defvar slime-indentation-update-hooks) + +(defun slime-intern-indentation-spec (spec) + (cond ((consp spec) + (cons (slime-intern-indentation-spec (car spec)) + (slime-intern-indentation-spec (cdr spec)))) + ((stringp spec) + (intern spec)) + (t + spec))) + +;; FIXME: restore the old version without per-package +;; stuff. slime-indentation.el should be able tho disable the simple +;; version if needed. +(defun slime-handle-indentation-update (alist) + "Update Lisp indent information. + +ALIST is a list of (SYMBOL-NAME . INDENT-SPEC) of proposed indentation +settings for `common-lisp-indent-function'. The appropriate property +is setup, unless the user already set one explicitly." + (dolist (info alist) + (let ((symbol (intern (car info))) + (indent (slime-intern-indentation-spec (cl-second info))) + (packages (cl-third info))) + (if (and (boundp 'common-lisp-system-indentation) + (fboundp 'slime-update-system-indentation)) + ;; A table provided by slime-cl-indent.el. + (funcall #'slime-update-system-indentation symbol indent packages) + ;; Does the symbol have an indentation value that we set? + (when (equal (get symbol 'common-lisp-indent-function) + (get symbol 'slime-indent)) + (put symbol 'common-lisp-indent-function indent) + (put symbol 'slime-indent indent))) + (run-hook-with-args 'slime-indentation-update-hooks + symbol indent packages)))) + + +;;;; Contrib modules + +(defun slime-require (module) + (cl-pushnew module slime-required-modules) + (when (slime-connected-p) + (slime-load-contribs))) + +(defun slime-load-contribs () + (let ((needed (cl-remove-if (lambda (s) + (member (cl-subseq (symbol-name s) 1) + (mapcar #'downcase + (slime-lisp-modules)))) + slime-required-modules))) + (when needed + ;; No asynchronous request because with :SPAWN that could result + ;; in the attempt to load modules concurrently which may not be + ;; supported by the host Lisp. + (setf (slime-lisp-modules) + (slime-eval `(swank:swank-require ',needed)))))) + +(cl-defstruct slime-contrib + name + slime-dependencies + swank-dependencies + enable + disable + authors + license) + +(defun slime-contrib--enable-fun (name) + (intern (concat (symbol-name name) "-init"))) + +(defun slime-contrib--disable-fun (name) + (intern (concat (symbol-name name) "-unload"))) + +(defmacro define-slime-contrib (name _docstring &rest clauses) + (declare (indent 1)) + (cl-destructuring-bind (&key slime-dependencies + swank-dependencies + on-load + on-unload + authors + license) + (cl-loop for (key . value) in clauses append `(,key ,value)) + `(progn + ,@(mapcar (lambda (d) `(require ',d)) slime-dependencies) + (defun ,(slime-contrib--enable-fun name) () + (mapc #'funcall ',(mapcar + #'slime-contrib--enable-fun + slime-dependencies)) + (mapc #'slime-require ',swank-dependencies) + ,@on-load) + (defun ,(slime-contrib--disable-fun name) () + ,@on-unload + (mapc #'funcall ',(mapcar + #'slime-contrib--disable-fun + slime-dependencies))) + (put 'slime-contribs ',name + (make-slime-contrib + :name ',name :authors ',authors :license ',license + :slime-dependencies ',slime-dependencies + :swank-dependencies ',swank-dependencies + :enable ',(slime-contrib--enable-fun name) + :disable ',(slime-contrib--disable-fun name)))))) + +(defun slime-all-contribs () + (cl-loop for (nil val) on (symbol-plist 'slime-contribs) by #'cddr + when (slime-contrib-p val) + collect val)) + +(defun slime-contrib-all-dependencies (contrib) + "List all contribs recursively needed by CONTRIB, including self." + (cons contrib + (cl-mapcan #'slime-contrib-all-dependencies + (slime-contrib-slime-dependencies + (slime-find-contrib contrib))))) + +(defun slime-find-contrib (name) + (get 'slime-contribs name)) + +(defun slime-read-contrib-name () + (let ((names (cl-loop for c in (slime-all-contribs) collect + (symbol-name (slime-contrib-name c))))) + (intern (completing-read "Contrib: " names nil t)))) + +(defun slime-enable-contrib (name) + (interactive (list (slime-read-contrib-name))) + (let ((c (or (slime-find-contrib name) + (error "Unknown contrib: %S" name)))) + (funcall (slime-contrib-enable c)))) + +(defun slime-disable-contrib (name) + (interactive (list (slime-read-contrib-name))) + (let ((c (or (slime-find-contrib name) + (error "Unknown contrib: %S" name)))) + (funcall (slime-contrib-disable c)))) + + +;;;;; Pull-down menu + +(defvar slime-easy-menu + (let ((C '(slime-connected-p))) + `("SLIME" + [ "Edit Definition..." slime-edit-definition ,C ] + [ "Return From Definition" slime-pop-find-definition-stack ,C ] + [ "Complete Symbol" completion-at-point ,C ] + "--" + ("Evaluation" + [ "Eval Defun" slime-eval-defun ,C ] + [ "Eval Last Expression" slime-eval-last-expression ,C ] + [ "Eval And Pretty-Print" slime-pprint-eval-last-expression ,C ] + [ "Eval Region" slime-eval-region ,C ] + [ "Eval Region And Pretty-Print" slime-pprint-eval-region ,C ] + [ "Interactive Eval..." slime-interactive-eval ,C ] + [ "Edit Lisp Value..." slime-edit-value ,C ] + [ "Call Defun" slime-call-defun ,C ]) + ("Debugging" + [ "Macroexpand Once..." slime-macroexpand-1 ,C ] + [ "Macroexpand All..." slime-macroexpand-all ,C ] + [ "Create Trace Buffer" slime-redirect-trace-output ,C ] + [ "Toggle Trace..." slime-toggle-trace-fdefinition ,C ] + [ "Untrace All" slime-untrace-all ,C] + [ "Disassemble..." slime-disassemble-symbol ,C ] + [ "Inspect..." slime-inspect ,C ]) + ("Compilation" + [ "Compile Defun" slime-compile-defun ,C ] + [ "Compile/Load File" slime-compile-and-load-file ,C ] + [ "Compile File" slime-compile-file ,C ] + [ "Compile Region" slime-compile-region ,C ] + "--" + [ "Next Note" slime-next-note t ] + [ "Previous Note" slime-previous-note t ] + [ "Remove Notes" slime-remove-notes t ] + [ "List Notes" slime-list-compiler-notes ,C ]) + ("Cross Reference" + [ "Who Calls..." slime-who-calls ,C ] + [ "Who References... " slime-who-references ,C ] + [ "Who Sets..." slime-who-sets ,C ] + [ "Who Binds..." slime-who-binds ,C ] + [ "Who Macroexpands..." slime-who-macroexpands ,C ] + [ "Who Specializes..." slime-who-specializes ,C ] + [ "List Callers..." slime-list-callers ,C ] + [ "List Callees..." slime-list-callees ,C ] + [ "Next Location" slime-next-location t ]) + ("Editing" + [ "Check Parens" check-parens t] + [ "Update Indentation" slime-update-indentation ,C] + [ "Select Buffer" slime-selector t]) + ("Profiling" + [ "Toggle Profiling..." slime-toggle-profile-fdefinition ,C ] + [ "Profile Package" slime-profile-package ,C] + [ "Profile by Substring" slime-profile-by-substring ,C ] + [ "Unprofile All" slime-unprofile-all ,C ] + [ "Show Profiled" slime-profiled-functions ,C ] + "--" + [ "Report" slime-profile-report ,C ] + [ "Reset Counters" slime-profile-reset ,C ]) + ("Documentation" + [ "Describe Symbol..." slime-describe-symbol ,C ] + [ "Lookup Documentation..." slime-documentation-lookup t ] + [ "Apropos..." slime-apropos ,C ] + [ "Apropos all..." slime-apropos-all ,C ] + [ "Apropos Package..." slime-apropos-package ,C ] + [ "Hyperspec..." slime-hyperspec-lookup t ]) + "--" + [ "Interrupt Command" slime-interrupt ,C ] + [ "Abort Async. Command" slime-quit ,C ] + [ "Sync Package & Directory" slime-sync-package-and-default-directory ,C] + ))) + +(defvar slime-sldb-easy-menu + (let ((C '(slime-connected-p))) + `("SLDB" + [ "Next Frame" sldb-down t ] + [ "Previous Frame" sldb-up t ] + [ "Toggle Frame Details" sldb-toggle-details t ] + [ "Next Frame (Details)" sldb-details-down t ] + [ "Previous Frame (Details)" sldb-details-up t ] + "--" + [ "Eval Expression..." slime-interactive-eval ,C ] + [ "Eval in Frame..." sldb-eval-in-frame ,C ] + [ "Eval in Frame (pretty print)..." sldb-pprint-eval-in-frame ,C ] + [ "Inspect In Frame..." sldb-inspect-in-frame ,C ] + [ "Inspect Condition Object" sldb-inspect-condition ,C ] + "--" + [ "Restart Frame" sldb-restart-frame ,C ] + [ "Return from Frame..." sldb-return-from-frame ,C ] + ("Invoke Restart" + [ "Continue" sldb-continue ,C ] + [ "Abort" sldb-abort ,C ] + [ "Step" sldb-step ,C ] + [ "Step next" sldb-next ,C ] + [ "Step out" sldb-out ,C ] + ) + "--" + [ "Quit (throw)" sldb-quit ,C ] + [ "Break With Default Debugger" sldb-break-with-default-debugger ,C ]))) + +(easy-menu-define menubar-slime slime-mode-map "SLIME" slime-easy-menu) + +(defun slime-add-easy-menu () + (easy-menu-add slime-easy-menu 'slime-mode-map)) + +(add-hook 'slime-mode-hook 'slime-add-easy-menu) + +(defun slime-sldb-add-easy-menu () + (easy-menu-define menubar-slime-sldb + sldb-mode-map "SLDB" slime-sldb-easy-menu) + (easy-menu-add slime-sldb-easy-menu 'sldb-mode-map)) + +(add-hook 'sldb-mode-hook 'slime-sldb-add-easy-menu) + + +;;;; Cheat Sheet + +(defvar + slime-cheat-sheet-table + '((:title + "Editing lisp code" + :map slime-mode-map + :bindings ((slime-eval-defun "Evaluate current top level form") + (slime-compile-defun "Compile current top level form") + (slime-interactive-eval "Prompt for form and eval it") + (slime-compile-and-load-file "Compile and load current file") + (slime-sync-package-and-default-directory + "Synch default package and directory with current buffer") + (slime-next-note "Next compiler note") + (slime-previous-note "Previous compiler note") + (slime-remove-notes "Remove notes") + slime-documentation-lookup)) + (:title "Completion" + :map slime-mode-map + :bindings (slime-indent-and-complete-symbol + slime-fuzzy-complete-symbol)) + (:title + "Within SLDB buffers" + :map sldb-mode-map + :bindings ((sldb-default-action "Do 'whatever' with thing at point") + (sldb-toggle-details "Toggle frame details visualization") + (sldb-quit "Quit to REPL") + (sldb-abort "Invoke ABORT restart") + (sldb-continue "Invoke CONTINUE restart (if available)") + (sldb-show-source "Jump to frame's source code") + (sldb-eval-in-frame "Evaluate in frame at point") + (sldb-inspect-in-frame + "Evaluate in frame at point and inspect result"))) + (:title + "Within the Inspector" + :map slime-inspector-mode-map + :bindings ((slime-inspector-next-inspectable-object + "Jump to next inspectable object") + (slime-inspector-operate-on-point + "Inspect object or execute action at point") + (slime-inspector-reinspect "Reinspect current object") + (slime-inspector-pop "Return to previous object") + ;;(slime-inspector-copy-down "Send object at point to REPL") + (slime-inspector-toggle-verbose "Toggle verbose mode") + (slime-inspector-quit "Quit"))) + (:title + "Finding Definitions" + :map slime-mode-map + :bindings (slime-edit-definition + slime-pop-find-definition-stack)))) + +(defun slime-cheat-sheet () + (interactive) + (switch-to-buffer-other-frame + (get-buffer-create (slime-buffer-name :cheat-sheet))) + (setq buffer-read-only nil) + (delete-region (point-min) (point-max)) + (goto-char (point-min)) + (insert + "SLIME: The Superior Lisp Interaction Mode for Emacs (minor-mode).\n\n") + (dolist (mode slime-cheat-sheet-table) + (let ((title (cl-getf mode :title)) + (mode-map (cl-getf mode :map)) + (mode-keys (cl-getf mode :bindings))) + (insert title) + (insert ":\n") + (insert (make-string (1+ (length title)) ?-)) + (insert "\n") + (let ((keys '()) + (descriptions '())) + (dolist (func mode-keys) + ;; func is eithor the function name or a list (NAME DESCRIPTION) + (push (if (symbolp func) + (prin1-to-string func) + (cl-second func)) + descriptions) + (let ((all-bindings (where-is-internal (if (symbolp func) + func + (cl-first func)) + (symbol-value mode-map))) + (key-bindings '())) + (dolist (binding all-bindings) + (when (and (vectorp binding) + (integerp (aref binding 0))) + (push binding key-bindings))) + (push (mapconcat 'key-description key-bindings " or ") keys))) + (cl-loop with desc-length = (apply 'max (mapcar 'length descriptions)) + for key in (nreverse keys) + for desc in (nreverse descriptions) + do (insert desc) + do (insert (make-string (- desc-length (length desc)) ? )) + do (insert " => ") + do (insert (if (string= "" key) + "" + key)) + do (insert "\n") + finally do (insert "\n"))))) + (setq buffer-read-only t) + (goto-char (point-min))) + + +;;;; Utilities (no not Paul Graham style) + +;; XXX: unused function +(defun slime-intersperse (element list) + "Intersperse ELEMENT between each element of LIST." + (if (null list) + '() + (cons (car list) + (cl-mapcan (lambda (x) (list element x)) (cdr list))))) + +;;; FIXME: this looks almost slime `slime-alistify', perhaps the two +;;; functions can be merged. +(defun slime-group-similar (similar-p list) + "Return the list of lists of 'similar' adjacent elements of LIST. +The function SIMILAR-P is used to test for similarity. +The order of the input list is preserved." + (if (null list) + nil + (let ((accumulator (list (list (car list))))) + (dolist (x (cdr list)) + (if (funcall similar-p x (caar accumulator)) + (push x (car accumulator)) + (push (list x) accumulator))) + (reverse (mapcar #'reverse accumulator))))) + +(defun slime-alistify (list key test) + "Partition the elements of LIST into an alist. +KEY extracts the key from an element and TEST is used to compare +keys." + (let ((alist '())) + (dolist (e list) + (let* ((k (funcall key e)) + (probe (cl-assoc k alist :test test))) + (if probe + (push e (cdr probe)) + (push (cons k (list e)) alist)))) + ;; Put them back in order. + (cl-loop for (key . value) in (reverse alist) + collect (cons key (reverse value))))) + +;;;;; Misc. + +(defun slime-length= (seq n) + "Return (= (length SEQ) N)." + (cl-etypecase seq + (list + (cond ((zerop n) (null seq)) + ((let ((tail (nthcdr (1- n) seq))) + (and tail (null (cdr tail))))))) + (sequence + (= (length seq) n)))) + +(defun slime-length> (seq n) + "Return (> (length SEQ) N)." + (cl-etypecase seq + (list (nthcdr n seq)) + (sequence (> (length seq) n)))) + +(defun slime-trim-whitespace (str) + (let ((start (cl-position-if-not (lambda (x) + (memq x '(?\t ?\n ?\s ?\r))) + str)) + + (end (cl-position-if-not (lambda (x) + (memq x '(?\t ?\n ?\s ?\r))) + str + :from-end t))) + (if start + (substring str start (1+ end)) + ""))) + +;;;;; Buffer related + +(defun slime-buffer-narrowed-p (&optional buffer) + "Returns T if BUFFER (or the current buffer respectively) is narrowed." + (with-current-buffer (or buffer (current-buffer)) + (let ((beg (point-min)) + (end (point-max)) + (total (buffer-size))) + (or (/= beg 1) (/= end (1+ total)))))) + +(defun slime-column-max () + (save-excursion + (goto-char (point-min)) + (cl-loop for column = (prog2 (end-of-line) (current-column) (forward-line)) + until (= (point) (point-max)) + maximizing column))) + +;;;;; CL symbols vs. Elisp symbols. + +(defun slime-cl-symbol-name (symbol) + (let ((n (if (stringp symbol) symbol (symbol-name symbol)))) + (if (string-match ":\\([^:]*\\)$" n) + (let ((symbol-part (match-string 1 n))) + (if (string-match "^|\\(.*\\)|$" symbol-part) + (match-string 1 symbol-part) + symbol-part)) + n))) + +(defun slime-cl-symbol-package (symbol &optional default) + (let ((n (if (stringp symbol) symbol (symbol-name symbol)))) + (if (string-match "^\\([^:]*\\):" n) + (match-string 1 n) + default))) + +(defun slime-qualify-cl-symbol-name (symbol-or-name) + "Return a package-qualified string for SYMBOL-OR-NAME. +If SYMBOL-OR-NAME doesn't already have a package prefix the +current package is used." + (let ((s (if (stringp symbol-or-name) + symbol-or-name + (symbol-name symbol-or-name)))) + (if (slime-cl-symbol-package s) + s + (format "%s::%s" + (let* ((package (slime-current-package))) + ;; package is a string like ":cl-user" + ;; or "CL-USER", or "\"CL-USER\"". + (if package + (slime-pretty-package-name package) + "CL-USER")) + (slime-cl-symbol-name s))))) + +;;;;; Moving, CL idiosyncracies aware (reader conditionals &c.) + +(defmacro slime-point-moves-p (&rest body) + "Execute BODY and return true if the current buffer's point moved." + (declare (indent 0)) + (let ((pointvar (cl-gensym "point-"))) + `(let ((,pointvar (point))) + (save-current-buffer ,@body) + (/= ,pointvar (point))))) + +(defun slime-forward-sexp (&optional count) + "Like `forward-sexp', but understands reader-conditionals (#- and #+), +and skips comments." + (dotimes (_i (or count 1)) + (slime-forward-cruft) + (forward-sexp))) + +(defconst slime-reader-conditionals-regexp + ;; #!+, #!- are SBCL specific reader-conditional syntax. + ;; We need this for the source files of SBCL itself. + (regexp-opt '("#+" "#-" "#!+" "#!-"))) + +(defun slime-forward-reader-conditional () + "Move past any reader conditional (#+ or #-) at point." + (when (looking-at slime-reader-conditionals-regexp) + (goto-char (match-end 0)) + (let* ((plus-conditional-p (eq (char-before) ?+)) + (result (slime-eval-feature-expression + (condition-case e + (read (current-buffer)) + (invalid-read-syntax + (signal 'slime-unknown-feature-expression (cdr e))))))) + (unless (if plus-conditional-p result (not result)) + ;; skip this sexp + (slime-forward-sexp))))) + +(defun slime-forward-cruft () + "Move forward over whitespace, comments, reader conditionals." + (while (slime-point-moves-p (skip-chars-forward " \t\n") + (forward-comment (buffer-size)) + (inline (slime-forward-reader-conditional))))) + +(defun slime-keywordify (symbol) + "Make a keyword out of the symbol SYMBOL." + (let ((name (downcase (symbol-name symbol)))) + (intern (if (eq ?: (aref name 0)) + name + (concat ":" name))))) + +(put 'slime-incorrect-feature-expression + 'error-conditions '(slime-incorrect-feature-expression error)) + +(put 'slime-unknown-feature-expression + 'error-conditions '(slime-unknown-feature-expression + slime-incorrect-feature-expression + error)) + +;; FIXME: let it crash +;; FIXME: the length=1 constraint is bogus +(defun slime-eval-feature-expression (e) + "Interpret a reader conditional expression." + (cond ((symbolp e) + (memq (slime-keywordify e) (slime-lisp-features))) + ((and (consp e) (symbolp (car e))) + (funcall (let ((head (slime-keywordify (car e)))) + (cl-case head + (:and #'cl-every) + (:or #'cl-some) + (:not + (lexical-let ((feature-expression e)) + (lambda (f l) + (cond + ((slime-length= l 0) t) + ((slime-length= l 1) (not (apply f l))) + (t (signal 'slime-incorrect-feature-expression + feature-expression)))))) + (t (signal 'slime-unknown-feature-expression head)))) + #'slime-eval-feature-expression + (cdr e))) + (t (signal 'slime-incorrect-feature-expression e)))) + +;;;;; Extracting Lisp forms from the buffer or user + +(defun slime-defun-at-point () + "Return the text of the defun at point." + (apply #'buffer-substring-no-properties + (slime-region-for-defun-at-point))) + +(defun slime-region-for-defun-at-point () + "Return the start and end position of defun at point." + (save-excursion + (save-match-data + (end-of-defun) + (let ((end (point))) + (beginning-of-defun) + (list (point) end))))) + +(defun slime-beginning-of-symbol () + "Move to the beginning of the CL-style symbol at point." + (while (re-search-backward "\\(\\sw\\|\\s_\\|\\s\\.\\|\\s\\\\|[#@|]\\)\\=" + (when (> (point) 2000) (- (point) 2000)) + t)) + (re-search-forward "\\=#[-+.<|]" nil t) + (when (and (looking-at "@") (eq (char-before) ?\,)) + (forward-char))) + +(defun slime-end-of-symbol () + "Move to the end of the CL-style symbol at point." + (re-search-forward "\\=\\(\\sw\\|\\s_\\|\\s\\.\\|#:\\|[@|]\\)*")) + +(put 'slime-symbol 'end-op 'slime-end-of-symbol) +(put 'slime-symbol 'beginning-op 'slime-beginning-of-symbol) + +(defun slime-symbol-start-pos () + "Return the starting position of the symbol under point. +The result is unspecified if there isn't a symbol under the point." + (save-excursion (slime-beginning-of-symbol) (point))) + +(defun slime-symbol-end-pos () + (save-excursion (slime-end-of-symbol) (point))) + +(defun slime-bounds-of-symbol-at-point () + "Return the bounds of the symbol around point. +The returned bounds are either nil or non-empty." + (let ((bounds (bounds-of-thing-at-point 'slime-symbol))) + (if (and bounds + (< (car bounds) + (cdr bounds))) + bounds))) + +(defun slime-symbol-at-point () + "Return the name of the symbol at point, otherwise nil." + ;; (thing-at-point 'symbol) returns "" in empty buffers + (let ((bounds (slime-bounds-of-symbol-at-point))) + (if bounds + (buffer-substring-no-properties (car bounds) + (cdr bounds))))) + +(defun slime-bounds-of-sexp-at-point () + "Return the bounds sexp at point as a pair (or nil)." + (or (slime-bounds-of-symbol-at-point) + (and (equal (char-after) ?\() + (member (char-before) '(?\' ?\, ?\@)) + ;; hide stuff before ( to avoid quirks with '( etc. + (save-restriction + (narrow-to-region (point) (point-max)) + (bounds-of-thing-at-point 'sexp))) + (bounds-of-thing-at-point 'sexp))) + +(defun slime-sexp-at-point () + "Return the sexp at point as a string, otherwise nil." + (let ((bounds (slime-bounds-of-sexp-at-point))) + (if bounds + (buffer-substring-no-properties (car bounds) + (cdr bounds))))) + +(defun slime-sexp-at-point-or-error () + "Return the sexp at point as a string, othwise signal an error." + (or (slime-sexp-at-point) (user-error "No expression at point"))) + +(defun slime-string-at-point () + "Returns the string at point as a string, otherwise nil." + (let ((sexp (slime-sexp-at-point))) + (if (and sexp + (eql (char-syntax (aref sexp 0)) ?\")) + sexp + nil))) + +(defun slime-string-at-point-or-error () + "Return the sexp at point as a string, othwise signal an error." + (or (slime-string-at-point) (error "No string at point."))) + +(defun slime-input-complete-p (start end) + "Return t if the region from START to END contains a complete sexp." + (save-excursion + (goto-char start) + (cond ((looking-at "\\s *['`#]?[(\"]") + (ignore-errors + (save-restriction + (narrow-to-region start end) + ;; Keep stepping over blanks and sexps until the end of + ;; buffer is reached or an error occurs. Tolerate extra + ;; close parens. + (cl-loop do (skip-chars-forward " \t\r\n)") + until (eobp) + do (forward-sexp)) + t))) + (t t)))) + + +;;;; slime.el in pretty colors + +(cl-loop for sym in (list 'slime-def-connection-var + 'slime-define-channel-type + 'slime-define-channel-method + 'define-slime-contrib + 'slime-defun-if-undefined + 'slime-defmacro-if-undefined) + for regexp = (format "(\\(%S\\)\\s +\\(\\(\\w\\|\\s_\\)+\\)" + sym) + do (font-lock-add-keywords + 'emacs-lisp-mode + `((,regexp (1 font-lock-keyword-face) + (2 font-lock-variable-name-face))))) + +;;;; target manipulation (used by slime-presentations, slime-media, +;;;; slime-repl and slime-buffer-streams, at +;;;; least) + +(defvar slime-output-target-to-marker + (make-hash-table) + "Map from TARGET ids to Emacs markers. +The markers indicate where output should be inserted.") + +(defun slime-output-target-marker (target) + "Return the marker where output for TARGET should be inserted." + (gethash target slime-output-target-to-marker)) + +(defun slime-emit-to-target (string target) + "Insert STRING at target TARGET. +See `slime-output-target-to-marker'." + (let* ((marker (slime-output-target-marker target)) + (buffer (and marker (marker-buffer marker)))) + (when buffer + (with-current-buffer buffer + (save-excursion + ;; Insert STRING at MARKER, then move MARKER behind + ;; the insertion. + (goto-char marker) + (insert-before-markers string) + (set-marker marker (point))))))) + +;;;; Finishing up + +(eval-when-compile + (require 'bytecomp)) + +(defun slime--byte-compile (symbol) + (require 'bytecomp) ;; tricky interaction between autoload and let. + (let ((byte-compile-warnings '())) + (byte-compile symbol))) + +(defun slime--compile-hotspots () + (mapc (lambda (sym) + (cond ((fboundp sym) + (unless (byte-code-function-p (symbol-function sym)) + (slime--byte-compile sym))) + (t (error "%S is not fbound" sym)))) + '(slime-alistify + slime-log-event + slime-events-buffer + slime-process-available-input + slime-dispatch-event + slime-net-filter + slime-net-have-input-p + slime-net-decode-length + slime-net-read + slime-print-apropos + slime-insert-propertized + slime-beginning-of-symbol + slime-end-of-symbol + slime-eval-feature-expression + slime-forward-sexp + slime-forward-cruft + slime-forward-reader-conditional))) + +(slime--compile-hotspots) + +(add-to-list 'load-path (expand-file-name "contrib" slime-path)) + +(run-hooks 'slime-load-hook) +(provide 'slime) + +(slime-setup) + +;; Local Variables: +;; outline-regexp: ";;;;+" +;; indent-tabs-mode: nil +;; coding: latin-1-unix +;; End: +;;; slime.el ends here diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/start-swank.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/start-swank.lisp new file mode 100644 index 0000000..340606c --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/start-swank.lisp @@ -0,0 +1,20 @@ +;;; This file is intended to be loaded by an implementation to +;;; get a running swank server +;;; e.g. sbcl --load start-swank.lisp +;;; +;;; Default port is 4005 + +;;; For additional swank-side configurations see +;;; 6.2 section of the Slime user manual. + +(load (merge-pathnames "swank-loader.lisp" *load-truename*)) + +(swank-loader:init + :delete nil ; delete any existing SWANK packages + :reload nil ; reload SWANK, even if the SWANK package already exists + :load-contribs nil) ; load all contribs + +(swank:create-server :port 4005 + ;; if non-nil the connection won't be closed + ;; after connecting + :dont-close nil) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank-loader.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank-loader.lisp new file mode 100644 index 0000000..ec89e67 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank-loader.lisp @@ -0,0 +1,376 @@ +;;;; -*- indent-tabs-mode: nil -*- +;;; +;;; swank-loader.lisp --- Compile and load the Slime backend. +;;; +;;; Created 2003, James Bielman +;;; +;;; This code has been placed in the Public Domain. All warranties +;;; are disclaimed. +;;; + +;; If you want customize the source- or fasl-directory you can set +;; swank-loader:*source-directory* resp. swank-loader:*fasl-directory* +;; before loading this files. +;; E.g.: +;; +;; (load ".../swank-loader.lisp") +;; (setq swank-loader::*fasl-directory* "/tmp/fasl/") +;; (swank-loader:init) + +(cl:defpackage :swank-loader + (:use :cl) + (:export :init + :dump-image + :list-fasls + :*source-directory* + :*fasl-directory* + :*started-from-emacs*)) + +(cl:in-package :swank-loader) + +(defvar *started-from-emacs* nil) + +(defvar *source-directory* + (make-pathname :name nil :type nil + :defaults (or *load-pathname* *default-pathname-defaults*)) + "The directory where to look for the source.") + +(defparameter *sysdep-files* + #+cmu '((swank source-path-parser) (swank source-file-cache) (swank cmucl) + (swank gray)) + #+scl '((swank source-path-parser) (swank source-file-cache) (swank scl) + (swank gray)) + #+sbcl '((swank source-path-parser) (swank source-file-cache) (swank sbcl) + (swank gray)) + #+clozure '(metering (swank ccl) (swank gray)) + #+lispworks '((swank lispworks) (swank gray)) + #+allegro '((swank allegro) (swank gray)) + #+clisp '(xref metering (swank clisp) (swank gray)) + #+armedbear '((swank abcl)) + #+cormanlisp '((swank corman) (swank gray)) + #+ecl '((swank ecl) (swank gray)) + #+clasp '((swank clasp) (swank gray)) + #+mkcl '((swank mkcl) (swank gray)) + #+mezzano '((swank mezzano) (swank gray)) + ) + +(defparameter *implementation-features* + '(:allegro :lispworks :sbcl :clozure :cmu :clisp :ccl :corman :cormanlisp + :armedbear :gcl :ecl :scl :mkcl :clasp :mezzano)) + +(defparameter *os-features* + '(:macosx :linux :windows :mswindows :win32 :solaris :darwin :sunos :hpux + :unix :mezzano)) + +(defparameter *architecture-features* + '(:powerpc :ppc :x86 :x86-64 :x86_64 :amd64 :i686 :i586 :i486 :pc386 :iapx386 + :sparc64 :sparc :hppa64 :hppa :arm :armv5l :armv6l :armv7l :arm64 :aarch64 + :pentium3 :pentium4 + :mips :mipsel + :java-1.4 :java-1.5 :java-1.6 :java-1.7)) + +(defun q (s) (read-from-string s)) + +#+ecl +(defun ecl-version-string () + (format nil "~A~@[-~A~]" + (lisp-implementation-version) + (when (find-symbol "LISP-IMPLEMENTATION-VCS-ID" :ext) + (let ((vcs-id (funcall (q "ext:lisp-implementation-vcs-id")))) + (when (>= (length vcs-id) 8) + (subseq vcs-id 0 8)))))) + +#+clasp +(defun clasp-version-string () + (format nil "~A~@[-~A~]" + (lisp-implementation-version) + (core:lisp-implementation-id))) + +(defun lisp-version-string () + #+(or clozure cmu) (substitute-if #\_ (lambda (x) (find x " /")) + (lisp-implementation-version)) + #+(or cormanlisp scl mkcl) (lisp-implementation-version) + #+sbcl (format nil "~a~:[~;-no-threads~]" + (lisp-implementation-version) + #+sb-thread nil + #-sb-thread t) + #+lispworks (lisp-implementation-version) + #+allegro (format nil "~@{~a~}" + excl::*common-lisp-version-number* + (if (eq 'h 'H) "A" "M") ; ANSI vs MoDeRn + (if (member :smp *features*) "s" "") + (if (member :64bit *features*) "-64bit" "") + (excl:ics-target-case + (:-ics "") + (:+ics "-ics"))) + #+clisp (let ((s (lisp-implementation-version))) + (subseq s 0 (position #\space s))) + #+armedbear (lisp-implementation-version) + #+ecl (ecl-version-string) + #+clasp (clasp-version-string) + #+mezzano (let ((s (lisp-implementation-version))) + (subseq s 0 (position #\space s)))) + +(defun unique-dir-name () + "Return a name that can be used as a directory name that is +unique to a Lisp implementation, Lisp implementation version, +operating system, and hardware architecture." + (flet ((first-of (features) + (loop for f in features + when (find f *features*) return it)) + (maybe-warn (value fstring &rest args) + (cond (value) + (t (apply #'warn fstring args) + "unknown")))) + (let ((lisp (maybe-warn (first-of *implementation-features*) + "No implementation feature found in ~a." + *implementation-features*)) + (os (maybe-warn (first-of *os-features*) + "No os feature found in ~a." *os-features*)) + (arch (maybe-warn (first-of *architecture-features*) + "No architecture feature found in ~a." + *architecture-features*)) + (version (maybe-warn (lisp-version-string) + "Don't know how to get Lisp ~ + implementation version."))) + (format nil "~(~@{~a~^-~}~)" lisp version os arch)))) + +(defun file-newer-p (new-file old-file) + "Returns true if NEW-FILE is newer than OLD-FILE." + (> (file-write-date new-file) (file-write-date old-file))) + +(defun string-starts-with (string prefix) + (string-equal string prefix :end1 (min (length string) (length prefix)))) + +(defun slime-version-string () + "Return a string identifying the SLIME version. +Return nil if nothing appropriate is available." + (with-open-file (s (merge-pathnames "slime.el" *source-directory*) + :if-does-not-exist nil) + (when s + (loop with prefix = ";; Version: " + for line = (read-line s nil :eof) + until (eq line :eof) + when (string-starts-with line prefix) + return (subseq line (length prefix)))))) + +(defun default-fasl-dir () + (merge-pathnames + (make-pathname + :directory `(:relative ".slime" "fasl" + ,@(if (slime-version-string) (list (slime-version-string))) + ,(unique-dir-name))) + (user-homedir-pathname))) + +(defvar *fasl-directory* (default-fasl-dir) + "The directory where fasl files should be placed.") + +(defun binary-pathname (src-pathname binary-dir) + "Return the pathname where SRC-PATHNAME's binary should be compiled." + (let ((cfp (compile-file-pathname src-pathname))) + (merge-pathnames (make-pathname :name (pathname-name cfp) + :type (pathname-type cfp)) + binary-dir))) + +(defun handle-swank-load-error (condition context pathname) + (fresh-line *error-output*) + (pprint-logical-block (*error-output* () :per-line-prefix ";; ") + (format *error-output* + "~%Error ~A ~A:~% ~A~%" + context pathname condition))) + +(defun compile-files (files fasl-dir load quiet) + "Compile each file in FILES if the source is newer than its +corresponding binary, or the file preceding it was recompiled. +If LOAD is true, load the fasl file." + (let ((needs-recompile nil) + (state :unknown)) + (dolist (src files) + (let ((dest (binary-pathname src fasl-dir))) + (handler-bind + ((error (lambda (c) + (ecase state + (:compile (handle-swank-load-error c "compiling" src)) + (:load (handle-swank-load-error c "loading" dest)) + (:unknown (handle-swank-load-error c "???ing" src)))))) + (when (or needs-recompile + (not (probe-file dest)) + (file-newer-p src dest)) + (ensure-directories-exist dest) + ;; need to recompile SRC, so we'll need to recompile + ;; everything after this too. + (setf needs-recompile t + state :compile) + (or (compile-file src :output-file dest :print nil + :verbose (not quiet)) + ;; An implementation may not necessarily signal a + ;; condition itself when COMPILE-FILE fails (e.g. ECL) + (error "COMPILE-FILE returned NIL."))) + (when load + (setf state :load) + (load dest :verbose (not quiet)))))))) + +#+cormanlisp +(defun compile-files (files fasl-dir load quiet) + "Corman Lisp has trouble with compiled files." + (declare (ignore fasl-dir)) + (when load + (dolist (file files) + (load file :verbose (not quiet) + (force-output))))) + +(defun load-user-init-file () + "Load the user init file, return NIL if it does not exist." + (load (merge-pathnames (user-homedir-pathname) + (make-pathname :name ".swank" :type "lisp")) + :if-does-not-exist nil)) + +(defun load-site-init-file (dir) + (load (make-pathname :name "site-init" :type "lisp" + :defaults dir) + :if-does-not-exist nil)) + +(defun src-files (names src-dir) + (mapcar (lambda (name) + (multiple-value-bind (dirs name) + (etypecase name + (symbol (values '() name)) + (cons (values (butlast name) (car (last name))))) + (make-pathname + :directory (append (or (pathname-directory src-dir) + '(:relative)) + (mapcar #'string-downcase dirs)) + :name (string-downcase name) + :type "lisp" + :defaults src-dir))) + names)) + +(defvar *swank-files* + `(packages + (swank backend) ,@*sysdep-files* (swank match) (swank rpc) + swank)) + +(defvar *contribs* + '(swank-util swank-repl + swank-c-p-c swank-arglists swank-fuzzy + swank-fancy-inspector + swank-presentations swank-presentation-streams + #+(or asdf2 asdf3 sbcl ecl) swank-asdf + swank-package-fu + swank-hyperdoc + #+sbcl swank-sbcl-exts + swank-mrepl + swank-trace-dialog + swank-macrostep + swank-quicklisp) + "List of names for contrib modules.") + +(defun append-dir (absolute name) + (merge-pathnames + (make-pathname :directory `(:relative ,name) :defaults absolute) + absolute)) + +(defun contrib-dir (base-dir) + (append-dir base-dir "contrib")) + +(defun load-swank (&key (src-dir *source-directory*) + (fasl-dir *fasl-directory*) + quiet) + (with-compilation-unit () + (compile-files (src-files *swank-files* src-dir) fasl-dir t quiet)) + (funcall (q "swank::before-init") + (slime-version-string) + (list (contrib-dir fasl-dir) + (contrib-dir src-dir)))) + +(defun delete-stale-contrib-fasl-files (swank-files contrib-files fasl-dir) + (let ((newest (reduce #'max (mapcar #'file-write-date swank-files)))) + (dolist (src contrib-files) + (let ((fasl (binary-pathname src fasl-dir))) + (when (and (probe-file fasl) + (<= (file-write-date fasl) newest)) + (delete-file fasl)))))) + +(defun compile-contribs (&key (src-dir (contrib-dir *source-directory*)) + (fasl-dir (contrib-dir *fasl-directory*)) + (swank-src-dir *source-directory*) + load quiet) + (let* ((swank-src-files (src-files *swank-files* swank-src-dir)) + (contrib-src-files (src-files *contribs* src-dir))) + (delete-stale-contrib-fasl-files swank-src-files contrib-src-files + fasl-dir) + (compile-files contrib-src-files fasl-dir load quiet))) + +(defun loadup () + (load-swank) + (compile-contribs :load t)) + +(defun setup () + (load-site-init-file *source-directory*) + (load-user-init-file) + (when (#-clisp probe-file + #+clisp ext:probe-directory + (contrib-dir *source-directory*)) + (eval `(pushnew 'compile-contribs ,(q "swank::*after-init-hook*")))) + (funcall (q "swank::init"))) + +(defun list-swank-packages () + (remove-if-not (lambda (package) + (let ((name (package-name package))) + (and (string-not-equal name "swank-loader") + (string-starts-with name "swank")))) + (list-all-packages))) + +(defun delete-packages (packages) + (dolist (package packages) + (flet ((handle-package-error (c) + (let ((pkgs (set-difference (package-used-by-list package) + packages))) + (when pkgs + (warn "deleting ~a which is used by ~{~a~^, ~}." + package pkgs)) + (continue c)))) + (handler-bind ((package-error #'handle-package-error)) + (delete-package package))))) + +(defun init (&key delete reload load-contribs (setup t) + (quiet (not *load-verbose*)) + from-emacs) + "Load SWANK and initialize some global variables. +If DELETE is true, delete any existing SWANK packages. +If RELOAD is true, reload SWANK, even if the SWANK package already exists. +If LOAD-CONTRIBS is true, load all contribs +If SETUP is true, load user init files and initialize some +global variabes in SWANK." + (when from-emacs + (setf *started-from-emacs* t)) + (when (and delete (find-package :swank)) + (delete-packages (list-swank-packages))) + (cond ((or (not (find-package :swank)) reload) + (load-swank :quiet quiet)) + (t + (warn "Not reloading SWANK. Package already exists."))) + (when load-contribs + (compile-contribs :load t :quiet quiet)) + (when setup + (setup))) + +(defun dump-image (filename) + (init :setup nil) + (funcall (q "swank/backend:save-image") filename)) + +(defun list-fasls (&key (include-contribs t) (compile t) + (quiet (not *compile-verbose*))) + "List up SWANK's fasls along with their dependencies." + (flet ((collect-fasls (files fasl-dir) + (when compile + (compile-files files fasl-dir nil quiet)) + (loop for src in files + when (probe-file (binary-pathname src fasl-dir)) + collect it))) + (append (collect-fasls (src-files *swank-files* *source-directory*) + *fasl-directory*) + (when include-contribs + (collect-fasls (src-files *contribs* + (contrib-dir *source-directory*)) + (contrib-dir *fasl-directory*)))))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank.asd b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank.asd new file mode 100644 index 0000000..d9a7627 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank.asd @@ -0,0 +1,37 @@ +;;; -*- lisp -*- + +;; ASDF system definition for loading the Swank server independently +;; of Emacs. +;; +;; This is only useful if you want to start a Swank server in a Lisp +;; processes that doesn't run under Emacs. Lisp processes created by +;; `M-x slime' automatically start the server. + +;; Usage: +;; +;; (require :swank) +;; (swank:create-swank-server PORT) => ACTUAL-PORT +;; +;; (PORT can be zero to mean "any available port".) +;; Then the Swank server is running on localhost:ACTUAL-PORT. You can +;; use `M-x slime-connect' to connect Emacs to it. +;; +;; This code has been placed in the Public Domain. All warranties +;; are disclaimed. + +(defpackage :swank-loader + (:use :cl)) + +(in-package :swank-loader) + +(defclass swank-loader-file (asdf:cl-source-file) ()) + +;;;; after loading run init + +(defmethod asdf:perform ((o asdf:load-op) (f swank-loader-file)) + (load (asdf::component-pathname f)) + (funcall (read-from-string "swank-loader::init") :reload t)) + +(asdf:defsystem :swank + :default-component-class swank-loader-file + :components ((:file "swank-loader"))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank.lisp new file mode 100644 index 0000000..d0ba81b --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank.lisp @@ -0,0 +1,3795 @@ +;;;; swank.lisp --- Server for SLIME commands. +;;; +;;; This code has been placed in the Public Domain. All warranties +;;; are disclaimed. +;;; +;;; This file defines the "Swank" TCP server for Emacs to talk to. The +;;; code in this file is purely portable Common Lisp. We do require a +;;; smattering of non-portable functions in order to write the server, +;;; so we have defined them in `swank/backend.lisp' and implemented +;;; them separately for each Lisp implementation. These extensions are +;;; available to us here via the `SWANK/BACKEND' package. + +(in-package :swank) +;;;; Top-level variables, constants, macros + +(defconstant cl-package (find-package :cl) + "The COMMON-LISP package.") + +(defconstant keyword-package (find-package :keyword) + "The KEYWORD package.") + +(defconstant default-server-port 4005 + "The default TCP port for the server (when started manually).") + +(defvar *swank-debug-p* t + "When true, print extra debugging information.") + +(defvar *backtrace-pprint-dispatch-table* + (let ((table (copy-pprint-dispatch nil))) + (flet ((print-string (stream string) + (cond (*print-escape* + (escape-string string stream + :map '((#\" . "\\\"") + (#\\ . "\\\\") + (#\newline . "\\n") + (#\return . "\\r")))) + (t (write-string string stream))))) + (set-pprint-dispatch 'string #'print-string 0 table) + table))) + +(defvar *backtrace-printer-bindings* + `((*print-pretty* . t) + (*print-readably* . nil) + (*print-level* . 4) + (*print-length* . 6) + (*print-lines* . 1) + (*print-right-margin* . 200) + (*print-pprint-dispatch* . ,*backtrace-pprint-dispatch-table*)) + "Pretter settings for printing backtraces.") + +(defvar *default-worker-thread-bindings* '() + "An alist to initialize dynamic variables in worker threads. +The list has the form ((VAR . VALUE) ...). Each variable VAR will be +bound to the corresponding VALUE.") + +(defun call-with-bindings (alist fun) + "Call FUN with variables bound according to ALIST. +ALIST is a list of the form ((VAR . VAL) ...)." + (if (null alist) + (funcall fun) + (let* ((rlist (reverse alist)) + (vars (mapcar #'car rlist)) + (vals (mapcar #'cdr rlist))) + (progv vars vals + (funcall fun))))) + +(defmacro with-bindings (alist &body body) + "See `call-with-bindings'." + `(call-with-bindings ,alist (lambda () ,@body))) + +;;; The `DEFSLIMEFUN' macro defines a function that Emacs can call via +;;; RPC. + +(defmacro defslimefun (name arglist &body rest) + "A DEFUN for functions that Emacs can call by RPC." + `(progn + (defun ,name ,arglist ,@rest) + ;; see + (eval-when (:compile-toplevel :load-toplevel :execute) + (export ',name (symbol-package ',name))))) + +(defun missing-arg () + "A function that the compiler knows will never to return a value. +You can use (MISSING-ARG) as the initform for defstruct slots that +must always be supplied. This way the :TYPE slot option need not +include some arbitrary initial value like NIL." + (error "A required &KEY or &OPTIONAL argument was not supplied.")) + + +;;;; Hooks +;;; +;;; We use Emacs-like `add-hook' and `run-hook' utilities to support +;;; simple indirection. The interface is more CLish than the Emacs +;;; Lisp one. + +(defmacro add-hook (place function) + "Add FUNCTION to the list of values on PLACE." + `(pushnew ,function ,place)) + +(defun run-hook (functions &rest arguments) + "Call each of FUNCTIONS with ARGUMENTS." + (dolist (function functions) + (apply function arguments))) + +(defun run-hook-until-success (functions &rest arguments) + "Call each of FUNCTIONS with ARGUMENTS, stop if any function returns +a truthy value" + (loop for hook in functions + thereis (apply hook arguments))) + +(defvar *new-connection-hook* '() + "This hook is run each time a connection is established. +The connection structure is given as the argument. +Backend code should treat the connection structure as opaque.") + +(defvar *connection-closed-hook* '() + "This hook is run when a connection is closed. +The connection as passed as an argument. +Backend code should treat the connection structure as opaque.") + +(defvar *pre-reply-hook* '() + "Hook run (without arguments) immediately before replying to an RPC.") + +(defvar *after-init-hook* '() + "Hook run after user init files are loaded.") + + +;;;; Connections +;;; +;;; Connection structures represent the network connections between +;;; Emacs and Lisp. Each has a socket stream, a set of user I/O +;;; streams that redirect to Emacs, and optionally a second socket +;;; used solely to pipe user-output to Emacs (an optimization). This +;;; is also the place where we keep everything that needs to be +;;; freed/closed/killed when we disconnect. + +(defstruct (connection + (:constructor %make-connection) + (:conc-name connection.) + (:print-function print-connection)) + ;; The listening socket. (usually closed) + (socket (missing-arg) :type t :read-only t) + ;; Character I/O stream of socket connection. Read-only to avoid + ;; race conditions during initialization. + (socket-io (missing-arg) :type stream :read-only t) + ;; Optional dedicated output socket (backending `user-output' slot). + ;; Has a slot so that it can be closed with the connection. + (dedicated-output nil :type (or stream null)) + ;; Streams that can be used for user interaction, with requests + ;; redirected to Emacs. + (user-input nil :type (or stream null)) + (user-output nil :type (or stream null)) + (user-io nil :type (or stream null)) + ;; Bindings used for this connection (usually streams) + (env '() :type list) + ;; A stream that we use for *trace-output*; if nil, we user user-output. + (trace-output nil :type (or stream null)) + ;; A stream where we send REPL results. + (repl-results nil :type (or stream null)) + ;; Cache of macro-indentation information that has been sent to Emacs. + ;; This is used for preparing deltas to update Emacs's knowledge. + ;; Maps: symbol -> indentation-specification + (indentation-cache (make-hash-table :test 'eq) :type hash-table) + ;; The list of packages represented in the cache: + (indentation-cache-packages '()) + ;; The communication style used. + (communication-style nil :type (member nil :spawn :sigio :fd-handler)) + ) + +(defun print-connection (conn stream depth) + (declare (ignore depth)) + (print-unreadable-object (conn stream :type t :identity t))) + +(defstruct (singlethreaded-connection (:include connection) + (:conc-name sconn.)) + ;; The SIGINT handler we should restore when the connection is + ;; closed. + saved-sigint-handler + ;; A queue of events. Not all events can be processed in order and + ;; we need a place to stored them. + (event-queue '() :type list) + ;; A counter that is incremented whenever an event is added to the + ;; queue. This is used to detected modifications to the event queue + ;; by interrupts. The counter wraps around. + (events-enqueued 0 :type fixnum)) + +(defstruct (multithreaded-connection (:include connection) + (:conc-name mconn.)) + ;; In multithreaded systems we delegate certain tasks to specific + ;; threads. The `reader-thread' is responsible for reading network + ;; requests from Emacs and sending them to the `control-thread'; the + ;; `control-thread' is responsible for dispatching requests to the + ;; threads that should handle them; the `repl-thread' is the one + ;; that evaluates REPL expressions. The control thread dispatches + ;; all REPL evaluations to the REPL thread and for other requests it + ;; spawns new threads. + reader-thread + control-thread + repl-thread + auto-flush-thread + indentation-cache-thread + ;; List of threads that are currently processing requests. We use + ;; this to find the newest/current thread for an interrupt. In the + ;; future we may store here (thread . request-tag) pairs so that we + ;; can interrupt specific requests. + (active-threads '() :type list) + ) + +(defvar *emacs-connection* nil + "The connection to Emacs currently in use.") + +(defun make-connection (socket stream style) + (let ((conn (funcall (ecase style + (:spawn + #'make-multithreaded-connection) + ((:sigio nil :fd-handler) + #'make-singlethreaded-connection)) + :socket socket + :socket-io stream + :communication-style style))) + (run-hook *new-connection-hook* conn) + (send-to-sentinel `(:add-connection ,conn)) + conn)) + +(defslimefun ping (tag) + tag) + +(defun safe-backtrace () + (ignore-errors + (call-with-debugging-environment + (lambda () (backtrace 0 nil))))) + +(define-condition swank-error (error) + ((backtrace :initarg :backtrace :reader swank-error.backtrace) + (condition :initarg :condition :reader swank-error.condition)) + (:report (lambda (c s) (princ (swank-error.condition c) s))) + (:documentation "Condition which carries a backtrace.")) + +(defun signal-swank-error (condition &optional (backtrace (safe-backtrace))) + (error 'swank-error :condition condition :backtrace backtrace)) + +(defvar *debug-on-swank-protocol-error* nil + "When non-nil invoke the system debugger on errors that were +signalled during decoding/encoding the wire protocol. Do not set this +to T unless you want to debug swank internals.") + +(defmacro with-swank-error-handler ((connection) &body body) + "Close the connection on internal `swank-error's." + (let ((conn (gensym))) + `(let ((,conn ,connection)) + (handler-case + (handler-bind ((swank-error + (lambda (condition) + (when *debug-on-swank-protocol-error* + (invoke-default-debugger condition))))) + (progn . ,body)) + (swank-error (condition) + (close-connection ,conn + (swank-error.condition condition) + (swank-error.backtrace condition))))))) + +(defmacro with-panic-handler ((connection) &body body) + "Close the connection on unhandled `serious-condition's." + (let ((conn (gensym))) + `(let ((,conn ,connection)) + (handler-bind ((serious-condition + (lambda (condition) + (close-connection ,conn condition (safe-backtrace)) + (abort condition)))) + . ,body)))) + +(add-hook *new-connection-hook* 'notify-backend-of-connection) +(defun notify-backend-of-connection (connection) + (declare (ignore connection)) + (emacs-connected)) + + +;;;; Utilities + + +;;;;; Logging + +(defvar *swank-io-package* + (let ((package (make-package :swank-io-package :use '()))) + (import '(nil t quote) package) + package)) + +(defvar *log-events* nil) + +(defun init-log-output () + (unless *log-output* + (setq *log-output* (real-output-stream *error-output*)))) + +(add-hook *after-init-hook* 'init-log-output) + +(defun real-input-stream (stream) + (typecase stream + (synonym-stream + (real-input-stream (symbol-value (synonym-stream-symbol stream)))) + (two-way-stream + (real-input-stream (two-way-stream-input-stream stream))) + (t stream))) + +(defun real-output-stream (stream) + (typecase stream + (synonym-stream + (real-output-stream (symbol-value (synonym-stream-symbol stream)))) + (two-way-stream + (real-output-stream (two-way-stream-output-stream stream))) + (t stream))) + +(defvar *event-history* (make-array 40 :initial-element nil) + "A ring buffer to record events for better error messages.") +(defvar *event-history-index* 0) +(defvar *enable-event-history* t) + +(defun log-event (format-string &rest args) + "Write a message to *terminal-io* when *log-events* is non-nil. +Useful for low level debugging." + (with-standard-io-syntax + (let ((*print-readably* nil) + (*print-pretty* nil) + (*package* *swank-io-package*)) + (when *enable-event-history* + (setf (aref *event-history* *event-history-index*) + (format nil "~?" format-string args)) + (setf *event-history-index* + (mod (1+ *event-history-index*) (length *event-history*)))) + (when *log-events* + (write-string (escape-non-ascii (format nil "~?" format-string args)) + *log-output*) + (force-output *log-output*))))) + +(defun event-history-to-list () + "Return the list of events (older events first)." + (let ((arr *event-history*) + (idx *event-history-index*)) + (concatenate 'list (subseq arr idx) (subseq arr 0 idx)))) + +(defun clear-event-history () + (fill *event-history* nil) + (setq *event-history-index* 0)) + +(defun dump-event-history (stream) + (dolist (e (event-history-to-list)) + (dump-event e stream))) + +(defun dump-event (event stream) + (cond ((stringp event) + (write-string (escape-non-ascii event) stream)) + ((null event)) + (t + (write-string + (escape-non-ascii (format nil "Unexpected event: ~A~%" event)) + stream)))) + +(defun escape-non-ascii (string) + "Return a string like STRING but with non-ascii chars escaped." + (cond ((ascii-string-p string) string) + (t (with-output-to-string (out) + (loop for c across string do + (cond ((ascii-char-p c) (write-char c out)) + (t (format out "\\x~4,'0X" (char-code c))))))))) + +(defun ascii-string-p (o) + (and (stringp o) + (every #'ascii-char-p o))) + +(defun ascii-char-p (c) + (<= (char-code c) 127)) + + +;;;;; Helper macros + +(defmacro dcase (value &body patterns) + "Dispatch VALUE to one of PATTERNS. +A cross between `case' and `destructuring-bind'. +The pattern syntax is: + ((HEAD . ARGS) . BODY) +The list of patterns is searched for a HEAD `eq' to the car of +VALUE. If one is found, the BODY is executed with ARGS bound to the +corresponding values in the CDR of VALUE." + (let ((operator (gensym "op-")) + (operands (gensym "rand-")) + (tmp (gensym "tmp-"))) + `(let* ((,tmp ,value) + (,operator (car ,tmp)) + (,operands (cdr ,tmp))) + (case ,operator + ,@(loop for (pattern . body) in patterns collect + (if (eq pattern t) + `(t ,@body) + (destructuring-bind (op &rest rands) pattern + `(,op (destructuring-bind ,rands ,operands + ,@body))))) + ,@(if (eq (caar (last patterns)) t) + '() + `((t (error "dcase failed: ~S" ,tmp)))))))) + + +;;;; Interrupt handling + +;; Usually we'd like to enter the debugger when an interrupt happens. +;; But for some operations, in particular send&receive, it's crucial +;; that those are not interrupted when the mailbox is in an +;; inconsistent/locked state. Obviously, if send&receive don't work we +;; can't communicate and the debugger will not work. To solve that +;; problem, we try to handle interrupts only at certain safe-points. +;; +;; Whenever an interrupt happens we call the function +;; INVOKE-OR-QUEUE-INTERRUPT. Usually this simply invokes the +;; debugger, but if interrupts are disabled the interrupt is put in a +;; queue for later processing. At safe-points, we call +;; CHECK-SLIME-INTERRUPTS which looks at the queue and invokes the +;; debugger if needed. +;; +;; The queue for interrupts is stored in a thread local variable. +;; WITH-CONNECTION sets it up. WITH-SLIME-INTERRUPTS allows +;; interrupts, i.e. the debugger is entered immediately. When we call +;; "user code" or non-problematic code we allow interrupts. When +;; inside WITHOUT-SLIME-INTERRUPTS, interrupts are queued. When we +;; switch from "user code" to more delicate operations we need to +;; disable interrupts. In particular, interrupts should be disabled +;; for SEND and RECEIVE-IF. + +;; If true execute interrupts, otherwise queue them. +;; Note: `with-connection' binds *pending-slime-interrupts*. +(defvar *slime-interrupts-enabled*) + +(defmacro with-interrupts-enabled% (flag body) + `(progn + ,@(if flag '((check-slime-interrupts))) + (multiple-value-prog1 + (let ((*slime-interrupts-enabled* ,flag)) + ,@body) + ,@(if flag '((check-slime-interrupts)))))) + +(defmacro with-slime-interrupts (&body body) + `(with-interrupts-enabled% t ,body)) + +(defmacro without-slime-interrupts (&body body) + `(with-interrupts-enabled% nil ,body)) + +(defun queue-thread-interrupt (thread function) + (interrupt-thread thread + (lambda () + ;; safely interrupt THREAD + (when (invoke-or-queue-interrupt function) + (wake-thread thread))))) + +(defun invoke-or-queue-interrupt (function) + (log-event "invoke-or-queue-interrupt: ~a~%" function) + (cond ((not (boundp '*slime-interrupts-enabled*)) + (without-slime-interrupts + (funcall function))) + (*slime-interrupts-enabled* + (log-event "interrupts-enabled~%") + (funcall function)) + (t + (setq *pending-slime-interrupts* + (nconc *pending-slime-interrupts* + (list function))) + (cond ((cdr *pending-slime-interrupts*) + (log-event "too many queued interrupts~%") + (with-simple-restart (continue "Continue from interrupt") + (handler-bind ((serious-condition #'invoke-slime-debugger)) + (check-slime-interrupts)))) + (t + (log-event "queue-interrupt: ~a~%" function) + (when *interrupt-queued-handler* + (funcall *interrupt-queued-handler*)) + t))))) + + +;;; FIXME: poor name? +(defmacro with-io-redirection ((connection) &body body) + "Execute BODY I/O redirection to CONNECTION. " + `(with-bindings (connection.env ,connection) + . ,body)) + +;; Thread local variable used for flow-control. +;; It's bound by `with-connection'. +(defvar *send-counter*) + +(defmacro with-connection ((connection) &body body) + "Execute BODY in the context of CONNECTION." + `(let ((connection ,connection) + (function (lambda () . ,body))) + (if (eq *emacs-connection* connection) + (funcall function) + (let ((*emacs-connection* connection) + (*pending-slime-interrupts* '()) + (*send-counter* 0)) + (without-slime-interrupts + (with-swank-error-handler (connection) + (with-io-redirection (connection) + (call-with-debugger-hook #'swank-debugger-hook + function)))))))) + +(defun call-with-retry-restart (msg thunk) + (loop (with-simple-restart (retry "~a" msg) + (return (funcall thunk))))) + +(defmacro with-retry-restart ((&key (msg "Retry.")) &body body) + (check-type msg string) + `(call-with-retry-restart ,msg (lambda () ,@body))) + +(defmacro with-struct* ((conc-name get obj) &body body) + (let ((var (gensym))) + `(let ((,var ,obj)) + (macrolet ((,get (slot) + (let ((getter (intern (concatenate 'string + ',(string conc-name) + (string slot)) + (symbol-package ',conc-name)))) + `(,getter ,',var)))) + ,@body)))) + +(defmacro define-special (name doc) + "Define a special variable NAME with doc string DOC. +This is like defvar, but NAME will not be initialized." + `(progn + (defvar ,name) + (setf (documentation ',name 'variable) ,doc))) + + +;;;;; Sentinel +;;; +;;; The sentinel thread manages some global lists. +;;; FIXME: Overdesigned? + +(defvar *connections* '() + "List of all active connections, with the most recent at the front.") + +(defvar *servers* '() + "A list ((server-socket port thread) ...) describing the listening sockets. +Used to close sockets on server shutdown or restart.") + +;; FIXME: we simply access the global variable here. We could ask the +;; sentinel thread instead but then we still have the problem that the +;; connection could be closed before we use it. +(defun default-connection () + "Return the 'default' Emacs connection. +This connection can be used to talk with Emacs when no specific +connection is in use, i.e. *EMACS-CONNECTION* is NIL. + +The default connection is defined (quite arbitrarily) as the most +recently established one." + (car *connections*)) + +(defun start-sentinel () + (unless (find-registered 'sentinel) + (let ((thread (spawn #'sentinel :name "Swank Sentinel"))) + (register-thread 'sentinel thread)))) + +(defun sentinel () + (catch 'exit-sentinel + (loop (sentinel-serve (receive))))) + +(defun send-to-sentinel (msg) + (let ((sentinel (find-registered 'sentinel))) + (cond (sentinel (send sentinel msg)) + (t (sentinel-serve msg))))) + +(defun sentinel-serve (msg) + (dcase msg + ((:add-connection conn) + (push conn *connections*)) + ((:close-connection connection condition backtrace) + (close-connection% connection condition backtrace) + (sentinel-maybe-exit)) + ((:add-server socket port thread) + (push (list socket port thread) *servers*)) + ((:stop-server key port) + (sentinel-stop-server key port) + (sentinel-maybe-exit)))) + +(defun sentinel-stop-server (key value) + (let ((probe (find value *servers* :key (ecase key + (:socket #'car) + (:port #'cadr))))) + (cond (probe + (setq *servers* (delete probe *servers*)) + (destructuring-bind (socket _port thread) probe + (declare (ignore _port)) + (ignore-errors (close-socket socket)) + (when (and thread + (thread-alive-p thread) + (not (eq thread (current-thread)))) + (ignore-errors (kill-thread thread))))) + (t + (warn "No server for ~s: ~s" key value))))) + +(defun sentinel-maybe-exit () + (when (and (null *connections*) + (null *servers*) + (and (current-thread) + (eq (find-registered 'sentinel) + (current-thread)))) + (register-thread 'sentinel nil) + (throw 'exit-sentinel nil))) + + +;;;;; Misc + +(defun use-threads-p () + (eq (connection.communication-style *emacs-connection*) :spawn)) + +(defun current-thread-id () + (thread-id (current-thread))) + +(declaim (inline ensure-list)) +(defun ensure-list (thing) + (if (listp thing) thing (list thing))) + + +;;;;; Symbols + +;; FIXME: this docstring is more confusing than helpful. +(defun symbol-status (symbol &optional (package (symbol-package symbol))) + "Returns one of + + :INTERNAL if the symbol is _present_ in PACKAGE as an _internal_ symbol, + + :EXTERNAL if the symbol is _present_ in PACKAGE as an _external_ symbol, + + :INHERITED if the symbol is _inherited_ by PACKAGE through USE-PACKAGE, + but is not _present_ in PACKAGE, + + or NIL if SYMBOL is not _accessible_ in PACKAGE. + + +Be aware not to get confused with :INTERNAL and how \"internal +symbols\" are defined in the spec; there is a slight mismatch of +definition with the Spec and what's commonly meant when talking +about internal symbols most times. As the spec says: + + In a package P, a symbol S is + + _accessible_ if S is either _present_ in P itself or was + inherited from another package Q (which implies + that S is _external_ in Q.) + + You can check that with: (AND (SYMBOL-STATUS S P) T) + + + _present_ if either P is the /home package/ of S or S has been + imported into P or exported from P by IMPORT, or + EXPORT respectively. + + Or more simply, if S is not _inherited_. + + You can check that with: (LET ((STATUS (SYMBOL-STATUS S P))) + (AND STATUS + (NOT (EQ STATUS :INHERITED)))) + + + _external_ if S is going to be inherited into any package that + /uses/ P by means of USE-PACKAGE, MAKE-PACKAGE, or + DEFPACKAGE. + + Note that _external_ implies _present_, since to + make a symbol _external_, you'd have to use EXPORT + which will automatically make the symbol _present_. + + You can check that with: (EQ (SYMBOL-STATUS S P) :EXTERNAL) + + + _internal_ if S is _accessible_ but not _external_. + + You can check that with: (LET ((STATUS (SYMBOL-STATUS S P))) + (AND STATUS + (NOT (EQ STATUS :EXTERNAL)))) + + + Notice that this is *different* to + (EQ (SYMBOL-STATUS S P) :INTERNAL) + because what the spec considers _internal_ is split up into two + explicit pieces: :INTERNAL, and :INHERITED; just as, for instance, + CL:FIND-SYMBOL does. + + The rationale is that most times when you speak about \"internal\" + symbols, you're actually not including the symbols inherited + from other packages, but only about the symbols directly specific + to the package in question. +" + (when package ; may be NIL when symbol is completely uninterned. + (check-type symbol symbol) (check-type package package) + (multiple-value-bind (present-symbol status) + (find-symbol (symbol-name symbol) package) + (and (eq symbol present-symbol) status)))) + +(defun symbol-external-p (symbol &optional (package (symbol-package symbol))) + "True if SYMBOL is external in PACKAGE. +If PACKAGE is not specified, the home package of SYMBOL is used." + (eq (symbol-status symbol package) :external)) + + +;;;; TCP Server + +(defvar *communication-style* (preferred-communication-style)) + +(defvar *dont-close* nil + "Default value of :dont-close argument to start-server and + create-server.") + +(defparameter *loopback-interface* "localhost") + +(defun start-server (port-file &key (style *communication-style*) + (dont-close *dont-close*)) + "Start the server and write the listen port number to PORT-FILE. +This is the entry point for Emacs." + (setup-server 0 + (lambda (port) (announce-server-port port-file port)) + style dont-close nil)) + +(defun create-server (&key (port default-server-port) + (style *communication-style*) + (dont-close *dont-close*) + interface + backlog) + "Start a SWANK server on PORT running in STYLE. +If DONT-CLOSE is true then the listen socket will accept multiple +connections, otherwise it will be closed after the first. + +Optionally, an INTERFACE could be specified and swank will bind +the PORT on this interface. By default, interface is \"localhost\"." + (let ((*loopback-interface* (or interface + *loopback-interface*))) + (setup-server port #'simple-announce-function + style dont-close backlog))) + +(defun find-external-format-or-lose (coding-system) + (or (find-external-format coding-system) + (error "Unsupported coding system: ~s" coding-system))) + +(defmacro restart-loop (form &body clauses) + "Executes FORM, with restart-case CLAUSES which have a chance to modify FORM's +environment before trying again (by returning normally) or giving up (through an +explicit transfer of control), all within an implicit block named nil. +e.g.: (restart-loop (http-request url) (use-value (new) (setq url new)))" + `(loop (restart-case (return ,form) ,@clauses))) + +(defun socket-quest (port backlog) + (restart-loop (create-socket *loopback-interface* port :backlog backlog) + (use-value (&optional (new-port (1+ port))) + :report (lambda (stream) (format stream "Try a port other than ~D" port)) + :interactive + (lambda () + (format *query-io* "Enter port (defaults to ~D): " (1+ port)) + (finish-output *query-io*) ; necessary for tunnels + (ignore-errors (list (parse-integer (read-line *query-io*))))) + (setq port new-port)))) + +(defun setup-server (port announce-fn style dont-close backlog) + (init-log-output) + (let* ((socket (socket-quest port backlog)) + (port (local-port socket))) + (funcall announce-fn port) + (labels ((serve () (accept-connections socket style dont-close)) + (note () (send-to-sentinel `(:add-server ,socket ,port + ,(current-thread)))) + (serve-loop () (note) (loop do (serve) while dont-close))) + (ecase style + (:spawn (initialize-multiprocessing + (lambda () + (start-sentinel) + (spawn #'serve-loop :name (format nil "Swank ~s" port))))) + ((:fd-handler :sigio) + (note) + (add-fd-handler socket #'serve)) + ((nil) (serve-loop)))) + port)) + +(defun stop-server (port) + "Stop server running on PORT." + (send-to-sentinel `(:stop-server :port ,port))) + +(defun restart-server (&key (port default-server-port) + (style *communication-style*) + (dont-close *dont-close*)) + "Stop the server listening on PORT, then start a new SWANK server +on PORT running in STYLE. If DONT-CLOSE is true then the listen socket +will accept multiple connections, otherwise it will be closed after the +first." + (stop-server port) + (sleep 5) + (create-server :port port :style style :dont-close dont-close)) + +(defun accept-connections (socket style dont-close) + (unwind-protect + (let ((client (accept-connection socket :external-format nil + :buffering t))) + (authenticate-client client) + (serve-requests (make-connection socket client style))) + (unless dont-close + (send-to-sentinel `(:stop-server :socket ,socket))))) + +(defun authenticate-client (stream) + (let ((secret (slime-secret))) + (when secret + (set-stream-timeout stream 20) + (let ((first-val (read-packet stream))) + (unless (and (stringp first-val) (string= first-val secret)) + (error "Incoming connection doesn't know the password."))) + (set-stream-timeout stream nil)))) + +(defun slime-secret () + "Finds the magic secret from the user's home directory. Returns nil +if the file doesn't exist; otherwise the first line of the file." + (with-open-file (in + (merge-pathnames (user-homedir-pathname) #p".slime-secret") + :if-does-not-exist nil) + (and in (read-line in nil "")))) + +(defun serve-requests (connection) + "Read and process all requests on connections." + (etypecase connection + (multithreaded-connection + (spawn-threads-for-connection connection)) + (singlethreaded-connection + (ecase (connection.communication-style connection) + ((nil) (simple-serve-requests connection)) + (:sigio (install-sigio-handler connection)) + (:fd-handler (install-fd-handler connection)))))) + +(defun stop-serving-requests (connection) + (etypecase connection + (multithreaded-connection + (cleanup-connection-threads connection)) + (singlethreaded-connection + (ecase (connection.communication-style connection) + ((nil)) + (:sigio (deinstall-sigio-handler connection)) + (:fd-handler (deinstall-fd-handler connection)))))) + +(defun announce-server-port (file port) + (with-open-file (s file + :direction :output + :if-exists :error + :if-does-not-exist :create) + (format s "~S~%" port)) + (simple-announce-function port)) + +(defun simple-announce-function (port) + (when *swank-debug-p* + (format *log-output* "~&;; Swank started at port: ~D.~%" port) + (force-output *log-output*))) + + +;;;;; Event Decoding/Encoding + +(defun decode-message (stream) + "Read an S-expression from STREAM using the SLIME protocol." + (log-event "decode-message~%") + (without-slime-interrupts + (handler-bind ((error #'signal-swank-error)) + (handler-case (read-message stream *swank-io-package*) + (swank-reader-error (c) + `(:reader-error ,(swank-reader-error.packet c) + ,(swank-reader-error.cause c))))))) + +(defun encode-message (message stream) + "Write an S-expression to STREAM using the SLIME protocol." + (log-event "encode-message~%") + (without-slime-interrupts + (handler-bind ((error #'signal-swank-error)) + (write-message message *swank-io-package* stream)))) + + +;;;;; Event Processing + +(defvar *sldb-quit-restart* nil + "The restart that will be invoked when the user calls sldb-quit.") + +;; Establish a top-level restart and execute BODY. +;; Execute K if the restart is invoked. +(defmacro with-top-level-restart ((connection k) &body body) + `(with-connection (,connection) + (restart-case + (let ((*sldb-quit-restart* (find-restart 'abort))) + ,@body) + (abort (&optional v) + :report "Return to SLIME's top level." + (declare (ignore v)) + (force-user-output) + ,k)))) + +(defun handle-requests (connection &optional timeout) + "Read and process :emacs-rex requests. +The processing is done in the extent of the toplevel restart." + (with-connection (connection) + (cond (*sldb-quit-restart* + (process-requests timeout)) + (t + (tagbody + start + (with-top-level-restart (connection (go start)) + (process-requests timeout))))))) + +(defun process-requests (timeout) + "Read and process requests from Emacs." + (loop + (multiple-value-bind (event timeout?) + (wait-for-event `(or (:emacs-rex . _) + (:emacs-channel-send . _)) + timeout) + (when timeout? (return)) + (dcase event + ((:emacs-rex &rest args) (apply #'eval-for-emacs args)) + ((:emacs-channel-send channel (selector &rest args)) + (channel-send channel selector args)))))) + +(defun current-socket-io () + (connection.socket-io *emacs-connection*)) + +(defun close-connection (connection condition backtrace) + (send-to-sentinel `(:close-connection ,connection ,condition ,backtrace))) + +(defun close-connection% (c condition backtrace) + (let ((*debugger-hook* nil)) + (log-event "close-connection: ~a ...~%" condition) + (format *log-output* "~&;; swank:close-connection: ~A~%" + (escape-non-ascii (safe-condition-message condition))) + (stop-serving-requests c) + (close (connection.socket-io c)) + (when (connection.dedicated-output c) + (close (connection.dedicated-output c))) + (setf *connections* (remove c *connections*)) + (run-hook *connection-closed-hook* c) + (when (and condition (not (typep condition 'end-of-file))) + (finish-output *log-output*) + (format *log-output* "~&;; Event history start:~%") + (dump-event-history *log-output*) + (format *log-output* "~ +;; Event history end.~%~ +;; Backtrace:~%~{~A~%~}~ +;; Connection to Emacs lost. [~%~ +;; condition: ~A~%~ +;; type: ~S~%~ +;; style: ~S]~%" + (loop for (i f) in backtrace collect + (ignore-errors + (format nil "~d: ~a" i (escape-non-ascii f)))) + (escape-non-ascii (safe-condition-message condition) ) + (type-of condition) + (connection.communication-style c))) + (finish-output *log-output*) + (log-event "close-connection ~a ... done.~%" condition))) + +;;;;;; Thread based communication + +(defun read-loop (connection) + (let ((input-stream (connection.socket-io connection)) + (control-thread (mconn.control-thread connection))) + (with-swank-error-handler (connection) + (loop (send control-thread (decode-message input-stream)))))) + +(defun dispatch-loop (connection) + (let ((*emacs-connection* connection)) + (with-panic-handler (connection) + (loop (dispatch-event connection (receive)))))) + +(defgeneric thread-for-evaluation (connection id) + (:documentation "Find or create a thread to evaluate the next request.") + (:method ((connection multithreaded-connection) (id (eql t))) + (spawn-worker-thread connection)) + (:method ((connection multithreaded-connection) (id (eql :find-existing))) + (car (mconn.active-threads connection))) + (:method (connection (id integer)) + (declare (ignorable connection)) + (find-thread id)) + (:method ((connection singlethreaded-connection) id) + (declare (ignorable connection connection id)) + (current-thread))) + +(defun interrupt-worker-thread (connection id) + (let ((thread (thread-for-evaluation connection + (cond ((eq id t) :find-existing) + (t id))))) + (log-event "interrupt-worker-thread: ~a ~a~%" id thread) + (if thread + (etypecase connection + (multithreaded-connection + (queue-thread-interrupt thread #'simple-break)) + (singlethreaded-connection + (simple-break))) + (encode-message (list :debug-condition (current-thread-id) + (format nil "Thread with id ~a not found" + id)) + (current-socket-io))))) + +(defun spawn-worker-thread (connection) + (spawn (lambda () + (with-bindings *default-worker-thread-bindings* + (with-top-level-restart (connection nil) + (apply #'eval-for-emacs + (cdr (wait-for-event `(:emacs-rex . _))))))) + :name "worker")) + +(defun add-active-thread (connection thread) + (etypecase connection + (multithreaded-connection + (push thread (mconn.active-threads connection))) + (singlethreaded-connection))) + +(defun remove-active-thread (connection thread) + (etypecase connection + (multithreaded-connection + (setf (mconn.active-threads connection) + (delete thread (mconn.active-threads connection) :count 1))) + (singlethreaded-connection))) + +(defparameter *event-hook* nil) + +(defun dispatch-event (connection event) + "Handle an event triggered either by Emacs or within Lisp." + (log-event "dispatch-event: ~s~%" event) + (or (run-hook-until-success *event-hook* connection event) + (dcase event + ((:emacs-rex form package thread-id id) + (let ((thread (thread-for-evaluation connection thread-id))) + (cond (thread + (add-active-thread connection thread) + (send-event thread `(:emacs-rex ,form ,package ,id))) + (t + (encode-message + (list :invalid-rpc id + (format nil "Thread not found: ~s" thread-id)) + (current-socket-io)))))) + ((:return thread &rest args) + (remove-active-thread connection thread) + (encode-message `(:return ,@args) (current-socket-io))) + ((:emacs-interrupt thread-id) + (interrupt-worker-thread connection thread-id)) + (((:write-string + :debug :debug-condition :debug-activate :debug-return :channel-send + :presentation-start :presentation-end + :new-package :new-features :ed :indentation-update + :eval :eval-no-wait :background-message :inspect :ping + :y-or-n-p :read-from-minibuffer :read-string :read-aborted :test-delay + :write-image :ed-rpc :ed-rpc-no-wait) + &rest _) + (declare (ignore _)) + (encode-message event (current-socket-io))) + (((:emacs-pong :emacs-return :emacs-return-string :ed-rpc-forbidden) + thread-id &rest args) + (send-event (find-thread thread-id) (cons (car event) args))) + ((:emacs-channel-send channel-id msg) + (let ((ch (find-channel channel-id))) + (send-event (channel-thread ch) `(:emacs-channel-send ,ch ,msg)))) + ((:reader-error packet condition) + (encode-message `(:reader-error ,packet + ,(safe-condition-message condition)) + (current-socket-io)))))) + + +(defun send-event (thread event) + (log-event "send-event: ~s ~s~%" thread event) + (let ((c *emacs-connection*)) + (etypecase c + (multithreaded-connection + (send thread event)) + (singlethreaded-connection + (setf (sconn.event-queue c) (nconc (sconn.event-queue c) (list event))) + (setf (sconn.events-enqueued c) (mod (1+ (sconn.events-enqueued c)) + most-positive-fixnum)))))) + +(defun send-to-emacs (event) + "Send EVENT to Emacs." + ;;(log-event "send-to-emacs: ~a" event) + (without-slime-interrupts + (let ((c *emacs-connection*)) + (etypecase c + (multithreaded-connection + (send (mconn.control-thread c) event)) + (singlethreaded-connection + (dispatch-event c event))) + (maybe-slow-down)))) + + +;;;;;; Flow control + +;; After sending N (usually 100) messages we slow down and ping Emacs +;; to make sure that everything we have sent so far was received. + +(defconstant send-counter-limit 100) + +(defun maybe-slow-down () + (let ((counter (incf *send-counter*))) + (when (< send-counter-limit counter) + (setf *send-counter* 0) + (ping-pong)))) + +(defun ping-pong () + (let* ((tag (make-tag)) + (pattern `(:emacs-pong ,tag))) + (send-to-emacs `(:ping ,(current-thread-id) ,tag)) + (wait-for-event pattern))) + + +(defun wait-for-event (pattern &optional timeout) + "Scan the event queue for PATTERN and return the event. +If TIMEOUT is 'nil wait until a matching event is enqued. +If TIMEOUT is 't only scan the queue without waiting. +The second return value is t if the timeout expired before a matching +event was found." + (log-event "wait-for-event: ~s ~s~%" pattern timeout) + (without-slime-interrupts + (let ((c *emacs-connection*)) + (etypecase c + (multithreaded-connection + (receive-if (lambda (e) (event-match-p e pattern)) timeout)) + (singlethreaded-connection + (wait-for-event/event-loop c pattern timeout)))))) + +(defun wait-for-event/event-loop (connection pattern timeout) + (assert (or (not timeout) (eq timeout t))) + (loop + (check-slime-interrupts) + (let ((event (poll-for-event connection pattern))) + (when event (return (car event)))) + (let ((events-enqueued (sconn.events-enqueued connection)) + (ready (wait-for-input (list (current-socket-io)) timeout))) + (cond ((and timeout (not ready)) + (return (values nil t))) + ((or (/= events-enqueued (sconn.events-enqueued connection)) + (eq ready :interrupt)) + ;; rescan event queue, interrupts may enqueue new events + ) + (t + (assert (equal ready (list (current-socket-io)))) + (dispatch-event connection + (decode-message (current-socket-io)))))))) + +(defun poll-for-event (connection pattern) + (let* ((c connection) + (tail (member-if (lambda (e) (event-match-p e pattern)) + (sconn.event-queue c)))) + (when tail + (setf (sconn.event-queue c) + (nconc (ldiff (sconn.event-queue c) tail) (cdr tail))) + tail))) + +;;; FIXME: Make this use SWANK-MATCH. +(defun event-match-p (event pattern) + (cond ((or (keywordp pattern) (numberp pattern) (stringp pattern) + (member pattern '(nil t))) + (equal event pattern)) + ((symbolp pattern) t) + ((consp pattern) + (case (car pattern) + ((or) (some (lambda (p) (event-match-p event p)) (cdr pattern))) + (t (and (consp event) + (and (event-match-p (car event) (car pattern)) + (event-match-p (cdr event) (cdr pattern))))))) + (t (error "Invalid pattern: ~S" pattern)))) + + + +(defun spawn-threads-for-connection (connection) + (setf (mconn.control-thread connection) + (spawn (lambda () (control-thread connection)) + :name "control-thread")) + connection) + +(defun control-thread (connection) + (with-struct* (mconn. @ connection) + (setf (@ control-thread) (current-thread)) + (setf (@ reader-thread) (spawn (lambda () (read-loop connection)) + :name "reader-thread")) + (setf (@ indentation-cache-thread) + (spawn (lambda () (indentation-cache-loop connection)) + :name "swank-indentation-cache-thread")) + (dispatch-loop connection))) + +(defun cleanup-connection-threads (connection) + (let* ((c connection) + (threads (list (mconn.repl-thread c) + (mconn.reader-thread c) + (mconn.control-thread c) + (mconn.auto-flush-thread c) + (mconn.indentation-cache-thread c)))) + (dolist (thread threads) + (when (and thread + (thread-alive-p thread) + (not (equal (current-thread) thread))) + (ignore-errors (kill-thread thread)))))) + +;;;;;; Signal driven IO + +(defun install-sigio-handler (connection) + (add-sigio-handler (connection.socket-io connection) + (lambda () (process-io-interrupt connection))) + (handle-requests connection t)) + +(defvar *io-interupt-level* 0) + +(defun process-io-interrupt (connection) + (log-event "process-io-interrupt ~d ...~%" *io-interupt-level*) + (let ((*io-interupt-level* (1+ *io-interupt-level*))) + (invoke-or-queue-interrupt + (lambda () (handle-requests connection t)))) + (log-event "process-io-interrupt ~d ... done ~%" *io-interupt-level*)) + +(defun deinstall-sigio-handler (connection) + (log-event "deinstall-sigio-handler...~%") + (remove-sigio-handlers (connection.socket-io connection)) + (log-event "deinstall-sigio-handler...done~%")) + +;;;;;; SERVE-EVENT based IO + +(defun install-fd-handler (connection) + (add-fd-handler (connection.socket-io connection) + (lambda () (handle-requests connection t))) + (setf (sconn.saved-sigint-handler connection) + (install-sigint-handler + (lambda () + (invoke-or-queue-interrupt + (lambda () (dispatch-interrupt-event connection)))))) + (handle-requests connection t)) + +(defun dispatch-interrupt-event (connection) + (with-connection (connection) + (dispatch-event connection `(:emacs-interrupt ,(current-thread-id))))) + +(defun deinstall-fd-handler (connection) + (log-event "deinstall-fd-handler~%") + (remove-fd-handlers (connection.socket-io connection)) + (install-sigint-handler (sconn.saved-sigint-handler connection))) + +;;;;;; Simple sequential IO + +(defun simple-serve-requests (connection) + (unwind-protect + (with-connection (connection) + (call-with-user-break-handler + (lambda () + (invoke-or-queue-interrupt + (lambda () (dispatch-interrupt-event connection)))) + (lambda () + (with-simple-restart (close-connection "Close SLIME connection.") + (let* ((stdin (real-input-stream *standard-input*)) + (*standard-input* (make-repl-input-stream connection + stdin))) + (tagbody toplevel + (with-top-level-restart (connection (go toplevel)) + (simple-repl)))))))) + (close-connection connection nil (safe-backtrace)))) + +;; this is signalled when our custom stream thinks the end-of-file is reached. +;; (not when the end-of-file on the socket is reached) +(define-condition end-of-repl-input (end-of-file) ()) + +(defun simple-repl () + (loop + (format t "~a> " (package-string-for-prompt *package*)) + (force-output) + (let ((form (handler-case (read) + (end-of-repl-input () (return))))) + (let ((- form) + (values (multiple-value-list (eval form)))) + (setq *** ** ** * * (car values) + /// // // / / values + +++ ++ ++ + + form) + (cond ((null values) (format t "; No values~&")) + (t (mapc (lambda (v) (format t "~s~&" v)) values))))))) + +(defun make-repl-input-stream (connection stdin) + (make-input-stream + (lambda () (repl-input-stream-read connection stdin)))) + +(defun repl-input-stream-read (connection stdin) + (loop + (let* ((socket (connection.socket-io connection)) + (inputs (list socket stdin)) + (ready (wait-for-input inputs))) + (cond ((eq ready :interrupt) + (check-slime-interrupts)) + ((member socket ready) + ;; A Slime request from Emacs is pending; make sure to + ;; redirect IO to the REPL buffer. + (with-simple-restart (process-input "Continue reading input.") + (let ((*sldb-quit-restart* (find-restart 'process-input))) + (with-io-redirection (connection) + (handle-requests connection t))))) + ((member stdin ready) + ;; User typed something into the *inferior-lisp* buffer, + ;; so do not redirect. + (return (read-non-blocking stdin))) + (t (assert (null ready))))))) + +(defun read-non-blocking (stream) + (with-output-to-string (str) + (handler-case + (loop (let ((c (read-char-no-hang stream))) + (unless c (return)) + (write-char c str))) + (end-of-file () (error 'end-of-repl-input :stream stream))))) + + +;;; Channels + +;; FIXME: should be per connection not global. +(defvar *channels* '()) +(defvar *channel-counter* 0) + +(defclass channel () + ((id :reader channel-id) + (thread :initarg :thread :initform (current-thread) :reader channel-thread) + (name :initarg :name :initform nil))) + +(defmethod initialize-instance :after ((ch channel) &key) + (with-slots (id) ch + (setf id (incf *channel-counter*)) + (push (cons id ch) *channels*))) + +(defmethod print-object ((c channel) stream) + (print-unreadable-object (c stream :type t) + (with-slots (id name) c + (format stream "~d ~a" id name)))) + +(defun find-channel (id) + (cdr (assoc id *channels*))) + +(defgeneric channel-send (channel selector args)) + +(defmacro define-channel-method (selector (channel &rest args) &body body) + `(defmethod channel-send (,channel (selector (eql ',selector)) args) + (destructuring-bind ,args args + . ,body))) + +(defun send-to-remote-channel (channel-id msg) + (send-to-emacs `(:channel-send ,channel-id ,msg))) + + + +(defvar *slime-features* nil + "The feature list that has been sent to Emacs.") + +(defun send-oob-to-emacs (object) + (send-to-emacs object)) + +;; FIXME: belongs to swank-repl.lisp +(defun force-user-output () + (force-output (connection.user-io *emacs-connection*))) + +(add-hook *pre-reply-hook* 'force-user-output) + +;; FIXME: belongs to swank-repl.lisp +(defun clear-user-input () + (clear-input (connection.user-input *emacs-connection*))) + +;; FIXME: not thread save. +(defvar *tag-counter* 0) + +(defun make-tag () + (setq *tag-counter* (mod (1+ *tag-counter*) (expt 2 22)))) + +(defun y-or-n-p-in-emacs (format-string &rest arguments) + "Like y-or-n-p, but ask in the Emacs minibuffer." + (let ((tag (make-tag)) + (question (apply #'format nil format-string arguments))) + (force-output) + (send-to-emacs `(:y-or-n-p ,(current-thread-id) ,tag ,question)) + (third (wait-for-event `(:emacs-return ,tag result))))) + +(defun read-from-minibuffer-in-emacs (prompt &optional initial-value) + "Ask user a question in Emacs' minibuffer. Returns \"\" when user +entered nothing, returns NIL when user pressed C-g." + (check-type prompt string) (check-type initial-value (or null string)) + (let ((tag (make-tag))) + (force-output) + (send-to-emacs `(:read-from-minibuffer ,(current-thread-id) ,tag + ,prompt ,initial-value)) + (third (wait-for-event `(:emacs-return ,tag result))))) + +(defstruct (unreadable-result + (:constructor make-unreadable-result (string)) + (:copier nil) + (:print-object + (lambda (object stream) + (print-unreadable-object (object stream :type t) + (princ (unreadable-result-string object) stream))))) + string) + +(defun symbol-name-for-emacs (symbol) + (check-type symbol symbol) + (let ((name (string-downcase (symbol-name symbol)))) + (if (keywordp symbol) + (concatenate 'string ":" name) + name))) + +(defun process-form-for-emacs (form) + "Returns a string which emacs will read as equivalent to +FORM. FORM can contain lists, strings, characters, symbols and +numbers. + +Characters are converted emacs' ? notaion, strings are left +as they are (except for espacing any nested \" chars, numbers are +printed in base 10 and symbols are printed as their symbol-name +converted to lower case." + (etypecase form + (string (format nil "~S" form)) + (cons (format nil "(~A . ~A)" + (process-form-for-emacs (car form)) + (process-form-for-emacs (cdr form)))) + (character (format nil "?~C" form)) + (symbol (symbol-name-for-emacs form)) + (number (let ((*print-base* 10)) + (princ-to-string form))))) + +(defun wait-for-emacs-return (tag) + (let ((event (caddr (wait-for-event `(:emacs-return ,tag result))))) + (dcase event + ((:unreadable value) (make-unreadable-result value)) + ((:ok value) value) + ((:error kind . data) (error "~a: ~{~a~}" kind data)) + ((:abort) (abort)) + ;; only in reply to :ed-rpc{-no-wait} events. + ((:ed-rpc-forbidden fn) (error "ED-RPC forbidden for ~a" fn))))) + +(defun eval-in-emacs (form &optional nowait) + "Eval FORM in Emacs. +`slime-enable-evaluate-in-emacs' should be set to T on the Emacs side." + (cond (nowait + (send-to-emacs `(:eval-no-wait ,(process-form-for-emacs form)))) + (t + (force-output) + (let ((tag (make-tag))) + (send-to-emacs `(:eval ,(current-thread-id) ,tag + ,(process-form-for-emacs form))) + (wait-for-emacs-return tag))))) + +(defun ed-rpc-no-wait (fn &rest args) + "Invoke FN in Emacs (or some lesser editor) and don't wait for the result." + (send-to-emacs `(:ed-rpc-no-wait ,(symbol-name-for-emacs fn) ,@args)) + (values)) + +(defun ed-rpc (fn &rest args) + "Invoke FN in Emacs (or some lesser editor). FN should be defined in +Emacs Lisp via `defslimefun' or otherwise marked as RPCallable." + (let ((tag (make-tag))) + (send-to-emacs `(:ed-rpc ,(current-thread-id) ,tag + ,(symbol-name-for-emacs fn) + ,@args)) + (wait-for-emacs-return tag))) + +(defvar *swank-wire-protocol-version* nil + "The version of the swank/slime communication protocol.") + +(defslimefun connection-info () + "Return a key-value list of the form: +\(&key PID STYLE LISP-IMPLEMENTATION MACHINE FEATURES PACKAGE VERSION) +PID: is the process-id of Lisp process (or nil, depending on the STYLE) +STYLE: the communication style +LISP-IMPLEMENTATION: a list (&key TYPE NAME VERSION) +FEATURES: a list of keywords +PACKAGE: a list (&key NAME PROMPT) +VERSION: the protocol version" + (let ((c *emacs-connection*)) + (setq *slime-features* *features*) + `(:pid ,(getpid) :style ,(connection.communication-style c) + :encoding (:coding-systems + ,(loop for cs in '("utf-8-unix" "iso-latin-1-unix") + when (find-external-format cs) collect cs)) + :lisp-implementation (:type ,(lisp-implementation-type) + :name ,(lisp-implementation-type-name) + :version ,(lisp-implementation-version) + :program ,(lisp-implementation-program)) + :machine (:instance ,(machine-instance) + :type ,(machine-type) + :version ,(machine-version)) + :features ,(features-for-emacs) + :modules ,*modules* + :package (:name ,(package-name *package*) + :prompt ,(package-string-for-prompt *package*)) + :version ,*swank-wire-protocol-version*))) + +(defun debug-on-swank-error () + (assert (eq *debug-on-swank-protocol-error* *debug-swank-backend*)) + *debug-on-swank-protocol-error*) + +(defun (setf debug-on-swank-error) (new-value) + (setf *debug-on-swank-protocol-error* new-value) + (setf *debug-swank-backend* new-value)) + +(defslimefun toggle-debug-on-swank-error () + (setf (debug-on-swank-error) (not (debug-on-swank-error)))) + + +;;;; Reading and printing + +(define-special *buffer-package* + "Package corresponding to slime-buffer-package. + +EVAL-FOR-EMACS binds *buffer-package*. Strings originating from a slime +buffer are best read in this package. See also FROM-STRING and TO-STRING.") + +(define-special *buffer-readtable* + "Readtable associated with the current buffer") + +(defmacro with-buffer-syntax ((&optional package) &body body) + "Execute BODY with appropriate *package* and *readtable* bindings. + +This should be used for code that is conceptionally executed in an +Emacs buffer." + `(call-with-buffer-syntax ,package (lambda () ,@body))) + +(defun call-with-buffer-syntax (package fun) + (let ((*package* (if package + (guess-buffer-package package) + *buffer-package*))) + ;; Don't shadow *readtable* unnecessarily because that prevents + ;; the user from assigning to it. + (if (eq *readtable* *buffer-readtable*) + (call-with-syntax-hooks fun) + (let ((*readtable* *buffer-readtable*)) + (call-with-syntax-hooks fun))))) + +(defmacro without-printing-errors ((&key object stream + (msg "<>")) + &body body) + "Catches errors during evaluation of BODY and prints MSG instead." + `(handler-case (progn ,@body) + (serious-condition () + ,(cond ((and stream object) + (let ((gstream (gensym "STREAM+"))) + `(let ((,gstream ,stream)) + (print-unreadable-object (,object ,gstream :type t + :identity t) + (write-string ,msg ,gstream))))) + (stream + `(write-string ,msg ,stream)) + (object + `(with-output-to-string (s) + (print-unreadable-object (,object s :type t :identity t) + (write-string ,msg s)))) + (t msg))))) + +(defun to-string (object) + "Write OBJECT in the *BUFFER-PACKAGE*. +The result may not be readable. Handles problems with PRINT-OBJECT methods +gracefully." + (with-buffer-syntax () + (let ((*print-readably* nil)) + (without-printing-errors (:object object :stream nil) + (prin1-to-string object))))) + +(defun from-string (string) + "Read string in the *BUFFER-PACKAGE*" + (with-buffer-syntax () + (let ((*read-suppress* nil)) + (values (read-from-string string))))) + +(defun parse-string (string package) + "Read STRING in PACKAGE." + (with-buffer-syntax (package) + (let ((*read-suppress* nil)) + (read-from-string string)))) + +;; FIXME: deal with #\| etc. hard to do portably. +(defun tokenize-symbol (string) + "STRING is interpreted as the string representation of a symbol +and is tokenized accordingly. The result is returned in three +values: The package identifier part, the actual symbol identifier +part, and a flag if the STRING represents a symbol that is +internal to the package identifier part. (Notice that the flag is +also true with an empty package identifier part, as the STRING is +considered to represent a symbol internal to some current package.)" + (let ((package (let ((pos (position #\: string))) + (if pos (subseq string 0 pos) nil))) + (symbol (let ((pos (position #\: string :from-end t))) + (if pos (subseq string (1+ pos)) string))) + (internp (not (= (count #\: string) 1)))) + (values symbol package internp))) + +(defun tokenize-symbol-thoroughly (string) + "This version of TOKENIZE-SYMBOL handles escape characters." + (let ((package nil) + (token (make-array (length string) :element-type 'character + :fill-pointer 0)) + (backslash nil) + (vertical nil) + (internp nil)) + (loop for char across string do + (cond + (backslash + (vector-push-extend char token) + (setq backslash nil)) + ((char= char #\\) ; Quotes next character, even within |...| + (setq backslash t)) + ((char= char #\|) + (setq vertical (not vertical))) + (vertical + (vector-push-extend char token)) + ((char= char #\:) + (cond ((and package internp) + (return-from tokenize-symbol-thoroughly)) + (package + (setq internp t)) + (t + (setq package token + token (make-array (length string) + :element-type 'character + :fill-pointer 0))))) + (t + (vector-push-extend (casify-char char) token)))) + (unless vertical + (values token package (or (not package) internp))))) + +(defun untokenize-symbol (package-name internal-p symbol-name) + "The inverse of TOKENIZE-SYMBOL. + + (untokenize-symbol \"quux\" nil \"foo\") ==> \"quux:foo\" + (untokenize-symbol \"quux\" t \"foo\") ==> \"quux::foo\" + (untokenize-symbol nil nil \"foo\") ==> \"foo\" +" + (cond ((not package-name) symbol-name) + (internal-p (cat package-name "::" symbol-name)) + (t (cat package-name ":" symbol-name)))) + +(defun casify-char (char) + "Convert CHAR accoring to readtable-case." + (ecase (readtable-case *readtable*) + (:preserve char) + (:upcase (char-upcase char)) + (:downcase (char-downcase char)) + (:invert (if (upper-case-p char) + (char-downcase char) + (char-upcase char))))) + + +(defun find-symbol-with-status (symbol-name status + &optional (package *package*)) + (multiple-value-bind (symbol flag) (find-symbol symbol-name package) + (if (and flag (eq flag status)) + (values symbol flag) + (values nil nil)))) + +(defun parse-symbol (string &optional (package *package*)) + "Find the symbol named STRING. +Return the symbol and a flag indicating whether the symbols was found." + (multiple-value-bind (sname pname internalp) + (tokenize-symbol-thoroughly string) + (when sname + (let ((package (cond ((string= pname "") keyword-package) + (pname (find-package pname)) + (t package)))) + (if package + (multiple-value-bind (symbol flag) + (if internalp + (find-symbol sname package) + (find-symbol-with-status sname ':external package)) + (values symbol flag sname package)) + (values nil nil nil nil)))))) + +(defun parse-symbol-or-lose (string &optional (package *package*)) + (multiple-value-bind (symbol status) (parse-symbol string package) + (if status + (values symbol status) + (error "Unknown symbol: ~A [in ~A]" string package)))) + +(defun parse-package (string) + "Find the package named STRING. +Return the package or nil." + ;; STRING comes usually from a (in-package STRING) form. + (ignore-errors + (find-package (let ((*package* *swank-io-package*)) + (read-from-string string))))) + +(defun unparse-name (string) + "Print the name STRING according to the current printer settings." + ;; this is intended for package or symbol names + (subseq (prin1-to-string (make-symbol string)) 2)) + +(defun guess-package (string) + "Guess which package corresponds to STRING. +Return nil if no package matches." + (when string + (or (find-package string) + (parse-package string) + (if (find #\! string) ; for SBCL + (guess-package (substitute #\- #\! string)))))) + +(defvar *readtable-alist* (default-readtable-alist) + "An alist mapping package names to readtables.") + +(defun guess-buffer-readtable (package-name) + (let ((package (guess-package package-name))) + (or (and package + (cdr (assoc (package-name package) *readtable-alist* + :test #'string=))) + *readtable*))) + + +;;;; Evaluation + +(defvar *pending-continuations* '() + "List of continuations for Emacs. (thread local)") + +(defun guess-buffer-package (string) + "Return a package for STRING. +Fall back to the current if no such package exists." + (or (and string (guess-package string)) + *package*)) + +(defun eval-for-emacs (form buffer-package id) + "Bind *BUFFER-PACKAGE* to BUFFER-PACKAGE and evaluate FORM. +Return the result to the continuation ID. +Errors are trapped and invoke our debugger." + (let (ok result condition) + (unwind-protect + (let ((*buffer-package* (guess-buffer-package buffer-package)) + (*buffer-readtable* (guess-buffer-readtable buffer-package)) + (*pending-continuations* (cons id *pending-continuations*))) + (check-type *buffer-package* package) + (check-type *buffer-readtable* readtable) + ;; APPLY would be cleaner than EVAL. + ;; (setq result (apply (car form) (cdr form))) + (handler-bind ((t (lambda (c) (setf condition c)))) + (setq result (with-slime-interrupts (eval form)))) + (run-hook *pre-reply-hook*) + (setq ok t)) + (send-to-emacs `(:return ,(current-thread) + ,(if ok + `(:ok ,result) + `(:abort ,(prin1-to-string condition))) + ,id))))) + +(defvar *echo-area-prefix* "=> " + "A prefix that `format-values-for-echo-area' should use.") + +(defun format-values-for-echo-area (values) + (with-buffer-syntax () + (let ((*print-readably* nil)) + (cond ((null values) "; No value") + ((and (integerp (car values)) (null (cdr values))) + (let ((i (car values))) + (format nil "~A~D (~a bit~:p, #x~X, #o~O, #b~B)" + *echo-area-prefix* + i (integer-length i) i i i))) + ((and (typep (car values) 'ratio) + (null (cdr values)) + (ignore-errors + ;; The ratio may be to large to be represented as a single float + (format nil "~A~D (~:*~f)" + *echo-area-prefix* + (car values))))) + (t (format nil "~a~{~S~^, ~}" *echo-area-prefix* values)))))) + +(defmacro values-to-string (values) + `(format-values-for-echo-area (multiple-value-list ,values))) + +(defslimefun interactive-eval (string) + (with-buffer-syntax () + (with-retry-restart (:msg "Retry SLIME interactive evaluation request.") + (let ((values (multiple-value-list (eval (from-string string))))) + (finish-output) + (format-values-for-echo-area values))))) + +(defslimefun eval-and-grab-output (string) + (with-buffer-syntax () + (with-retry-restart (:msg "Retry SLIME evaluation request.") + (let* ((s (make-string-output-stream)) + (*standard-output* s) + (values (multiple-value-list (eval (from-string string))))) + (list (get-output-stream-string s) + (format nil "~{~S~^~%~}" values)))))) + +(defun eval-region (string) + "Evaluate STRING. +Return the results of the last form as a list and as secondary value the +last form." + (with-input-from-string (stream string) + (let (- values) + (loop + (let ((form (read stream nil stream))) + (when (eq form stream) + (finish-output) + (return (values values -))) + (setq - form) + (setq values (multiple-value-list (eval form))) + (finish-output)))))) + +(defslimefun interactive-eval-region (string) + (with-buffer-syntax () + (with-retry-restart (:msg "Retry SLIME interactive evaluation request.") + (format-values-for-echo-area (eval-region string))))) + +(defslimefun re-evaluate-defvar (form) + (with-buffer-syntax () + (with-retry-restart (:msg "Retry SLIME evaluation request.") + (let ((form (read-from-string form))) + (destructuring-bind (dv name &optional value doc) form + (declare (ignore value doc)) + (assert (eq dv 'defvar)) + (makunbound name) + (prin1-to-string (eval form))))))) + +(defvar *swank-pprint-bindings* + `((*print-pretty* . t) + (*print-level* . nil) + (*print-length* . nil) + (*print-circle* . t) + (*print-gensym* . t) + (*print-readably* . nil)) + "A list of variables bindings during pretty printing. +Used by pprint-eval.") + +(defun swank-pprint (values) + "Bind some printer variables and pretty print each object in VALUES." + (with-buffer-syntax () + (with-bindings *swank-pprint-bindings* + (cond ((null values) "; No value") + (t (with-output-to-string (*standard-output*) + (dolist (o values) + (pprint o) + (terpri)))))))) + +(defslimefun pprint-eval (string) + (with-buffer-syntax () + (let* ((s (make-string-output-stream)) + (values + (let ((*standard-output* s) + (*trace-output* s)) + (multiple-value-list (eval (read-from-string string)))))) + (cat (get-output-stream-string s) + (swank-pprint values))))) + +(defslimefun set-package (name) + "Set *package* to the package named NAME. +Return the full package-name and the string to use in the prompt." + (let ((p (guess-package name))) + (assert (packagep p) nil "Package ~a doesn't exist." name) + (setq *package* p) + (list (package-name p) (package-string-for-prompt p)))) + +(defun cat (&rest strings) + "Concatenate all arguments and make the result a string." + (with-output-to-string (out) + (dolist (s strings) + (etypecase s + (string (write-string s out)) + (character (write-char s out)))))) + +(defun truncate-string (string width &optional ellipsis) + (let ((len (length string))) + (cond ((< len width) string) + (ellipsis (cat (subseq string 0 width) ellipsis)) + (t (subseq string 0 width))))) + +(defun call/truncated-output-to-string (length function + &optional (ellipsis "..")) + "Call FUNCTION with a new stream, return the output written to the stream. +If FUNCTION tries to write more than LENGTH characters, it will be +aborted and return immediately with the output written so far." + (let ((buffer (make-string (+ length (length ellipsis)))) + (fill-pointer 0)) + (block buffer-full + (flet ((write-output (string) + (let* ((free (- length fill-pointer)) + (count (min free (length string)))) + (replace buffer string :start1 fill-pointer :end2 count) + (incf fill-pointer count) + (when (> (length string) free) + (replace buffer ellipsis :start1 fill-pointer) + (return-from buffer-full buffer))))) + (let ((stream (make-output-stream #'write-output))) + (funcall function stream) + (finish-output stream) + (subseq buffer 0 fill-pointer)))))) + +(defmacro with-string-stream ((var &key length bindings) + &body body) + (cond ((and (not bindings) (not length)) + `(with-output-to-string (,var) . ,body)) + ((not bindings) + `(call/truncated-output-to-string + ,length (lambda (,var) . ,body))) + (t + `(with-bindings ,bindings + (with-string-stream (,var :length ,length) + . ,body))))) + +(defun to-line (object &optional width) + "Print OBJECT to a single line. Return the string." + (let ((width (or width 512))) + (without-printing-errors (:object object :stream nil) + (with-string-stream (stream :length width) + (write object :stream stream :right-margin width :lines 1))))) + +(defun escape-string (string stream &key length (map '((#\" . "\\\"") + (#\\ . "\\\\")))) + "Write STRING to STREAM surronded by double-quotes. +LENGTH -- if non-nil truncate output after LENGTH chars. +MAP -- rewrite the chars in STRING according to this alist." + (let ((limit (or length array-dimension-limit))) + (write-char #\" stream) + (loop for c across string + for i from 0 do + (when (= i limit) + (write-string "..." stream) + (return)) + (let ((probe (assoc c map))) + (cond (probe (write-string (cdr probe) stream)) + (t (write-char c stream))))) + (write-char #\" stream))) + + +;;;; Prompt + +;; FIXME: do we really need 45 lines of code just to figure out the +;; prompt? + +(defvar *canonical-package-nicknames* + `((:common-lisp-user . :cl-user)) + "Canonical package names to use instead of shortest name/nickname.") + +(defvar *auto-abbreviate-dotted-packages* t + "Abbreviate dotted package names to their last component if T.") + +(defun package-string-for-prompt (package) + "Return the shortest nickname (or canonical name) of PACKAGE." + (unparse-name + (or (canonical-package-nickname package) + (auto-abbreviated-package-name package) + (shortest-package-nickname package)))) + +(defun canonical-package-nickname (package) + "Return the canonical package nickname, if any, of PACKAGE." + (let ((name (cdr (assoc (package-name package) *canonical-package-nicknames* + :test #'string=)))) + (and name (string name)))) + +(defun auto-abbreviated-package-name (package) + "Return an abbreviated 'name' for PACKAGE. + +N.B. this is not an actual package name or nickname." + (when *auto-abbreviate-dotted-packages* + (loop with package-name = (package-name package) + with offset = nil + do (let ((last-dot-pos (position #\. package-name :end offset + :from-end t))) + (unless last-dot-pos + (return nil)) + ;; If a dot chunk contains only numbers, that chunk most + ;; likely represents a version number; so we collect the + ;; next chunks, too, until we find one with meat. + (let ((name (subseq package-name (1+ last-dot-pos) offset))) + (if (notevery #'digit-char-p name) + (return (subseq package-name (1+ last-dot-pos))) + (setq offset last-dot-pos))))))) + +(defun shortest-package-nickname (package) + "Return the shortest nickname of PACKAGE." + (loop for name in (cons (package-name package) (package-nicknames package)) + for shortest = name then (if (< (length name) (length shortest)) + name + shortest) + finally (return shortest))) + + + +(defslimefun ed-in-emacs (&optional what) + "Edit WHAT in Emacs. + +WHAT can be: + A pathname or a string, + A list (PATHNAME-OR-STRING &key LINE COLUMN POSITION), + A function name (symbol or cons), + NIL. " + (flet ((canonicalize-filename (filename) + (pathname-to-filename (or (probe-file filename) filename)))) + (let ((target + (etypecase what + (null nil) + ((or string pathname) + `(:filename ,(canonicalize-filename what))) + ((cons (or string pathname) *) + `(:filename ,(canonicalize-filename (car what)) ,@(cdr what))) + ((or symbol cons) + `(:function-name ,(prin1-to-string what)))))) + (cond (*emacs-connection* (send-oob-to-emacs `(:ed ,target))) + ((default-connection) + (with-connection ((default-connection)) + (send-oob-to-emacs `(:ed ,target)))) + (t (error "No connection")))))) + +(defslimefun inspect-in-emacs (what &key wait) + "Inspect WHAT in Emacs. If WAIT is true (default NIL) blocks until the +inspector has been closed in Emacs." + (flet ((send-it () + (let ((tag (when wait (make-tag))) + (thread (when wait (current-thread-id)))) + (with-buffer-syntax () + (reset-inspector) + (send-oob-to-emacs `(:inspect ,(inspect-object what) + ,thread + ,tag))) + (when wait + (wait-for-event `(:emacs-return ,tag result)))))) + (cond + (*emacs-connection* + (send-it)) + ((default-connection) + (with-connection ((default-connection)) + (send-it)))) + what)) + +(defslimefun value-for-editing (form) + "Return a readable value of FORM for editing in Emacs. +FORM is expected, but not required, to be SETF'able." + ;; FIXME: Can we check FORM for setfability? -luke (12/Mar/2005) + (with-buffer-syntax () + (let* ((value (eval (read-from-string form))) + (*print-length* nil)) + (prin1-to-string value)))) + +(defslimefun commit-edited-value (form value) + "Set the value of a setf'able FORM to VALUE. +FORM and VALUE are both strings from Emacs." + (with-buffer-syntax () + (eval `(setf ,(read-from-string form) + ,(read-from-string (concatenate 'string "`" value)))) + t)) + +(defun background-message (format-string &rest args) + "Display a message in Emacs' echo area. + +Use this function for informative messages only. The message may even +be dropped if we are too busy with other things." + (when *emacs-connection* + (send-to-emacs `(:background-message + ,(apply #'format nil format-string args))))) + +;; This is only used by the test suite. +(defun sleep-for (seconds) + "Sleep for at least SECONDS seconds. +This is just like cl:sleep but guarantees to sleep +at least SECONDS." + (let* ((start (get-internal-real-time)) + (end (+ start + (* seconds internal-time-units-per-second)))) + (loop + (let ((now (get-internal-real-time))) + (cond ((< end now) (return)) + (t (sleep (/ (- end now) + internal-time-units-per-second)))))))) + + +;;;; Debugger + +(defun invoke-slime-debugger (condition) + "Sends a message to Emacs declaring that the debugger has been entered, +then waits to handle further requests from Emacs. Eventually returns +after Emacs causes a restart to be invoked." + (without-slime-interrupts + (cond (*emacs-connection* + (debug-in-emacs condition)) + ((default-connection) + (with-connection ((default-connection)) + (debug-in-emacs condition)))))) + +(define-condition invoke-default-debugger () ()) + +(defun swank-debugger-hook (condition hook) + "Debugger function for binding *DEBUGGER-HOOK*." + (declare (ignore hook)) + (handler-case + (call-with-debugger-hook #'swank-debugger-hook + (lambda () (invoke-slime-debugger condition))) + (invoke-default-debugger () + (invoke-default-debugger condition)))) + +(defun invoke-default-debugger (condition) + (call-with-debugger-hook nil (lambda () (invoke-debugger condition)))) + +(defvar *global-debugger* t + "Non-nil means the Swank debugger hook will be installed globally.") + +(add-hook *new-connection-hook* 'install-debugger) +(defun install-debugger (connection) + (declare (ignore connection)) + (when *global-debugger* + (install-debugger-globally #'swank-debugger-hook))) + +;;;;; Debugger loop +;;; +;;; These variables are dynamically bound during debugging. +;;; +(defvar *swank-debugger-condition* nil + "The condition being debugged.") + +(defvar *sldb-level* 0 + "The current level of recursive debugging.") + +(defvar *sldb-initial-frames* 20 + "The initial number of backtrace frames to send to Emacs.") + +(defvar *sldb-restarts* nil + "The list of currenlty active restarts.") + +(defvar *sldb-stepping-p* nil + "True during execution of a step command.") + +(defun debug-in-emacs (condition) + (let ((*swank-debugger-condition* condition) + (*sldb-restarts* (compute-restarts condition)) + (*sldb-quit-restart* (and *sldb-quit-restart* + (find-restart *sldb-quit-restart*))) + (*package* (or (and (boundp '*buffer-package*) + (symbol-value '*buffer-package*)) + *package*)) + (*sldb-level* (1+ *sldb-level*)) + (*sldb-stepping-p* nil)) + (force-user-output) + (call-with-debugging-environment + (lambda () + (sldb-loop *sldb-level*))))) + +(defun sldb-loop (level) + (unwind-protect + (loop + (with-simple-restart (abort "Return to sldb level ~D." level) + (send-to-emacs + (list* :debug (current-thread-id) level + (debugger-info-for-emacs 0 *sldb-initial-frames*))) + (send-to-emacs + (list :debug-activate (current-thread-id) level nil)) + (loop + (handler-case + (dcase (wait-for-event + `(or (:emacs-rex . _) + (:sldb-return ,(1+ level)))) + ((:emacs-rex &rest args) (apply #'eval-for-emacs args)) + ((:sldb-return _) (declare (ignore _)) (return nil))) + (sldb-condition (c) + (handle-sldb-condition c)))))) + (send-to-emacs `(:debug-return + ,(current-thread-id) ,level ,*sldb-stepping-p*)) + (wait-for-event `(:sldb-return ,(1+ level)) t) ; clean event-queue + (when (> level 1) + (send-event (current-thread) `(:sldb-return ,level))))) + +(defun handle-sldb-condition (condition) + "Handle an internal debugger condition. +Rather than recursively debug the debugger (a dangerous idea!), these +conditions are simply reported." + (let ((real-condition (original-condition condition))) + (send-to-emacs `(:debug-condition ,(current-thread-id) + ,(princ-to-string real-condition))))) + +(defun %%condition-message (condition) + (let ((limit (ash 1 16))) + (with-string-stream (stream :length limit) + (handler-case + (let ((*print-readably* nil) + (*print-pretty* t) + (*print-right-margin* 65) + (*print-circle* t) + (*print-length* (or *print-length* limit)) + (*print-level* (or *print-level* limit)) + (*print-lines* (or *print-lines* limit))) + (print-condition condition stream)) + (serious-condition (c) + (ignore-errors + (with-standard-io-syntax + (let ((*print-readably* nil)) + (format stream "~&Error (~a) during printing: " (type-of c)) + (print-unreadable-object (condition stream :type t + :identity t)))))))))) + +(defun %condition-message (condition) + (string-trim #(#\newline #\space #\tab) + (%%condition-message condition))) + +(defvar *sldb-condition-printer* #'%condition-message + "Function called to print a condition to an SLDB buffer.") + +(defun safe-condition-message (condition) + "Print condition to a string, handling any errors during printing." + (funcall *sldb-condition-printer* condition)) + +(defun debugger-condition-for-emacs () + (list (safe-condition-message *swank-debugger-condition*) + (format nil " [Condition of type ~S]" + (type-of *swank-debugger-condition*)) + (condition-extras *swank-debugger-condition*))) + +(defun format-restarts-for-emacs () + "Return a list of restarts for *swank-debugger-condition* in a +format suitable for Emacs." + (let ((*print-right-margin* most-positive-fixnum)) + (loop for restart in *sldb-restarts* collect + (list (format nil "~:[~;*~]~a" + (eq restart *sldb-quit-restart*) + (restart-name restart)) + (with-output-to-string (stream) + (without-printing-errors (:object restart + :stream stream + :msg "<>") + (princ restart stream))))))) + +;;;;; SLDB entry points + +(defslimefun sldb-break-with-default-debugger (dont-unwind) + "Invoke the default debugger." + (cond (dont-unwind + (invoke-default-debugger *swank-debugger-condition*)) + (t + (signal 'invoke-default-debugger)))) + +(defslimefun backtrace (start end) + "Return a list ((I FRAME PLIST) ...) of frames from START to END. + +I is an integer, and can be used to reference the corresponding frame +from Emacs; FRAME is a string representation of an implementation's +frame." + (loop for frame in (compute-backtrace start end) + for i from start collect + (list* i (frame-to-string frame) + (ecase (frame-restartable-p frame) + ((nil) nil) + ((t) `((:restartable t))))))) + +(defun frame-to-string (frame) + (with-string-stream (stream :length (* (or *print-lines* 1) + (or *print-right-margin* 100)) + :bindings *backtrace-printer-bindings*) + (handler-case (print-frame frame stream) + (serious-condition () + (format stream "[error printing frame]"))))) + +(defslimefun debugger-info-for-emacs (start end) + "Return debugger state, with stack frames from START to END. +The result is a list: + (condition ({restart}*) ({stack-frame}*) (cont*)) +where + condition ::= (description type [extra]) + restart ::= (name description) + stack-frame ::= (number description [plist]) + extra ::= (:references and other random things) + cont ::= continutation + plist ::= (:restartable {nil | t | :unknown}) + +condition---a pair of strings: message, and type. If show-source is +not nil it is a frame number for which the source should be displayed. + +restart---a pair of strings: restart name, and description. + +stack-frame---a number from zero (the top), and a printed +representation of the frame's call. + +continutation---the id of a pending Emacs continuation. + +Below is an example return value. In this case the condition was a +division by zero (multi-line description), and only one frame is being +fetched (start=0, end=1). + + ((\"Arithmetic error DIVISION-BY-ZERO signalled. +Operation was KERNEL::DIVISION, operands (1 0).\" + \"[Condition of type DIVISION-BY-ZERO]\") + ((\"ABORT\" \"Return to Slime toplevel.\") + (\"ABORT\" \"Return to Top-Level.\")) + ((0 \"(KERNEL::INTEGER-/-INTEGER 1 0)\" (:restartable nil))) + (4))" + (list (debugger-condition-for-emacs) + (format-restarts-for-emacs) + (backtrace start end) + *pending-continuations*)) + +(defun nth-restart (index) + (nth index *sldb-restarts*)) + +(defslimefun invoke-nth-restart (index) + (let ((restart (nth-restart index))) + (when restart + (invoke-restart-interactively restart)))) + +(defslimefun sldb-abort () + (invoke-restart (find 'abort *sldb-restarts* :key #'restart-name))) + +(defslimefun sldb-continue () + (continue)) + +(defun coerce-to-condition (datum args) + (etypecase datum + (string (make-condition 'simple-error :format-control datum + :format-arguments args)) + (symbol (apply #'make-condition datum args)))) + +(defslimefun simple-break (&optional (datum "Interrupt from Emacs") &rest args) + (with-simple-restart (continue "Continue from break.") + (invoke-slime-debugger (coerce-to-condition datum args)))) + +;; FIXME: (last (compute-restarts)) looks dubious. +(defslimefun throw-to-toplevel () + "Invoke the ABORT-REQUEST restart abort an RPC from Emacs. +If we are not evaluating an RPC then ABORT instead." + (let ((restart (or (and *sldb-quit-restart* + (find-restart *sldb-quit-restart*)) + (car (last (compute-restarts)))))) + (cond (restart (invoke-restart restart)) + (t (format nil "Restart not active [~s]" *sldb-quit-restart*))))) + +(defslimefun invoke-nth-restart-for-emacs (sldb-level n) + "Invoke the Nth available restart. +SLDB-LEVEL is the debug level when the request was made. If this +has changed, ignore the request." + (when (= sldb-level *sldb-level*) + (invoke-nth-restart n))) + +(defun wrap-sldb-vars (form) + `(let ((*sldb-level* ,*sldb-level*)) + ,form)) + +(defun eval-in-frame-aux (frame string package print) + (let* ((form (wrap-sldb-vars (parse-string string package))) + (values (multiple-value-list (eval-in-frame form frame)))) + (with-buffer-syntax (package) + (funcall print values)))) + +(defslimefun eval-string-in-frame (string frame package) + (eval-in-frame-aux frame string package #'format-values-for-echo-area)) + +(defslimefun pprint-eval-string-in-frame (string frame package) + (eval-in-frame-aux frame string package #'swank-pprint)) + +(defslimefun frame-package-name (frame) + (let ((pkg (frame-package frame))) + (cond (pkg (package-name pkg)) + (t (with-buffer-syntax () (package-name *package*)))))) + +(defslimefun frame-locals-and-catch-tags (index) + "Return a list (LOCALS TAGS) for vars and catch tags in the frame INDEX. +LOCALS is a list of the form ((&key NAME ID VALUE) ...). +TAGS has is a list of strings." + (list (frame-locals-for-emacs index) + (mapcar #'to-string (frame-catch-tags index)))) + +(defun frame-locals-for-emacs (index) + (with-bindings *backtrace-printer-bindings* + (loop for var in (frame-locals index) collect + (destructuring-bind (&key name id value) var + (list :name (let ((*package* (or (frame-package index) *package*))) + (prin1-to-string name)) + :id id + :value (to-line value *print-right-margin*)))))) + +(defslimefun sldb-disassemble (index) + (with-output-to-string (*standard-output*) + (disassemble-frame index))) + +(defslimefun sldb-return-from-frame (index string) + (let ((form (from-string string))) + (to-string (multiple-value-list (return-from-frame index form))))) + +(defslimefun sldb-break (name) + (with-buffer-syntax () + (sldb-break-at-start (read-from-string name)))) + +(defmacro define-stepper-function (name backend-function-name) + `(defslimefun ,name (frame) + (cond ((sldb-stepper-condition-p *swank-debugger-condition*) + (setq *sldb-stepping-p* t) + (,backend-function-name)) + ((find-restart 'continue) + (activate-stepping frame) + (setq *sldb-stepping-p* t) + (continue)) + (t + (error "Not currently single-stepping, ~ +and no continue restart available."))))) + +(define-stepper-function sldb-step sldb-step-into) +(define-stepper-function sldb-next sldb-step-next) +(define-stepper-function sldb-out sldb-step-out) + +(defslimefun toggle-break-on-signals () + (setq *break-on-signals* (not *break-on-signals*)) + (format nil "*break-on-signals* = ~a" *break-on-signals*)) + +(defslimefun sdlb-print-condition () + (princ-to-string *swank-debugger-condition*)) + + +;;;; Compilation Commands. + +(defstruct (compilation-result (:type list)) + (type :compilation-result) + notes + (successp nil :type boolean) + (duration 0.0 :type float) + (loadp nil :type boolean) + (faslfile nil :type (or null string))) + +(defun measure-time-interval (fun) + "Call FUN and return the first return value and the elapsed time. +The time is measured in seconds." + (declare (type function fun)) + (let ((before (get-internal-real-time))) + (values + (funcall fun) + (/ (- (get-internal-real-time) before) + (coerce internal-time-units-per-second 'float))))) + +(defun make-compiler-note (condition) + "Make a compiler note data structure from a compiler-condition." + (declare (type compiler-condition condition)) + (list* :message (message condition) + :severity (severity condition) + :location (location condition) + :references (references condition) + (let ((s (source-context condition))) + (if s (list :source-context s))))) + +(defun collect-notes (function) + (let ((notes '())) + (multiple-value-bind (result seconds) + (handler-bind ((compiler-condition + (lambda (c) (push (make-compiler-note c) notes)))) + (measure-time-interval + (lambda () + ;; To report location of error-signaling toplevel forms + ;; for errors in EVAL-WHEN or during macroexpansion. + (restart-case (multiple-value-list (funcall function)) + (abort () :report "Abort compilation." (list nil)))))) + (destructuring-bind (successp &optional loadp faslfile) result + (let ((faslfile (etypecase faslfile + (null nil) + (pathname (pathname-to-filename faslfile))))) + (make-compilation-result :notes (reverse notes) + :duration seconds + :successp (if successp t) + :loadp (if loadp t) + :faslfile faslfile)))))) + +(defun swank-compile-file* (pathname load-p &rest options &key policy + &allow-other-keys) + (multiple-value-bind (output-pathname warnings? failure?) + (swank-compile-file pathname + (fasl-pathname pathname options) + nil + (or (guess-external-format pathname) + :default) + :policy policy) + (declare (ignore warnings?)) + (values t (not failure?) load-p output-pathname))) + +(defvar *compile-file-for-emacs-hook* '(swank-compile-file*)) + +(defslimefun compile-file-for-emacs (filename load-p &rest options) + "Compile FILENAME and, when LOAD-P, load the result. +Record compiler notes signalled as `compiler-condition's." + (with-buffer-syntax () + (collect-notes + (lambda () + (let ((pathname (filename-to-pathname filename)) + (*compile-print* nil) + (*compile-verbose* t)) + (loop for hook in *compile-file-for-emacs-hook* + do + (multiple-value-bind (tried success load? output-pathname) + (apply hook pathname load-p options) + (when tried + (return (values success load? output-pathname)))))))))) + +;; FIXME: now that *compile-file-for-emacs-hook* is there this is +;; redundant and confusing. +(defvar *fasl-pathname-function* nil + "In non-nil, use this function to compute the name for fasl-files.") + +(defun pathname-as-directory (pathname) + (append (pathname-directory pathname) + (when (pathname-name pathname) + (list (file-namestring pathname))))) + +(defun compile-file-output (file directory) + (make-pathname :directory (pathname-as-directory directory) + :defaults (compile-file-pathname file))) + +(defun fasl-pathname (input-file options) + (cond (*fasl-pathname-function* + (funcall *fasl-pathname-function* input-file options)) + ((getf options :fasl-directory) + (let ((dir (getf options :fasl-directory))) + (assert (char= (aref dir (1- (length dir))) #\/)) + (compile-file-output input-file dir))) + (t + (compile-file-pathname input-file)))) + +(defslimefun compile-string-for-emacs (string buffer position filename policy) + "Compile STRING (exerpted from BUFFER at POSITION). +Record compiler notes signalled as `compiler-condition's." + (let ((offset (cadr (assoc :position position)))) + (with-buffer-syntax () + (collect-notes + (lambda () + (let ((*compile-print* t) (*compile-verbose* nil)) + (swank-compile-string string + :buffer buffer + :position offset + :filename filename + :policy policy))))))) + +(defslimefun compile-multiple-strings-for-emacs (strings policy) + "Compile STRINGS (exerpted from BUFFER at POSITION). +Record compiler notes signalled as `compiler-condition's." + (loop for (string buffer package position filename) in strings collect + (collect-notes + (lambda () + (with-buffer-syntax (package) + (let ((*compile-print* t) (*compile-verbose* nil)) + (swank-compile-string string + :buffer buffer + :position position + :filename filename + :policy policy))))))) + +(defun file-newer-p (new-file old-file) + "Returns true if NEW-FILE is newer than OLD-FILE." + (> (file-write-date new-file) (file-write-date old-file))) + +(defun requires-compile-p (source-file) + (let ((fasl-file (probe-file (compile-file-pathname source-file)))) + (or (not fasl-file) + (file-newer-p source-file fasl-file)))) + +(defslimefun compile-file-if-needed (filename loadp) + (let ((pathname (filename-to-pathname filename))) + (cond ((requires-compile-p pathname) + (compile-file-for-emacs pathname loadp)) + (t + (collect-notes + (lambda () + (or (not loadp) + (load (compile-file-pathname pathname))))))))) + + +;;;; Loading + +(defslimefun load-file (filename) + (to-string (load (filename-to-pathname filename)))) + + +;;;;; swank-require + +(defslimefun swank-require (modules &optional filename) + "Load the module MODULE." + (dolist (module (ensure-list modules)) + (unless (member (string module) *modules* :test #'string=) + (require module (if filename + (filename-to-pathname filename) + (module-filename module))) + (assert (member (string module) *modules* :test #'string=) + () "Required module ~s was not provided" module))) + *modules*) + +(defvar *find-module* 'find-module + "Pluggable function to locate modules. +The function receives a module name as argument and should return +the filename of the module (or nil if the file doesn't exist).") + +(defun module-filename (module) + "Return the filename for the module MODULE." + (or (funcall *find-module* module) + (error "Can't locate module: ~s" module))) + +;;;;;; Simple *find-module* function. + +(defun merged-directory (dirname defaults) + (pathname-directory + (merge-pathnames + (make-pathname :directory `(:relative ,dirname) :defaults defaults) + defaults))) + +(defvar *load-path* '() + "A list of directories to search for modules.") + +(defun module-candidates (name dir) + (list (compile-file-pathname (make-pathname :name name :defaults dir)) + (make-pathname :name name :type "lisp" :defaults dir))) + +(defun find-module (module) + (let ((name (string-downcase module))) + (some (lambda (dir) (some #'probe-file (module-candidates name dir))) + *load-path*))) + + +;;;; Macroexpansion + +(defvar *macroexpand-printer-bindings* + '((*print-circle* . nil) + (*print-pretty* . t) + (*print-escape* . t) + (*print-lines* . nil) + (*print-level* . nil) + (*print-length* . nil))) + +(defun apply-macro-expander (expander string) + (with-buffer-syntax () + (with-bindings *macroexpand-printer-bindings* + (prin1-to-string (funcall expander (from-string string)))))) + +(defslimefun swank-macroexpand-1 (string) + (apply-macro-expander #'macroexpand-1 string)) + +(defslimefun swank-macroexpand (string) + (apply-macro-expander #'macroexpand string)) + +(defslimefun swank-macroexpand-all (string) + (apply-macro-expander #'macroexpand-all string)) + +(defslimefun swank-compiler-macroexpand-1 (string) + (apply-macro-expander #'compiler-macroexpand-1 string)) + +(defslimefun swank-compiler-macroexpand (string) + (apply-macro-expander #'compiler-macroexpand string)) + +(defslimefun swank-expand-1 (string) + (apply-macro-expander #'expand-1 string)) + +(defslimefun swank-expand (string) + (apply-macro-expander #'expand string)) + +(defun expand-1 (form) + (multiple-value-bind (expansion expanded?) (macroexpand-1 form) + (if expanded? + (values expansion t) + (compiler-macroexpand-1 form)))) + +(defun expand (form) + (expand-repeatedly #'expand-1 form)) + +(defun expand-repeatedly (expander form) + (loop + (multiple-value-bind (expansion expanded?) (funcall expander form) + (unless expanded? (return expansion)) + (setq form expansion)))) + +(defslimefun swank-format-string-expand (string) + (apply-macro-expander #'format-string-expand string)) + +(defslimefun disassemble-form (form) + (with-buffer-syntax () + (with-output-to-string (*standard-output*) + (let ((*print-readably* nil)) + (disassemble (eval (read-from-string form))))))) + + +;;;; Simple completion + +(defslimefun simple-completions (prefix package) + "Return a list of completions for the string PREFIX." + (let ((strings (all-completions prefix package))) + (list strings (longest-common-prefix strings)))) + +(defun all-completions (prefix package) + (multiple-value-bind (name pname intern) (tokenize-symbol prefix) + (let* ((extern (and pname (not intern))) + (pkg (cond ((equal pname "") keyword-package) + ((not pname) (guess-buffer-package package)) + (t (guess-package pname)))) + (test (lambda (sym) (prefix-match-p name (symbol-name sym)))) + (syms (and pkg (matching-symbols pkg extern test))) + (strings (loop for sym in syms + for str = (unparse-symbol sym) + when (prefix-match-p name str) ; remove |Foo| + collect str))) + (format-completion-set strings intern pname)))) + +(defun matching-symbols (package external test) + (let ((test (if external + (lambda (s) + (and (symbol-external-p s package) + (funcall test s))) + test)) + (result '())) + (do-symbols (s package) + (when (funcall test s) + (push s result))) + (remove-duplicates result))) + +(defun unparse-symbol (symbol) + (let ((*print-case* (case (readtable-case *readtable*) + (:downcase :upcase) + (t :downcase)))) + (unparse-name (symbol-name symbol)))) + +(defun prefix-match-p (prefix string) + "Return true if PREFIX is a prefix of STRING." + (not (mismatch prefix string :end2 (min (length string) (length prefix)) + :test #'char-equal))) + +(defun longest-common-prefix (strings) + "Return the longest string that is a common prefix of STRINGS." + (if (null strings) + "" + (flet ((common-prefix (s1 s2) + (let ((diff-pos (mismatch s1 s2))) + (if diff-pos (subseq s1 0 diff-pos) s1)))) + (reduce #'common-prefix strings)))) + +(defun format-completion-set (strings internal-p package-name) + "Format a set of completion strings. +Returns a list of completions with package qualifiers if needed." + (mapcar (lambda (string) (untokenize-symbol package-name internal-p string)) + (sort strings #'string<))) + + +;;;; Simple arglist display + +(defslimefun operator-arglist (name package) + (ignore-errors + (let ((args (arglist (parse-symbol name (guess-buffer-package package))))) + (cond ((eq args :not-available) nil) + (t (princ-to-string (cons name args))))))) + + +;;;; Documentation + +(defslimefun apropos-list-for-emacs (name &optional external-only + case-sensitive package) + "Make an apropos search for Emacs. +The result is a list of property lists." + (let ((package (if package + (or (parse-package package) + (error "No such package: ~S" package))))) + ;; The MAPCAN will filter all uninteresting symbols, i.e. those + ;; who cannot be meaningfully described. + (mapcan (listify #'briefly-describe-symbol-for-emacs) + (sort (remove-duplicates + (apropos-symbols name external-only case-sensitive package)) + #'present-symbol-before-p)))) + +(defun briefly-describe-symbol-for-emacs (symbol) + "Return a property list describing SYMBOL. +Like `describe-symbol-for-emacs' but with at most one line per item." + (flet ((first-line (string) + (let ((pos (position #\newline string))) + (if (null pos) string (subseq string 0 pos))))) + (let ((desc (map-if #'stringp #'first-line + (describe-symbol-for-emacs symbol)))) + (if desc + (list* :designator (to-string symbol) desc))))) + +(defun map-if (test fn &rest lists) + "Like (mapcar FN . LISTS) but only call FN on objects satisfying TEST. +Example: +\(map-if #'oddp #'- '(1 2 3 4 5)) => (-1 2 -3 4 -5)" + (apply #'mapcar + (lambda (x) (if (funcall test x) (funcall fn x) x)) + lists)) + +(defun listify (f) + "Return a function like F, but which returns any non-null value +wrapped in a list." + (lambda (x) + (let ((y (funcall f x))) + (and y (list y))))) + +(defun present-symbol-before-p (x y) + "Return true if X belongs before Y in a printed summary of symbols. +Sorted alphabetically by package name and then symbol name, except +that symbols accessible in the current package go first." + (declare (type symbol x y)) + (flet ((accessible (s) + ;; Test breaks on NIL for package that does not inherit it + (eq (find-symbol (symbol-name s) *buffer-package*) s))) + (let ((ax (accessible x)) (ay (accessible y))) + (cond ((and ax ay) (string< (symbol-name x) (symbol-name y))) + (ax t) + (ay nil) + (t (let ((px (symbol-package x)) (py (symbol-package y))) + (if (eq px py) + (string< (symbol-name x) (symbol-name y)) + (string< (package-name px) (package-name py))))))))) + +(defun make-apropos-matcher (pattern case-sensitive) + (let ((chr= (if case-sensitive #'char= #'char-equal))) + (lambda (symbol) + (search pattern (string symbol) :test chr=)))) + +(defun apropos-symbols (string external-only case-sensitive package) + (let ((packages (or package (remove (find-package :keyword) + (list-all-packages)))) + (matcher (make-apropos-matcher string case-sensitive)) + (result)) + (with-package-iterator (next packages :external :internal) + (loop (multiple-value-bind (morep symbol) (next) + (cond ((not morep) (return)) + ((and (if external-only (symbol-external-p symbol) t) + (funcall matcher symbol)) + (push symbol result)))))) + result)) + +(defun call-with-describe-settings (fn) + (let ((*print-readably* nil)) + (funcall fn))) + +(defmacro with-describe-settings ((&rest _) &body body) + (declare (ignore _)) + `(call-with-describe-settings (lambda () ,@body))) + +(defun describe-to-string (object) + (with-describe-settings () + (with-output-to-string (*standard-output*) + (describe object)))) + +(defslimefun describe-symbol (symbol-name) + (with-buffer-syntax () + (describe-to-string (parse-symbol-or-lose symbol-name)))) + +(defslimefun describe-function (name) + (with-buffer-syntax () + (let ((symbol (parse-symbol-or-lose name))) + (describe-to-string (or (macro-function symbol) + (symbol-function symbol)))))) + +(defslimefun describe-definition-for-emacs (name kind) + (with-buffer-syntax () + (with-describe-settings () + (with-output-to-string (*standard-output*) + (describe-definition (parse-symbol-or-lose name) kind))))) + +(defslimefun documentation-symbol (symbol-name) + (with-buffer-syntax () + (multiple-value-bind (sym foundp) (parse-symbol symbol-name) + (if foundp + (let ((vdoc (documentation sym 'variable)) + (fdoc (documentation sym 'function))) + (with-output-to-string (string) + (format string "Documentation for the symbol ~a:~2%" sym) + (unless (or vdoc fdoc) + (format string "Not documented." )) + (when vdoc + (format string "Variable:~% ~a~2%" vdoc)) + (when fdoc + (format string "Function:~% Arglist: ~a~2% ~a" + (arglist sym) + fdoc)))) + (format nil "No such symbol, ~a." symbol-name))))) + + +;;;; Package Commands + +(defslimefun list-all-package-names (&optional nicknames) + "Return a list of all package names. +Include the nicknames if NICKNAMES is true." + (mapcar #'unparse-name + (if nicknames + (mapcan #'package-names (list-all-packages)) + (mapcar #'package-name (list-all-packages))))) + + +;;;; Tracing + +;; Use eval for the sake of portability... +(defun tracedp (fspec) + (member fspec (eval '(trace)))) + +(defvar *after-toggle-trace-hook* nil + "Hook called whenever a SPEC is traced or untraced. + +If non-nil, called with two arguments SPEC and TRACED-P." ) +(defslimefun swank-toggle-trace (spec-string) + (let* ((spec (from-string spec-string)) + (retval (cond ((consp spec) ; handle complicated cases in the backend + (toggle-trace spec)) + ((tracedp spec) + (eval `(untrace ,spec)) + (format nil "~S is now untraced." spec)) + (t + (eval `(trace ,spec)) + (format nil "~S is now traced." spec)))) + (traced-p (let* ((tosearch "is now traced.") + (start (- (length retval) + (length tosearch))) + (end (+ start (length tosearch)))) + (search tosearch (subseq retval start end)))) + (hook-msg (when *after-toggle-trace-hook* + (funcall *after-toggle-trace-hook* + spec + traced-p)))) + (if hook-msg + (format nil "~a~%(also ~a)" retval hook-msg) + retval))) + +(defslimefun untrace-all () + (untrace)) + + +;;;; Undefing + +(defslimefun undefine-function (fname-string) + (let ((fname (from-string fname-string))) + (format nil "~S" (fmakunbound fname)))) + +(defslimefun unintern-symbol (name package) + (let ((pkg (guess-package package))) + (cond ((not pkg) (format nil "No such package: ~s" package)) + (t + (multiple-value-bind (sym found) (parse-symbol name pkg) + (case found + ((nil) (format nil "~s not in package ~s" name package)) + (t + (unintern sym pkg) + (format nil "Uninterned symbol: ~s" sym)))))))) + +(defslimefun swank-delete-package (package-name) + (let ((pkg (or (guess-package package-name) + (error "No such package: ~s" package-name)))) + (delete-package pkg) + nil)) + + +;;;; Profiling + +(defun profiledp (fspec) + (member fspec (profiled-functions))) + +(defslimefun toggle-profile-fdefinition (fname-string) + (let ((fname (from-string fname-string))) + (cond ((profiledp fname) + (unprofile fname) + (format nil "~S is now unprofiled." fname)) + (t + (profile fname) + (format nil "~S is now profiled." fname))))) + +(defslimefun profile-by-substring (substring package) + (let ((count 0)) + (flet ((maybe-profile (symbol) + (when (and (fboundp symbol) + (not (profiledp symbol)) + (search substring (symbol-name symbol) :test #'equalp)) + (handler-case (progn + (profile symbol) + (incf count)) + (error (condition) + (warn "~a" condition)))))) + (if package + (do-symbols (symbol (parse-package package)) + (maybe-profile symbol)) + (do-all-symbols (symbol) + (maybe-profile symbol)))) + (format nil "~a function~:p ~:*~[are~;is~:;are~] now profiled" count))) + +(defslimefun swank-profile-package (package-name callersp methodsp) + (let ((pkg (or (guess-package package-name) + (error "Not a valid package name: ~s" package-name)))) + (check-type callersp boolean) + (check-type methodsp boolean) + (profile-package pkg callersp methodsp))) + + +;;;; Source Locations + +(defslimefun find-definition-for-thing (thing) + (find-source-location thing)) + +(defslimefun find-source-location-for-emacs (spec) + (find-source-location (value-spec-ref spec))) + +(defun value-spec-ref (spec) + (dcase spec + ((:string string package) + (with-buffer-syntax (package) + (eval (read-from-string string)))) + ((:inspector part) + (inspector-nth-part part)) + ((:sldb frame var) + (frame-var-value frame var)))) + +(defvar *find-definitions-right-trim* ",:.>") +(defvar *find-definitions-left-trim* "#:<") + +(defun find-definitions-find-symbol-or-package (name) + (flet ((do-find (name) + (multiple-value-bind (symbol found name) + (with-buffer-syntax () + (parse-symbol name)) + (cond (found + (return-from find-definitions-find-symbol-or-package + (values symbol found))) + ;; Packages are not named by symbols, so + ;; not-interned symbols can refer to packages + ((find-package name) + (return-from find-definitions-find-symbol-or-package + (values (make-symbol name) t))))))) + (do-find name) + (do-find (string-right-trim *find-definitions-right-trim* name)) + (do-find (string-left-trim *find-definitions-left-trim* name)) + (do-find (string-left-trim *find-definitions-left-trim* + (string-right-trim + *find-definitions-right-trim* name))) + ;; Not exactly robust + (when (and (eql (search "(setf " name :test #'char-equal) 0) + (char= (char name (1- (length name))) #\))) + (multiple-value-bind (symbol found) + (with-buffer-syntax () + (parse-symbol (subseq name (length "(setf ") + (1- (length name))))) + (when found + (values `(setf ,symbol) t)))))) + +(defslimefun find-definitions-for-emacs (name) + "Return a list ((DSPEC LOCATION) ...) of definitions for NAME. +DSPEC is a string and LOCATION a source location. NAME is a string." + (multiple-value-bind (symbol found) + (find-definitions-find-symbol-or-package name) + (when found + (mapcar #'xref>elisp (find-definitions symbol))))) + +;;; Generic function so contribs can extend it. +(defgeneric xref-doit (type thing) + (:method (type thing) + (declare (ignore type thing)) + :not-implemented)) + +(macrolet ((define-xref-action (xref-type handler) + `(defmethod xref-doit ((type (eql ,xref-type)) thing) + (declare (ignorable type)) + (funcall ,handler thing)))) + (define-xref-action :calls #'who-calls) + (define-xref-action :calls-who #'calls-who) + (define-xref-action :references #'who-references) + (define-xref-action :binds #'who-binds) + (define-xref-action :sets #'who-sets) + (define-xref-action :macroexpands #'who-macroexpands) + (define-xref-action :specializes #'who-specializes) + (define-xref-action :callers #'list-callers) + (define-xref-action :callees #'list-callees)) + +(defslimefun xref (type name) + (multiple-value-bind (sexp error) (ignore-errors (from-string name)) + (unless error + (let ((xrefs (xref-doit type sexp))) + (if (eq xrefs :not-implemented) + :not-implemented + (mapcar #'xref>elisp xrefs)))))) + +(defslimefun xrefs (types name) + (loop for type in types + for xrefs = (xref type name) + when (and (not (eq :not-implemented xrefs)) + (not (null xrefs))) + collect (cons type xrefs))) + +(defun xref>elisp (xref) + (destructuring-bind (name loc) xref + (list (to-string name) loc))) + + +;;;;; Lazy lists + +(defstruct (lcons (:constructor %lcons (car %cdr)) + (:predicate lcons?)) + car + (%cdr nil :type (or null lcons function)) + (forced? nil)) + +(defmacro lcons (car cdr) + `(%lcons ,car (lambda () ,cdr))) + +(defmacro lcons* (car cdr &rest more) + (cond ((null more) `(lcons ,car ,cdr)) + (t `(lcons ,car (lcons* ,cdr ,@more))))) + +(defun lcons-cdr (lcons) + (with-struct* (lcons- @ lcons) + (cond ((@ forced?) + (@ %cdr)) + (t + (let ((value (funcall (@ %cdr)))) + (setf (@ forced?) t + (@ %cdr) value)))))) + +(defun llist-range (llist start end) + (llist-take (llist-skip llist start) (- end start))) + +(defun llist-skip (lcons index) + (do ((i 0 (1+ i)) + (l lcons (lcons-cdr l))) + ((or (= i index) (null l)) + l))) + +(defun llist-take (lcons count) + (let ((result '())) + (do ((i 0 (1+ i)) + (l lcons (lcons-cdr l))) + ((or (= i count) + (null l))) + (push (lcons-car l) result)) + (nreverse result))) + +(defun iline (label value) + `(:line ,label ,value)) + + +;;;; Inspecting + +(defvar *inspector-verbose* nil) + +(defvar *inspector-printer-bindings* + '((*print-lines* . 1) + (*print-right-margin* . 75) + (*print-pretty* . t) + (*print-readably* . nil))) + +(defvar *inspector-verbose-printer-bindings* + '((*print-escape* . t) + (*print-circle* . t) + (*print-array* . nil))) + +(defstruct inspector-state) +(defstruct (istate (:conc-name istate.) (:include inspector-state)) + object + (verbose *inspector-verbose*) + (parts (make-array 10 :adjustable t :fill-pointer 0)) + (actions (make-array 10 :adjustable t :fill-pointer 0)) + metadata-plist + content + next previous) + +(defvar *istate* nil) +(defvar *inspector-history*) + +(defun reset-inspector () + (setq *istate* nil + *inspector-history* (make-array 10 :adjustable t :fill-pointer 0))) + +(defslimefun init-inspector (string) + (with-buffer-syntax () + (with-retry-restart (:msg "Retry SLIME inspection request.") + (reset-inspector) + (inspect-object (eval (read-from-string string)))))) + +(defun ensure-istate-metadata (o indicator default) + (with-struct (istate. object metadata-plist) *istate* + (assert (eq object o)) + (let ((data (getf metadata-plist indicator default))) + (setf (getf metadata-plist indicator) data) + data))) + +(defun inspect-object (o) + (let* ((prev *istate*) + (istate (make-istate :object o :previous prev + :verbose (cond (prev (istate.verbose prev)) + (t *inspector-verbose*))))) + (setq *istate* istate) + (setf (istate.content istate) (emacs-inspect/istate istate)) + (unless (find o *inspector-history*) + (vector-push-extend o *inspector-history*)) + (let ((previous (istate.previous istate))) + (if previous (setf (istate.next previous) istate))) + (istate>elisp istate))) + +(defun emacs-inspect/istate (istate) + (with-bindings (if (istate.verbose istate) + *inspector-verbose-printer-bindings* + *inspector-printer-bindings*) + (emacs-inspect (istate.object istate)))) + +(defun istate>elisp (istate) + (list :title (prepare-title istate) + :id (assign-index (istate.object istate) (istate.parts istate)) + :content (prepare-range istate 0 500))) + +(defun prepare-title (istate) + (if (istate.verbose istate) + (with-bindings *inspector-verbose-printer-bindings* + (to-string (istate.object istate))) + (with-string-stream (stream :length 200 + :bindings *inspector-printer-bindings*) + (print-unreadable-object + ((istate.object istate) stream :type t :identity t))))) + +(defun prepare-range (istate start end) + (let* ((range (content-range (istate.content istate) start end)) + (ps (loop for part in range append (prepare-part part istate)))) + (list ps + (if (< (length ps) (- end start)) + (+ start (length ps)) + (+ end 1000)) + start end))) + +(defun prepare-part (part istate) + (let ((newline '#.(string #\newline))) + (etypecase part + (string (list part)) + (cons (dcase part + ((:newline) (list newline)) + ((:value obj &optional str) + (list (value-part obj str (istate.parts istate)))) + ((:label &rest strs) + (list (list :label (apply #'cat (mapcar #'string strs))))) + ((:action label lambda &key (refreshp t)) + (list (action-part label lambda refreshp + (istate.actions istate)))) + ((:line label value) + (list (princ-to-string label) ": " + (value-part value nil (istate.parts istate)) + newline))))))) + +(defun value-part (object string parts) + (list :value + (or string (print-part-to-string object)) + (assign-index object parts))) + +(defun action-part (label lambda refreshp actions) + (list :action label (assign-index (list lambda refreshp) actions))) + +(defun assign-index (object vector) + (let ((index (fill-pointer vector))) + (vector-push-extend object vector) + index)) + +(defun print-part-to-string (value) + (let* ((*print-readably* nil) + (string (to-line value)) + (pos (position value *inspector-history*))) + (if pos + (format nil "@~D=~A" pos string) + string))) + +(defun content-range (list start end) + (typecase list + (list (let ((len (length list))) + (subseq list start (min len end)))) + (lcons (llist-range list start end)))) + +(defslimefun inspector-nth-part (index) + "Return the current inspector's INDEXth part. +The second value indicates if that part exists at all." + (let* ((parts (istate.parts *istate*)) + (foundp (< index (length parts)))) + (values (and foundp (aref parts index)) + foundp))) + +(defslimefun inspect-nth-part (index) + (with-buffer-syntax () + (inspect-object (inspector-nth-part index)))) + +(defslimefun inspector-range (from to) + (prepare-range *istate* from to)) + +(defslimefun inspector-call-nth-action (index &rest args) + (destructuring-bind (fun refreshp) (aref (istate.actions *istate*) index) + (apply fun args) + (if refreshp + (inspector-reinspect) + ;; tell emacs that we don't want to refresh the inspector buffer + nil))) + +(defslimefun inspector-pop () + "Inspect the previous object. +Return nil if there's no previous object." + (with-buffer-syntax () + (cond ((istate.previous *istate*) + (setq *istate* (istate.previous *istate*)) + (istate>elisp *istate*)) + (t nil)))) + +(defslimefun inspector-next () + "Inspect the next element in the history of inspected objects.." + (with-buffer-syntax () + (cond ((istate.next *istate*) + (setq *istate* (istate.next *istate*)) + (istate>elisp *istate*)) + (t nil)))) + +(defslimefun inspector-reinspect () + (let ((istate *istate*)) + (setf (istate.content istate) (emacs-inspect/istate istate)) + (istate>elisp istate))) + +(defslimefun inspector-toggle-verbose () + "Toggle verbosity of inspected object." + (setf (istate.verbose *istate*) (not (istate.verbose *istate*))) + (istate>elisp *istate*)) + +(defslimefun inspector-eval (string) + (let* ((obj (istate.object *istate*)) + (context (eval-context obj)) + (form (with-buffer-syntax ((cdr (assoc '*package* context))) + (read-from-string string))) + (ignorable (remove-if #'boundp (mapcar #'car context)))) + (to-string (eval `(let ((* ',obj) (- ',form) + . ,(loop for (var . val) in context + unless (constantp var) collect + `(,var ',val))) + (declare (ignorable . ,ignorable)) + ,form))))) + +(defslimefun inspector-history () + (with-output-to-string (out) + (let ((newest (loop for s = *istate* then next + for next = (istate.next s) + if (not next) return s))) + (format out "--- next/prev chain ---") + (loop for s = newest then (istate.previous s) while s do + (let ((val (istate.object s))) + (format out "~%~:[ ~; *~]@~d " + (eq s *istate*) + (position val *inspector-history*)) + (print-unreadable-object (val out :type t :identity t))))) + (format out "~%~%--- all visited objects ---") + (loop for val across *inspector-history* for i from 0 do + (format out "~%~2,' d " i) + (print-unreadable-object (val out :type t :identity t))))) + +(defslimefun quit-inspector () + (reset-inspector) + nil) + +(defslimefun describe-inspectee () + "Describe the currently inspected object." + (with-buffer-syntax () + (describe-to-string (istate.object *istate*)))) + +(defslimefun pprint-inspector-part (index) + "Pretty-print the currently inspected object." + (with-buffer-syntax () + (swank-pprint (list (inspector-nth-part index))))) + +(defslimefun inspect-in-frame (string index) + (with-buffer-syntax () + (with-retry-restart (:msg "Retry SLIME inspection request.") + (reset-inspector) + (inspect-object (eval-in-frame (from-string string) index))))) + +(defslimefun inspect-current-condition () + (with-buffer-syntax () + (reset-inspector) + (inspect-object *swank-debugger-condition*))) + +(defslimefun inspect-frame-var (frame var) + (with-buffer-syntax () + (reset-inspector) + (inspect-object (frame-var-value frame var)))) + +;;;;; Lists + +(defmethod emacs-inspect ((o cons)) + (if (listp (cdr o)) + (inspect-list o) + (inspect-cons o))) + +(defun inspect-cons (cons) + (label-value-line* + ('car (car cons)) + ('cdr (cdr cons)))) + +(defun inspect-list (list) + (multiple-value-bind (length tail) (safe-length list) + (flet ((frob (title list) + (list* title '(:newline) (inspect-list-aux list)))) + (cond ((not length) + (frob "A circular list:" + (cons (car list) + (ldiff (cdr list) list)))) + ((not tail) + (frob "A proper list:" list)) + (t + (frob "An improper list:" list)))))) + +(defun inspect-list-aux (list) + (loop for i from 0 for rest on list while (consp rest) append + (if (listp (cdr rest)) + (label-value-line i (car rest)) + (label-value-line* (i (car rest)) (:tail (cdr rest)))))) + +(defun safe-length (list) + "Similar to `list-length', but avoid errors on improper lists. +Return two values: the length of the list and the last cdr. +Return NIL if LIST is circular." + (do ((n 0 (+ n 2)) ;Counter. + (fast list (cddr fast)) ;Fast pointer: leaps by 2. + (slow list (cdr slow))) ;Slow pointer: leaps by 1. + (nil) + (cond ((null fast) (return (values n nil))) + ((not (consp fast)) (return (values n fast))) + ((null (cdr fast)) (return (values (1+ n) (cdr fast)))) + ((and (eq fast slow) (> n 0)) (return nil)) + ((not (consp (cdr fast))) (return (values (1+ n) (cdr fast))))))) + +;;;;; Hashtables + +(defun hash-table-to-alist (ht) + (let ((result '())) + (maphash (lambda (key value) + (setq result (acons key value result))) + ht) + result)) + +(defmethod emacs-inspect ((ht hash-table)) + (append + (label-value-line* + ("Count" (hash-table-count ht)) + ("Size" (hash-table-size ht)) + ("Test" (hash-table-test ht)) + ("Rehash size" (hash-table-rehash-size ht)) + ("Rehash threshold" (hash-table-rehash-threshold ht))) + (let ((weakness (hash-table-weakness ht))) + (when weakness + (label-value-line "Weakness:" weakness))) + (unless (zerop (hash-table-count ht)) + `((:action "[clear hashtable]" + ,(lambda () (clrhash ht))) (:newline) + "Contents: " (:newline))) + (let ((content (hash-table-to-alist ht))) + (cond ((every (lambda (x) (typep (first x) '(or string symbol))) content) + (setf content (sort content 'string< :key #'first))) + ((every (lambda (x) (typep (first x) 'real)) content) + (setf content (sort content '< :key #'first)))) + (loop for (key . value) in content appending + `((:value ,key) " = " (:value ,value) + " " (:action "[remove entry]" + ,(let ((key key)) + (lambda () (remhash key ht)))) + (:newline)))))) + +;;;;; Arrays + +(defmethod emacs-inspect ((array array)) + (lcons* + (iline "Dimensions" (array-dimensions array)) + (iline "Element type" (array-element-type array)) + (iline "Total size" (array-total-size array)) + (iline "Adjustable" (adjustable-array-p array)) + (iline "Fill pointer" (if (array-has-fill-pointer-p array) + (fill-pointer array))) + "Contents:" '(:newline) + (labels ((k (i max) + (cond ((= i max) '()) + (t (lcons (iline i (row-major-aref array i)) + (k (1+ i) max)))))) + (k 0 (array-total-size array))))) + +;;;;; Chars + +(defmethod emacs-inspect ((char character)) + (append + (label-value-line* + ("Char code" (char-code char)) + ("Lower cased" (char-downcase char)) + ("Upper cased" (char-upcase char))) + (if (get-macro-character char) + `("In the current readtable (" + (:value ,*readtable*) ") it is a macro character: " + (:value ,(get-macro-character char)))))) + +;;;; Thread listing + +(defvar *thread-list* () + "List of threads displayed in Emacs. We don't care a about +synchronization issues (yet). There can only be one thread listing at +a time.") + +(defslimefun list-threads () + "Return a list (LABELS (ID NAME STATUS ATTRS ...) ...). +LABELS is a list of attribute names and the remaining lists are the +corresponding attribute values per thread. +Example: + ((:id :name :status :priority) + (6 \"swank-indentation-cache-thread\" \"Semaphore timed wait\" 0) + (5 \"reader-thread\" \"Active\" 0) + (4 \"control-thread\" \"Semaphore timed wait\" 0) + (2 \"Swank Sentinel\" \"Semaphore timed wait\" 0) + (1 \"listener\" \"Active\" 0) + (0 \"Initial\" \"Sleep\" 0))" + (setq *thread-list* (all-threads)) + (when (and *emacs-connection* + (use-threads-p) + (equalp (thread-name (current-thread)) "worker")) + (setf *thread-list* (delete (current-thread) *thread-list*))) + (let* ((plist (thread-attributes (car *thread-list*))) + (labels (loop for (key) on plist by #'cddr + collect key))) + `((:id :name :status ,@labels) + ,@(loop for thread in *thread-list* + for name = (thread-name thread) + for attributes = (thread-attributes thread) + collect (list* (thread-id thread) + (string name) + (thread-status thread) + (loop for label in labels + collect (getf attributes label))))))) + +(defslimefun quit-thread-browser () + (setq *thread-list* nil)) + +(defun nth-thread (index) + (nth index *thread-list*)) + +(defslimefun debug-nth-thread (index) + (let ((connection *emacs-connection*)) + (queue-thread-interrupt + (nth-thread index) + (lambda () + (with-connection (connection) + (simple-break)))))) + +(defslimefun kill-nth-thread (index) + (kill-thread (nth-thread index))) + +(defslimefun start-swank-server-in-thread (index port-file-name) + "Interrupt the INDEXth thread and make it start a swank server. +The server port is written to PORT-FILE-NAME." + (interrupt-thread (nth-thread index) + (lambda () + (start-server port-file-name :style nil)))) + +;;;; Class browser + +(defun mop-helper (class-name fn) + (let ((class (find-class class-name nil))) + (if class + (mapcar (lambda (x) (to-string (class-name x))) + (funcall fn class))))) + +(defslimefun mop (type symbol-name) + "Return info about classes using mop. + + When type is: + :subclasses - return the list of subclasses of class. + :superclasses - return the list of superclasses of class." + (let ((symbol (parse-symbol symbol-name *buffer-package*))) + (ecase type + (:subclasses + (mop-helper symbol #'swank-mop:class-direct-subclasses)) + (:superclasses + (mop-helper symbol #'swank-mop:class-direct-superclasses))))) + + +;;;; Automatically synchronized state +;;; +;;; Here we add hooks to push updates of relevant information to +;;; Emacs. + +;;;;; *FEATURES* + +(defun sync-features-to-emacs () + "Update Emacs if any relevant Lisp state has changed." + ;; FIXME: *slime-features* should be connection-local + (unless (eq *slime-features* *features*) + (setq *slime-features* *features*) + (send-to-emacs (list :new-features (features-for-emacs))))) + +(defun features-for-emacs () + "Return `*slime-features*' in a format suitable to send it to Emacs." + *slime-features*) + +(add-hook *pre-reply-hook* 'sync-features-to-emacs) + + +;;;;; Indentation of macros +;;; +;;; This code decides how macros should be indented (based on their +;;; arglists) and tells Emacs. A per-connection cache is used to avoid +;;; sending redundant information to Emacs -- we just say what's +;;; changed since last time. +;;; +;;; The strategy is to scan all symbols, pick out the macros, and look +;;; for &body-arguments. + +(defvar *configure-emacs-indentation* t + "When true, automatically send indentation information to Emacs +after each command.") + +(defslimefun update-indentation-information () + (send-to-indentation-cache `(:update-indentation-information)) + nil) + +;; This function is for *PRE-REPLY-HOOK*. +(defun sync-indentation-to-emacs () + "Send any indentation updates to Emacs via CONNECTION." + (when *configure-emacs-indentation* + (send-to-indentation-cache `(:sync-indentation ,*buffer-package*)))) + +;; Send REQUEST to the cache. If we are single threaded perform the +;; request right away, otherwise delegate the request to the +;; indentation-cache-thread. +(defun send-to-indentation-cache (request) + (let ((c *emacs-connection*)) + (etypecase c + (singlethreaded-connection + (handle-indentation-cache-request c request)) + (multithreaded-connection + (without-slime-interrupts + (send (mconn.indentation-cache-thread c) request)))))) + +(defun indentation-cache-loop (connection) + (with-connection (connection) + (loop + (restart-case + (handle-indentation-cache-request connection (receive)) + (abort () + :report "Return to the indentation cache request handling loop."))))) + +(defun handle-indentation-cache-request (connection request) + (dcase request + ((:sync-indentation package) + (let ((fullp (need-full-indentation-update-p connection))) + (perform-indentation-update connection fullp package))) + ((:update-indentation-information) + (perform-indentation-update connection t nil)))) + +(defun need-full-indentation-update-p (connection) + "Return true if the whole indentation cache should be updated. +This is a heuristic to avoid scanning all symbols all the time: +instead, we only do a full scan if the set of packages has changed." + (set-difference (list-all-packages) + (connection.indentation-cache-packages connection))) + +(defun perform-indentation-update (connection force package) + "Update the indentation cache in CONNECTION and update Emacs. +If FORCE is true then start again without considering the old cache." + (let ((cache (connection.indentation-cache connection))) + (when force (clrhash cache)) + (let ((delta (update-indentation/delta-for-emacs cache force package))) + (setf (connection.indentation-cache-packages connection) + (list-all-packages)) + (unless (null delta) + (setf (connection.indentation-cache connection) cache) + (send-to-emacs (list :indentation-update delta)))))) + +(defun update-indentation/delta-for-emacs (cache force package) + "Update the cache and return the changes in a (SYMBOL INDENT PACKAGES) list. +If FORCE is true then check all symbols, otherwise only check symbols +belonging to PACKAGE." + (let ((alist '())) + (flet ((consider (symbol) + (let ((indent (symbol-indentation symbol))) + (when indent + (unless (equal (gethash symbol cache) indent) + (setf (gethash symbol cache) indent) + (let ((pkgs (mapcar #'package-name + (symbol-packages symbol))) + (name (string-downcase symbol))) + (push (list name indent pkgs) alist))))))) + (cond (force + (do-all-symbols (symbol) + (consider symbol))) + ((package-name package) ; don't try to iterate over a + ; deleted package. + (do-symbols (symbol package) + (when (eq (symbol-package symbol) package) + (consider symbol))))) + alist))) + +(defun package-names (package) + "Return the name and all nicknames of PACKAGE in a fresh list." + (cons (package-name package) (copy-list (package-nicknames package)))) + +(defun symbol-packages (symbol) + "Return the packages where SYMBOL can be found." + (let ((string (string symbol))) + (loop for p in (list-all-packages) + when (eq symbol (find-symbol string p)) + collect p))) + +(defun cl-symbol-p (symbol) + "Is SYMBOL a symbol in the COMMON-LISP package?" + (eq (symbol-package symbol) cl-package)) + +(defun known-to-emacs-p (symbol) + "Return true if Emacs has special rules for indenting SYMBOL." + (cl-symbol-p symbol)) + +(defun symbol-indentation (symbol) + "Return a form describing the indentation of SYMBOL. +The form is to be used as the `common-lisp-indent-function' property +in Emacs." + (if (and (macro-function symbol) + (not (known-to-emacs-p symbol))) + (let ((arglist (arglist symbol))) + (etypecase arglist + ((member :not-available) + nil) + (list + (macro-indentation arglist)))) + nil)) + +(defun macro-indentation (arglist) + (if (well-formed-list-p arglist) + (position '&body (remove '&optional (clean-arglist arglist))) + nil)) + +(defun clean-arglist (arglist) + "Remove &whole, &enviroment, and &aux elements from ARGLIST." + (cond ((null arglist) '()) + ((member (car arglist) '(&whole &environment)) + (clean-arglist (cddr arglist))) + ((eq (car arglist) '&aux) + '()) + (t (cons (car arglist) (clean-arglist (cdr arglist)))))) + +(defun well-formed-list-p (list) + "Is LIST a proper list terminated by NIL?" + (typecase list + (null t) + (cons (well-formed-list-p (cdr list))) + (t nil))) + +(defun print-indentation-lossage (&optional (stream *standard-output*)) + "Return the list of symbols whose indentation styles collide incompatibly. +Collisions are caused because package information is ignored." + (let ((table (make-hash-table :test 'equal))) + (flet ((name (s) (string-downcase (symbol-name s)))) + (do-all-symbols (s) + (setf (gethash (name s) table) + (cons s (symbol-indentation s)))) + (let ((collisions '())) + (do-all-symbols (s) + (let* ((entry (gethash (name s) table)) + (owner (car entry)) + (indent (cdr entry))) + (unless (or (eq s owner) + (equal (symbol-indentation s) indent) + (and (not (fboundp s)) + (null (macro-function s)))) + (pushnew owner collisions) + (pushnew s collisions)))) + (if (null collisions) + (format stream "~&No worries!~%") + (format stream "~&Symbols with collisions:~%~{ ~S~%~}" + collisions)))))) + +;;; FIXME: it's too slow on CLASP right now, remove once it's fast enough. +#-clasp +(add-hook *pre-reply-hook* 'sync-indentation-to-emacs) + +(defun make-output-function-for-target (connection target) + "Create a function to send user output to a specific TARGET in Emacs." + (lambda (string) + (swank::with-connection (connection) + (with-simple-restart + (abort "Abort sending output to Emacs.") + (swank::send-to-emacs `(:write-string ,string ,target)))))) + +(defun make-output-stream-for-target (connection target) + "Create a stream that sends output to a specific TARGET in Emacs." + (make-output-stream (make-output-function-for-target connection target))) + + +;;;; Testing + +(defslimefun io-speed-test (&optional (n 1000) (m 1)) + (let* ((s *standard-output*) + (*trace-output* (make-broadcast-stream s *log-output*))) + (time (progn + (dotimes (i n) + (format s "~D abcdefghijklm~%" i) + (when (zerop (mod n m)) + (finish-output s))) + (finish-output s) + (when *emacs-connection* + (eval-in-emacs '(message "done."))))) + (terpri *trace-output*) + (finish-output *trace-output*) + nil)) + +(defslimefun flow-control-test (n delay) + (let ((stream (make-output-stream + (let ((conn *emacs-connection*)) + (lambda (string) + (declare (ignore string)) + (with-connection (conn) + (send-to-emacs `(:test-delay ,delay)))))))) + (dotimes (i n) + (print i stream) + (force-output stream) + (background-message "flow-control-test: ~d" i)))) + + +(defun before-init (version load-path) + (pushnew :swank *features*) + (setq *swank-wire-protocol-version* version) + (setq *load-path* load-path)) + +(defun init () + (run-hook *after-init-hook*)) + +;; Local Variables: +;; coding: latin-1-unix +;; indent-tabs-mode: nil +;; outline-regexp: ";;;;;*" +;; End: + +;;; swank.lisp ends here diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/abcl.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/abcl.lisp new file mode 100644 index 0000000..f5764d6 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/abcl.lisp @@ -0,0 +1,847 @@ +;;;; -*- indent-tabs-mode: nil; outline-regexp: ";;;;;*"; -*- +;;; +;;; swank-abcl.lisp --- Armedbear CL specific code for SLIME. +;;; +;;; Adapted from swank-acl.lisp, Andras Simon, 2004 +;;; +;;; This code has been placed in the Public Domain. All warranties +;;; are disclaimed. +;;; + +(defpackage swank/abcl + (:use cl swank/backend)) + +(in-package swank/abcl) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (require :collect) ;just so that it doesn't spoil the flying letters + (require :pprint) + (require :gray-streams) + (assert (>= (read-from-string (subseq (lisp-implementation-version) 0 4)) + 0.22) + () "This file needs ABCL version 0.22 or newer")) + +(defimplementation gray-package-name () + "GRAY-STREAMS") + +;; FIXME: switch to shared Gray stream implementation when bugs are +;; fixed in ABCL. See: http://abcl.org/trac/ticket/373. +(progn + (defimplementation make-output-stream (write-string) + (ext:make-slime-output-stream write-string)) + + (defimplementation make-input-stream (read-string) + (ext:make-slime-input-stream read-string + (make-synonym-stream '*standard-output*)))) + +(defimplementation call-with-compilation-hooks (function) + (funcall function)) + +;;; swank-mop + +;;dummies and definition + +(defclass standard-slot-definition ()()) + +;(defun class-finalized-p (class) t) + +(defun slot-definition-documentation (slot) + (declare (ignore slot)) + #+nil (documentation slot 't)) + +(defun slot-definition-type (slot) + (declare (ignore slot)) + t) + +(defun class-prototype (class) + (declare (ignore class)) + nil) + +(defun generic-function-declarations (gf) + (declare (ignore gf)) + nil) + +(defun specializer-direct-methods (spec) + (mop:class-direct-methods spec)) + +(defun slot-definition-name (slot) + (mop:slot-definition-name slot)) + +(defun class-slots (class) + (mop:class-slots class)) + +(defun method-generic-function (method) + (mop:method-generic-function method)) + +(defun method-function (method) + (mop:method-function method)) + +(defun slot-boundp-using-class (class object slotdef) + (declare (ignore class)) + (system::slot-boundp object (slot-definition-name slotdef))) + +(defun slot-value-using-class (class object slotdef) + (declare (ignore class)) + (system::slot-value object (slot-definition-name slotdef))) + +(import-to-swank-mop + '( ;; classes + cl:standard-generic-function + standard-slot-definition ;;dummy + cl:method + cl:standard-class + #+#.(swank/backend:with-symbol 'compute-applicable-methods-using-classes + 'mop) + mop:compute-applicable-methods-using-classes + ;; standard-class readers + mop:class-default-initargs + mop:class-direct-default-initargs + mop:class-direct-slots + mop:class-direct-subclasses + mop:class-direct-superclasses + mop:eql-specializer + mop:class-finalized-p + mop:finalize-inheritance + cl:class-name + mop:class-precedence-list + class-prototype ;;dummy + class-slots + specializer-direct-methods + ;; eql-specializer accessors + mop::eql-specializer-object + ;; generic function readers + mop:generic-function-argument-precedence-order + generic-function-declarations ;;dummy + mop:generic-function-lambda-list + mop:generic-function-methods + mop:generic-function-method-class + mop:generic-function-method-combination + mop:generic-function-name + ;; method readers + method-generic-function + method-function + mop:method-lambda-list + mop:method-specializers + mop:method-qualifiers + ;; slot readers + mop:slot-definition-allocation + slot-definition-documentation ;;dummy + mop:slot-definition-initargs + mop:slot-definition-initform + mop:slot-definition-initfunction + slot-definition-name + slot-definition-type ;;dummy + mop:slot-definition-readers + mop:slot-definition-writers + slot-boundp-using-class + slot-value-using-class + mop:slot-makunbound-using-class)) + +;;;; TCP Server + + +(defimplementation preferred-communication-style () + :spawn) + +(defimplementation create-socket (host port &key backlog) + (ext:make-server-socket port)) + +(defimplementation local-port (socket) + (java:jcall (java:jmethod "java.net.ServerSocket" "getLocalPort") socket)) + +(defimplementation close-socket (socket) + (ext:server-socket-close socket)) + +(defimplementation accept-connection (socket + &key external-format buffering timeout) + (declare (ignore buffering timeout)) + (ext:get-socket-stream (ext:socket-accept socket) + :element-type (if external-format + 'character + '(unsigned-byte 8)) + :external-format (or external-format :default))) + +;;;; UTF8 + +;; faster please! +(defimplementation string-to-utf8 (s) + (jbytes-to-octets + (java:jcall + (java:jmethod "java.lang.String" "getBytes" "java.lang.String") + s + "UTF8"))) + +(defimplementation utf8-to-string (u) + (java:jnew + (java:jconstructor "org.armedbear.lisp.SimpleString" + "java.lang.String") + (java:jnew (java:jconstructor "java.lang.String" "[B" "java.lang.String") + (octets-to-jbytes u) + "UTF8"))) + +(defun octets-to-jbytes (octets) + (declare (type octets (simple-array (unsigned-byte 8) (*)))) + (let* ((len (length octets)) + (bytes (java:jnew-array "byte" len))) + (loop for byte across octets + for i from 0 + do (java:jstatic (java:jmethod "java.lang.reflect.Array" "setByte" + "java.lang.Object" "int" "byte") + "java.lang.relect.Array" + bytes i byte)) + bytes)) + +(defun jbytes-to-octets (jbytes) + (let* ((len (java:jarray-length jbytes)) + (octets (make-array len :element-type '(unsigned-byte 8)))) + (loop for i from 0 below len + for jbyte = (java:jarray-ref jbytes i) + do (setf (aref octets i) jbyte)) + octets)) + +;;;; External formats + +(defvar *external-format-to-coding-system* + '((:iso-8859-1 "latin-1" "iso-latin-1" "iso-8859-1") + ((:iso-8859-1 :eol-style :lf) + "latin-1-unix" "iso-latin-1-unix" "iso-8859-1-unix") + (:utf-8 "utf-8") + ((:utf-8 :eol-style :lf) "utf-8-unix") + (:euc-jp "euc-jp") + ((:euc-jp :eol-style :lf) "euc-jp-unix") + (:us-ascii "us-ascii") + ((:us-ascii :eol-style :lf) "us-ascii-unix"))) + +(defimplementation find-external-format (coding-system) + (car (rassoc-if (lambda (x) + (member coding-system x :test #'equal)) + *external-format-to-coding-system*))) + +;;;; Unix signals + +(defimplementation getpid () + (handler-case + (let* ((runtime + (java:jstatic "getRuntime" "java.lang.Runtime")) + (command + (java:jnew-array-from-array + "java.lang.String" #("sh" "-c" "echo $PPID"))) + (runtime-exec-jmethod + ;; Complicated because java.lang.Runtime.exec() is + ;; overloaded on a non-primitive type (array of + ;; java.lang.String), so we have to use the actual + ;; parameter instance to get java.lang.Class + (java:jmethod "java.lang.Runtime" "exec" + (java:jcall + (java:jmethod "java.lang.Object" "getClass") + command))) + (process + (java:jcall runtime-exec-jmethod runtime command)) + (output + (java:jcall (java:jmethod "java.lang.Process" "getInputStream") + process))) + (java:jcall (java:jmethod "java.lang.Process" "waitFor") + process) + (loop :with b :do + (setq b + (java:jcall (java:jmethod "java.io.InputStream" "read") + output)) + :until (member b '(-1 #x0a)) ; Either EOF or LF + :collecting (code-char b) :into result + :finally (return + (parse-integer (coerce result 'string))))) + (t () 0))) + +(defimplementation lisp-implementation-type-name () + "armedbear") + +(defimplementation set-default-directory (directory) + (let ((dir (sys::probe-directory directory))) + (when dir (setf *default-pathname-defaults* dir)) + (namestring dir))) + + +;;;; Misc + +(defimplementation arglist (fun) + (cond ((symbolp fun) + (multiple-value-bind (arglist present) + (sys::arglist fun) + (when (and (not present) + (fboundp fun) + (typep (symbol-function fun) + 'standard-generic-function)) + (setq arglist + (mop::generic-function-lambda-list (symbol-function fun)) + present + t)) + (if present arglist :not-available))) + (t :not-available))) + +(defimplementation function-name (function) + (nth-value 2 (function-lambda-expression function))) + +(defimplementation macroexpand-all (form &optional env) + (ext:macroexpand-all form env)) + +(defimplementation collect-macro-forms (form &optional env) + ;; Currently detects only normal macros, not compiler macros. + (declare (ignore env)) + (with-collected-macro-forms (macro-forms) + (handler-bind ((warning #'muffle-warning)) + (ignore-errors + (compile nil `(lambda () ,(macroexpand-all form env))))) + (values macro-forms nil))) + +(defimplementation describe-symbol-for-emacs (symbol) + (let ((result '())) + (flet ((doc (kind &optional (sym symbol)) + (or (documentation sym kind) :not-documented)) + (maybe-push (property value) + (when value + (setf result (list* property value result))))) + (maybe-push + :variable (when (boundp symbol) + (doc 'variable))) + (when (fboundp symbol) + (maybe-push + (cond ((macro-function symbol) :macro) + ((special-operator-p symbol) :special-operator) + ((typep (fdefinition symbol) 'generic-function) + :generic-function) + (t :function)) + (doc 'function))) + (maybe-push + :class (if (find-class symbol nil) + (doc 'class))) + result))) + +(defimplementation describe-definition (symbol namespace) + (ecase namespace + ((:variable :macro) + (describe symbol)) + ((:function :generic-function) + (describe (symbol-function symbol))) + (:class + (describe (find-class symbol))))) + +(defimplementation describe-definition (symbol namespace) + (ecase namespace + (:variable + (describe symbol)) + ((:function :generic-function) + (describe (symbol-function symbol))) + (:class + (describe (find-class symbol))))) + + +;;;; Debugger + +;; Copied from swank-sbcl.lisp. +;; +;; Notice that *INVOKE-DEBUGGER-HOOK* is tried before *DEBUGGER-HOOK*, +;; so we have to make sure that the latter gets run when it was +;; established locally by a user (i.e. changed meanwhile.) +(defun make-invoke-debugger-hook (hook) + (lambda (condition old-hook) + (if *debugger-hook* + (funcall *debugger-hook* condition old-hook) + (funcall hook condition old-hook)))) + +(defimplementation call-with-debugger-hook (hook fun) + (let ((*debugger-hook* hook) + (sys::*invoke-debugger-hook* (make-invoke-debugger-hook hook))) + (funcall fun))) + +(defimplementation install-debugger-globally (function) + (setq *debugger-hook* function) + (setq sys::*invoke-debugger-hook* (make-invoke-debugger-hook function))) + +(defvar *sldb-topframe*) + +(defimplementation call-with-debugging-environment (debugger-loop-fn) + (let* ((magic-token (intern "SWANK-DEBUGGER-HOOK" 'swank)) + (*sldb-topframe* + (second (member magic-token (sys:backtrace) + :key (lambda (frame) + (first (sys:frame-to-list frame))))))) + (funcall debugger-loop-fn))) + +(defun backtrace (start end) + "A backtrace without initial SWANK frames." + (let ((backtrace (sys:backtrace))) + (subseq (or (member *sldb-topframe* backtrace) backtrace) + start end))) + +(defun nth-frame (index) + (nth index (backtrace 0 nil))) + +(defimplementation compute-backtrace (start end) + (let ((end (or end most-positive-fixnum))) + (backtrace start end))) + +(defimplementation print-frame (frame stream) + (write-string (sys:frame-to-string frame) + stream)) + +;;; Sorry, but can't seem to declare DEFIMPLEMENTATION under FLET. +;;; --ME 20150403 +(defun nth-frame-list (index) + (java:jcall "toLispList" (nth-frame index))) + +(defun match-lambda (operator values) + (jvm::match-lambda-list + (multiple-value-list + (jvm::parse-lambda-list (ext:arglist operator))) + values)) + +(defimplementation frame-locals (index) + (loop + :for id :upfrom 0 + :with frame = (nth-frame-list index) + :with operator = (first frame) + :with values = (rest frame) + :with arglist = (if (and operator (consp values) (not (null values))) + (handler-case + (match-lambda operator values) + (jvm::lambda-list-mismatch (e) + :lambda-list-mismatch)) + :not-available) + :for value :in values + :collecting (list + :name (if (not (keywordp arglist)) + (first (nth id arglist)) + (format nil "arg~A" id)) + :id id + :value value))) + +(defimplementation frame-var-value (index id) + (elt (rest (java:jcall "toLispList" (nth-frame index))) id)) + + +#+nil +(defimplementation disassemble-frame (index) + (disassemble (debugger:frame-function (nth-frame index)))) + +(defimplementation frame-source-location (index) + (let ((frame (nth-frame index))) + (or (source-location (nth-frame index)) + `(:error ,(format nil "No source for frame: ~a" frame))))) + +#+nil +(defimplementation eval-in-frame (form frame-number) + (debugger:eval-form-in-context + form + (debugger:environment-of-frame (nth-frame frame-number)))) + +#+nil +(defimplementation return-from-frame (frame-number form) + (let ((frame (nth-frame frame-number))) + (multiple-value-call #'debugger:frame-return + frame (debugger:eval-form-in-context + form + (debugger:environment-of-frame frame))))) + +;;; XXX doesn't work for frames with arguments +#+nil +(defimplementation restart-frame (frame-number) + (let ((frame (nth-frame frame-number))) + (debugger:frame-retry frame (debugger:frame-function frame)))) + +;;;; Compiler hooks + +(defvar *buffer-name* nil) +(defvar *buffer-start-position*) +(defvar *buffer-string*) +(defvar *compile-filename*) + +(defvar *abcl-signaled-conditions*) + +(defun handle-compiler-warning (condition) + (let ((loc (when (and jvm::*compile-file-pathname* + system::*source-position*) + (cons jvm::*compile-file-pathname* system::*source-position*)))) + ;; filter condition signaled more than once. + (unless (member condition *abcl-signaled-conditions*) + (push condition *abcl-signaled-conditions*) + (signal 'compiler-condition + :original-condition condition + :severity :warning + :message (format nil "~A" condition) + :location (cond (*buffer-name* + (make-location + (list :buffer *buffer-name*) + (list :offset *buffer-start-position* 0))) + (loc + (destructuring-bind (file . pos) loc + (make-location + (list :file (namestring (truename file))) + (list :position (1+ pos))))) + (t + (make-location + (list :file (namestring *compile-filename*)) + (list :position 1)))))))) + +(defimplementation swank-compile-file (input-file output-file + load-p external-format + &key policy) + (declare (ignore external-format policy)) + (let ((jvm::*resignal-compiler-warnings* t) + (*abcl-signaled-conditions* nil)) + (handler-bind ((warning #'handle-compiler-warning)) + (let ((*buffer-name* nil) + (*compile-filename* input-file)) + (multiple-value-bind (fn warn fail) + (compile-file input-file :output-file output-file) + (values fn warn + (and fn load-p + (not (load fn))))))))) + +(defimplementation swank-compile-string (string &key buffer position filename + policy) + (declare (ignore filename policy)) + (let ((jvm::*resignal-compiler-warnings* t) + (*abcl-signaled-conditions* nil)) + (handler-bind ((warning #'handle-compiler-warning)) + (let ((*buffer-name* buffer) + (*buffer-start-position* position) + (*buffer-string* string) + (sys::*source* (make-pathname :device "emacs-buffer" :name buffer)) + (sys::*source-position* position)) + (funcall (compile nil (read-from-string + (format nil "(~S () ~A)" 'lambda string)))) + t)))) + +#| +;;;; Definition Finding + +(defun find-fspec-location (fspec type) + (let ((file (excl::fspec-pathname fspec type))) + (etypecase file + (pathname + (let ((start (scm:find-definition-in-file fspec type file))) + (make-location (list :file (namestring (truename file))) + (if start + (list :position (1+ start)) + (list :function-name (string fspec)))))) + ((member :top-level) + (list :error (format nil "Defined at toplevel: ~A" fspec))) + (null + (list :error (format nil "Unkown source location for ~A" fspec)))))) + +(defun fspec-definition-locations (fspec) + (let ((defs (excl::find-multiple-definitions fspec))) + (loop for (fspec type) in defs + collect (list fspec (find-fspec-location fspec type))))) + +(defimplementation find-definitions (symbol) + (fspec-definition-locations symbol)) +|# + +(defgeneric source-location (object)) + +(defmethod source-location ((symbol symbol)) + (when (pathnamep (ext:source-pathname symbol)) + (let ((pos (ext:source-file-position symbol)) + (path (namestring (ext:source-pathname symbol)))) + (cond ((ext:pathname-jar-p path) + `(:location + ;; strip off "jar:file:" = 9 characters + (:zip ,@(split-string (subseq path 9) "!/")) + ;; pos never seems right. Use function name. + (:function-name ,(string symbol)) + (:align t))) + ((equal (pathname-device (ext:source-pathname symbol)) "emacs-buffer") + ;; conspire with swank-compile-string to keep the buffer + ;; name in a pathname whose device is "emacs-buffer". + `(:location + (:buffer ,(pathname-name (ext:source-pathname symbol))) + (:function-name ,(string symbol)) + (:align t))) + (t + `(:location + (:file ,path) + ,(if pos + (list :position (1+ pos)) + (list :function-name (string symbol))) + (:align t))))))) + +(defmethod source-location ((frame sys::java-stack-frame)) + (destructuring-bind (&key class method file line) (sys:frame-to-list frame) + (declare (ignore method)) + (let ((file (or (find-file-in-path file *source-path*) + (let ((f (format nil "~{~a/~}~a" + (butlast (split-string class "\\.")) + file))) + (find-file-in-path f *source-path*))))) + (and file + `(:location ,file (:line ,line) ()))))) + +(defmethod source-location ((frame sys::lisp-stack-frame)) + (destructuring-bind (operator &rest args) (sys:frame-to-list frame) + (declare (ignore args)) + (etypecase operator + (function (source-location operator)) + (list nil) + (symbol (source-location operator))))) + +(defmethod source-location ((fun function)) + (let ((name (function-name fun))) + (and name (source-location name)))) + +(defun system-property (name) + (java:jstatic "getProperty" "java.lang.System" name)) + +(defun pathname-parent (pathname) + (make-pathname :directory (butlast (pathname-directory pathname)))) + +(defun pathname-absolute-p (pathname) + (eq (car (pathname-directory pathname)) ':absolute)) + +(defun split-string (string regexp) + (coerce + (java:jcall (java:jmethod "java.lang.String" "split" "java.lang.String") + string regexp) + 'list)) + +(defun path-separator () + (java:jfield "java.io.File" "pathSeparator")) + +(defun search-path-property (prop-name) + (let ((string (system-property prop-name))) + (and string + (remove nil + (mapcar #'truename + (split-string string (path-separator))))))) + +(defun jdk-source-path () + (let* ((jre-home (truename (system-property "java.home"))) + (src-zip (merge-pathnames "src.zip" (pathname-parent jre-home))) + (truename (probe-file src-zip))) + (and truename (list truename)))) + +(defun class-path () + (append (search-path-property "java.class.path") + (search-path-property "sun.boot.class.path"))) + +(defvar *source-path* + (append (search-path-property "user.dir") + (jdk-source-path) + ;;(list (truename "/scratch/abcl/src")) + ) + "List of directories to search for source files.") + +(defun zipfile-contains-p (zipfile-name entry-name) + (let ((zipfile (java:jnew (java:jconstructor "java.util.zip.ZipFile" + "java.lang.String") + zipfile-name))) + (java:jcall + (java:jmethod "java.util.zip.ZipFile" "getEntry" "java.lang.String") + zipfile entry-name))) + +;; (find-file-in-path "java/lang/String.java" *source-path*) +;; (find-file-in-path "Lisp.java" *source-path*) + +;; Try to find FILENAME in PATH. If found, return a file spec as +;; needed by Emacs. We also look in zip files. +(defun find-file-in-path (filename path) + (labels ((try (dir) + (cond ((not (pathname-type dir)) + (let ((f (probe-file (merge-pathnames filename dir)))) + (and f `(:file ,(namestring f))))) + ((equal (pathname-type dir) "zip") + (try-zip dir)) + (t (error "strange path element: ~s" path)))) + (try-zip (zip) + (let* ((zipfile-name (namestring (truename zip)))) + (and (zipfile-contains-p zipfile-name filename) + `(:dir ,zipfile-name ,filename))))) + (cond ((pathname-absolute-p filename) (probe-file filename)) + (t + (loop for dir in path + if (try dir) return it))))) + +(defimplementation find-definitions (symbol) + (ext:resolve symbol) + (let ((srcloc (source-location symbol))) + (and srcloc `((,symbol ,srcloc))))) + +#| +Uncomment this if you have patched xref.lisp, as in +http://article.gmane.org/gmane.lisp.slime.devel/2425 +Also, make sure that xref.lisp is loaded by modifying the armedbear +part of *sysdep-pathnames* in swank.loader.lisp. + +;;;; XREF +(setq pxref:*handle-package-forms* '(cl:in-package)) + +(defmacro defxref (name function) + `(defimplementation ,name (name) + (xref-results (,function name)))) + +(defxref who-calls pxref:list-callers) +(defxref who-references pxref:list-readers) +(defxref who-binds pxref:list-setters) +(defxref who-sets pxref:list-setters) +(defxref list-callers pxref:list-callers) +(defxref list-callees pxref:list-callees) + +(defun xref-results (symbols) + (let ((xrefs '())) + (dolist (symbol symbols) + (push (list symbol (cadar (source-location symbol))) xrefs)) + xrefs)) +|# + +;;;; Inspecting +(defmethod emacs-inspect ((o t)) + (let ((parts (sys:inspected-parts o))) + `("The object is of type " ,(symbol-name (type-of o)) "." (:newline) + ,@(if parts + (loop :for (label . value) :in parts + :appending (label-value-line label value)) + (list "No inspectable parts, dumping output of CL:DESCRIBE:" + '(:newline) + (with-output-to-string (desc) (describe o desc))))))) + +(defmethod emacs-inspect ((slot mop::slot-definition)) + `("Name: " + (:value ,(mop:slot-definition-name slot)) + (:newline) + "Documentation:" (:newline) + ,@(when (slot-definition-documentation slot) + `((:value ,(slot-definition-documentation slot)) (:newline))) + "Initialization:" (:newline) + " Args: " (:value ,(mop:slot-definition-initargs slot)) (:newline) + " Form: " ,(if (mop:slot-definition-initfunction slot) + `(:value ,(mop:slot-definition-initform slot)) + "#") (:newline) + " Function: " + (:value ,(mop:slot-definition-initfunction slot)) + (:newline))) + +(defmethod emacs-inspect ((f function)) + `(,@(when (function-name f) + `("Name: " + ,(princ-to-string (function-name f)) (:newline))) + ,@(multiple-value-bind (args present) + (sys::arglist f) + (when present + `("Argument list: " + ,(princ-to-string args) (:newline)))) + (:newline) + #+nil,@(when (documentation f t) + `("Documentation:" (:newline) + ,(documentation f t) (:newline))) + ,@(when (function-lambda-expression f) + `("Lambda expression:" + (:newline) ,(princ-to-string + (function-lambda-expression f)) (:newline))))) + +;;; Although by convention toString() is supposed to be a +;;; non-computationally expensive operation this isn't always the +;;; case, so make its computation a user interaction. +(defparameter *to-string-hashtable* (make-hash-table)) +(defmethod emacs-inspect ((o java:java-object)) + (let ((to-string (lambda () + (handler-case + (setf (gethash o *to-string-hashtable*) + (java:jcall "toString" o)) + (t (e) + (setf (gethash o *to-string-hashtable*) + (format nil + "Could not invoke toString(): ~A" + e))))))) + (append + (if (gethash o *to-string-hashtable*) + (label-value-line "toString()" (gethash o *to-string-hashtable*)) + `((:action "[compute toString()]" ,to-string) (:newline))) + (loop :for (label . value) :in (sys:inspected-parts o) + :appending (label-value-line label value))))) + +;;;; Multithreading + +(defimplementation spawn (fn &key name) + (threads:make-thread (lambda () (funcall fn)) :name name)) + +(defvar *thread-plists* (make-hash-table) ; should be a weak table + "A hashtable mapping threads to a plist.") + +(defvar *thread-id-counter* 0) + +(defimplementation thread-id (thread) + (threads:synchronized-on *thread-plists* + (or (getf (gethash thread *thread-plists*) 'id) + (setf (getf (gethash thread *thread-plists*) 'id) + (incf *thread-id-counter*))))) + +(defimplementation find-thread (id) + (find id (all-threads) + :key (lambda (thread) + (getf (gethash thread *thread-plists*) 'id)))) + +(defimplementation thread-name (thread) + (threads:thread-name thread)) + +(defimplementation thread-status (thread) + (format nil "Thread is ~:[dead~;alive~]" (threads:thread-alive-p thread))) + +(defimplementation make-lock (&key name) + (declare (ignore name)) + (threads:make-thread-lock)) + +(defimplementation call-with-lock-held (lock function) + (threads:with-thread-lock (lock) (funcall function))) + +(defimplementation current-thread () + (threads:current-thread)) + +(defimplementation all-threads () + (copy-list (threads:mapcar-threads #'identity))) + +(defimplementation thread-alive-p (thread) + (member thread (all-threads))) + +(defimplementation interrupt-thread (thread fn) + (threads:interrupt-thread thread fn)) + +(defimplementation kill-thread (thread) + (threads:destroy-thread thread)) + +(defstruct mailbox + (queue '())) + +(defun mailbox (thread) + "Return THREAD's mailbox." + (threads:synchronized-on *thread-plists* + (or (getf (gethash thread *thread-plists*) 'mailbox) + (setf (getf (gethash thread *thread-plists*) 'mailbox) + (make-mailbox))))) + +(defimplementation send (thread message) + (let ((mbox (mailbox thread))) + (threads:synchronized-on mbox + (setf (mailbox-queue mbox) + (nconc (mailbox-queue mbox) (list message))) + (threads:object-notify-all mbox)))) + +(defimplementation receive-if (test &optional timeout) + (let* ((mbox (mailbox (current-thread)))) + (assert (or (not timeout) (eq timeout t))) + (loop + (check-slime-interrupts) + (threads:synchronized-on mbox + (let* ((q (mailbox-queue mbox)) + (tail (member-if test q))) + (when tail + (setf (mailbox-queue mbox) (nconc (ldiff q tail) (cdr tail))) + (return (car tail))) + (when (eq timeout t) (return (values nil t))) + (threads:object-wait mbox 0.3)))))) + +(defimplementation quit-lisp () + (ext:exit)) +;;; +#+#.(swank/backend:with-symbol 'package-local-nicknames 'ext) +(defimplementation package-local-nicknames (package) + (ext:package-local-nicknames package)) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/allegro.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/allegro.lisp new file mode 100644 index 0000000..63f4b6f --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/allegro.lisp @@ -0,0 +1,1070 @@ +;;;; -*- indent-tabs-mode: nil; outline-regexp: ";;;;;* "; -*- +;;; +;;; swank-allegro.lisp --- Allegro CL specific code for SLIME. +;;; +;;; Created 2003 +;;; +;;; This code has been placed in the Public Domain. All warranties +;;; are disclaimed. +;;; + +(defpackage swank/allegro + (:use cl swank/backend)) + +(in-package swank/allegro) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (require :sock) + (require :process) + #+(version>= 8 2) + (require 'lldb)) + +(defimplementation gray-package-name () + '#:excl) + +;;; swank-mop + +(import-swank-mop-symbols :clos '(:slot-definition-documentation)) + +(defun swank-mop:slot-definition-documentation (slot) + (documentation slot t)) + + +;;;; UTF8 + +(define-symbol-macro utf8-ef + (load-time-value + (excl:crlf-base-ef (excl:find-external-format :utf-8)) + t)) + +(defimplementation string-to-utf8 (s) + (excl:string-to-octets s :external-format utf8-ef + :null-terminate nil)) + +(defimplementation utf8-to-string (u) + (excl:octets-to-string u :external-format utf8-ef)) + + +;;;; TCP Server + +(defimplementation preferred-communication-style () + :spawn) + +(defimplementation create-socket (host port &key backlog) + (socket:make-socket :connect :passive :local-port port + :local-host host :reuse-address t + :backlog (or backlog 5))) + +(defimplementation local-port (socket) + (socket:local-port socket)) + +(defimplementation close-socket (socket) + (close socket)) + +(defimplementation accept-connection (socket &key external-format buffering + timeout) + (declare (ignore buffering timeout)) + (let ((s (socket:accept-connection socket :wait t))) + (when external-format + (setf (stream-external-format s) external-format)) + s)) + +(defimplementation socket-fd (stream) + (excl::stream-input-handle stream)) + +(defvar *external-format-to-coding-system* + '((:iso-8859-1 + "latin-1" "latin-1-unix" "iso-latin-1-unix" + "iso-8859-1" "iso-8859-1-unix") + (:utf-8 "utf-8" "utf-8-unix") + (:euc-jp "euc-jp" "euc-jp-unix") + (:us-ascii "us-ascii" "us-ascii-unix") + (:emacs-mule "emacs-mule" "emacs-mule-unix"))) + +(defimplementation find-external-format (coding-system) + (let ((e (rassoc-if (lambda (x) (member coding-system x :test #'equal)) + *external-format-to-coding-system*))) + (and e (excl:crlf-base-ef + (excl:find-external-format (car e) + :try-variant t))))) + +;;;; Unix signals + +(defimplementation getpid () + (excl::getpid)) + +(defimplementation lisp-implementation-type-name () + "allegro") + +(defimplementation set-default-directory (directory) + (let* ((dir (namestring (truename (merge-pathnames directory))))) + (setf *default-pathname-defaults* (pathname (excl:chdir dir))) + dir)) + +(defimplementation default-directory () + (namestring (excl:current-directory))) + +;;;; Misc + +(defimplementation arglist (symbol) + (handler-case (excl:arglist symbol) + (simple-error () :not-available))) + +(defimplementation macroexpand-all (form &optional env) + (declare (ignore env)) + #+(version>= 8 0) + (excl::walk-form form) + #-(version>= 8 0) + (excl::walk form)) + +(defimplementation describe-symbol-for-emacs (symbol) + (let ((result '())) + (flet ((doc (kind &optional (sym symbol)) + (or (documentation sym kind) :not-documented)) + (maybe-push (property value) + (when value + (setf result (list* property value result))))) + (maybe-push + :variable (when (boundp symbol) + (doc 'variable))) + (maybe-push + :function (if (fboundp symbol) + (doc 'function))) + (maybe-push + :class (if (find-class symbol nil) + (doc 'class))) + result))) + +(defimplementation describe-definition (symbol namespace) + (ecase namespace + (:variable + (describe symbol)) + ((:function :generic-function) + (describe (symbol-function symbol))) + (:class + (describe (find-class symbol))))) + +(defimplementation type-specifier-p (symbol) + (or (ignore-errors + (subtypep nil symbol)) + (not (eq (type-specifier-arglist symbol) :not-available)))) + +(defimplementation function-name (f) + (check-type f function) + (cross-reference::object-to-function-name f)) + +;;;; Debugger + +(defvar *sldb-topframe*) + +(defimplementation call-with-debugging-environment (debugger-loop-fn) + (let ((*sldb-topframe* (find-topframe)) + (excl::*break-hook* nil)) + (funcall debugger-loop-fn))) + +(defimplementation sldb-break-at-start (fname) + ;; :print-before is kind of mis-used but we just want to stuff our + ;; break form somewhere. This does not work for setf, :before and + ;; :after methods, which need special syntax in the trace call, see + ;; ACL's doc/debugging.htm chapter 10. + (eval `(trace (,fname + :print-before + ((break "Function start breakpoint of ~A" ',fname))))) + `(:ok ,(format nil "Set breakpoint at start of ~S" fname))) + +(defun find-topframe () + (let ((magic-symbol (intern (symbol-name :swank-debugger-hook) + (find-package :swank))) + (top-frame (excl::int-newest-frame (excl::current-thread)))) + (loop for frame = top-frame then (next-frame frame) + for i from 0 + while (and frame (< i 30)) + when (eq (debugger:frame-name frame) magic-symbol) + return (next-frame frame) + finally (return top-frame)))) + +(defun next-frame (frame) + (let ((next (excl::int-next-older-frame frame))) + (cond ((not next) nil) + ((debugger:frame-visible-p next) next) + (t (next-frame next))))) + +(defun nth-frame (index) + (do ((frame *sldb-topframe* (next-frame frame)) + (i index (1- i))) + ((zerop i) frame))) + +(defimplementation compute-backtrace (start end) + (let ((end (or end most-positive-fixnum))) + (loop for f = (nth-frame start) then (next-frame f) + for i from start below end + while f collect f))) + +(defimplementation print-frame (frame stream) + (debugger:output-frame stream frame :moderate)) + +(defimplementation frame-locals (index) + (let ((frame (nth-frame index))) + (loop for i from 0 below (debugger:frame-number-vars frame) + collect (list :name (debugger:frame-var-name frame i) + :id 0 + :value (debugger:frame-var-value frame i))))) + +(defimplementation frame-var-value (frame var) + (let ((frame (nth-frame frame))) + (debugger:frame-var-value frame var))) + +(defimplementation disassemble-frame (index) + (let ((frame (nth-frame index))) + (multiple-value-bind (x fun xx xxx pc) (debugger::dyn-fd-analyze frame) + (format t "pc: ~d (~s ~s ~s)~%fun: ~a~%" pc x xx xxx fun) + (disassemble (debugger:frame-function frame))))) + +(defimplementation frame-source-location (index) + (let* ((frame (nth-frame index))) + (multiple-value-bind (x fun xx xxx pc) (debugger::dyn-fd-analyze frame) + (declare (ignore x xx xxx)) + (cond ((and pc + #+(version>= 8 2) + (pc-source-location fun pc) + #-(version>= 8 2) + (function-source-location fun))) + (t ; frames for unbound functions etc end up here + (cadr (car (fspec-definition-locations + (car (debugger:frame-expression frame)))))))))) + +(defun function-source-location (fun) + (cadr (car (fspec-definition-locations + (xref::object-to-function-name fun))))) + +#+(version>= 8 2) +(defun pc-source-location (fun pc) + (let* ((debug-info (excl::function-source-debug-info fun))) + (cond ((not debug-info) + (function-source-location fun)) + (t + (let* ((code-loc (find-if (lambda (c) + (<= (- pc (sys::natural-width)) + (let ((x (excl::ldb-code-pc c))) + (or x -1)) + pc)) + debug-info))) + (cond ((not code-loc) + (ldb-code-to-src-loc (aref debug-info 0))) + (t + (ldb-code-to-src-loc code-loc)))))))) + +#+(version>= 8 2) +(defun ldb-code-to-src-loc (code) + (declare (optimize debug)) + (let* ((func (excl::ldb-code-func code)) + (debug-info (excl::function-source-debug-info func)) + (start (loop for i from (excl::ldb-code-index code) downto 0 + for bpt = (aref debug-info i) + for start = (excl::ldb-code-start-char bpt) + when start + return (if (listp start) + (first start) + start))) + (src-file (excl:source-file func))) + (cond (start + (buffer-or-file-location src-file start)) + (func + (let* ((debug-info (excl::function-source-debug-info func)) + (whole (aref debug-info 0)) + (paths (source-paths-of (excl::ldb-code-source whole) + (excl::ldb-code-source code))) + (path (if paths (longest-common-prefix paths) '())) + (start 0)) + (buffer-or-file + src-file + (lambda (file) + (make-location `(:file ,file) + `(:source-path (0 . ,path) ,start))) + (lambda (buffer bstart) + (make-location `(:buffer ,buffer) + `(:source-path (0 . ,path) + ,(+ bstart start))))))) + (t + nil)))) + +(defun longest-common-prefix (sequences) + (assert sequences) + (flet ((common-prefix (s1 s2) + (let ((diff-pos (mismatch s1 s2))) + (if diff-pos (subseq s1 0 diff-pos) s1)))) + (reduce #'common-prefix sequences))) + +(defun source-paths-of (whole part) + (let ((result '())) + (labels ((walk (form path) + (cond ((eq form part) + (push (reverse path) result)) + ((consp form) + (loop for i from 0 while (consp form) do + (walk (pop form) (cons i path))))))) + (walk whole '()) + (reverse result)))) + +(defimplementation eval-in-frame (form frame-number) + (let ((frame (nth-frame frame-number))) + ;; let-bind lexical variables + (let ((vars (loop for i below (debugger:frame-number-vars frame) + for name = (debugger:frame-var-name frame i) + if (typep name '(and symbol (not null) (not keyword))) + collect `(,name ',(debugger:frame-var-value frame i))))) + (debugger:eval-form-in-context + `(let* ,vars ,form) + (debugger:environment-of-frame frame))))) + +(defimplementation frame-package (frame-number) + (let* ((frame (nth-frame frame-number)) + (exp (debugger:frame-expression frame))) + (typecase exp + ((cons symbol) (symbol-package (car exp))) + ((cons (cons (eql :internal) (cons symbol))) + (symbol-package (cadar exp)))))) + +(defimplementation return-from-frame (frame-number form) + (let ((frame (nth-frame frame-number))) + (multiple-value-call #'debugger:frame-return + frame (debugger:eval-form-in-context + form + (debugger:environment-of-frame frame))))) + +(defimplementation frame-restartable-p (frame) + (handler-case (debugger:frame-retryable-p frame) + (serious-condition (c) + (funcall (read-from-string "swank::background-message") + "~a ~a" frame (princ-to-string c)) + nil))) + +(defimplementation restart-frame (frame-number) + (let ((frame (nth-frame frame-number))) + (cond ((debugger:frame-retryable-p frame) + (apply #'debugger:frame-retry frame (debugger:frame-function frame) + (cdr (debugger:frame-expression frame)))) + (t "Frame is not retryable")))) + +;;;; Compiler hooks + +(defvar *buffer-name* nil) +(defvar *buffer-start-position*) +(defvar *buffer-string*) +(defvar *compile-filename* nil) + +(defun compiler-note-p (object) + (member (type-of object) '(excl::compiler-note compiler::compiler-note))) + +(defun redefinition-p (condition) + (and (typep condition 'style-warning) + (every #'char-equal "redefin" (princ-to-string condition)))) + +(defun compiler-undefined-functions-called-warning-p (object) + (typep object 'excl:compiler-undefined-functions-called-warning)) + +(deftype compiler-note () + `(satisfies compiler-note-p)) + +(deftype redefinition () + `(satisfies redefinition-p)) + +(defun signal-compiler-condition (&rest args) + (apply #'signal 'compiler-condition args)) + +(defun handle-compiler-warning (condition) + (declare (optimize (debug 3) (speed 0) (space 0))) + (cond ((and #-(version>= 10 0) (not *buffer-name*) + (compiler-undefined-functions-called-warning-p condition)) + (handle-undefined-functions-warning condition)) + ((and (typep condition 'excl::compiler-note) + (let ((format (slot-value condition 'excl::format-control))) + (and (search "Closure" format) + (search "will be stack allocated" format)))) + ;; Ignore "Closure will be stack allocated" notes. + ;; That occurs often but is usually uninteresting. + ) + (t + (signal-compiler-condition + :original-condition condition + :severity (etypecase condition + (redefinition :redefinition) + (style-warning :style-warning) + (warning :warning) + (compiler-note :note) + (reader-error :read-error) + (error :error)) + :message (format nil "~A" condition) + :location (compiler-warning-location condition))))) + +(defun condition-pathname-and-position (condition) + (let* ((context #+(version>= 10 0) + (getf (slot-value condition 'excl::plist) + :source-context)) + (location-available (and context + (excl::source-context-start-char context)))) + (cond (location-available + (values (excl::source-context-pathname context) + (when-let (start-char (excl::source-context-start-char context)) + (let ((position (if (listp start-char) ; HACK + (first start-char) + start-char))) + (if (typep condition 'excl::compiler-free-reference-warning) + position + (1+ position)))))) + ((typep condition 'reader-error) + (let ((pos (car (last (slot-value condition 'excl::format-arguments)))) + (file (pathname (stream-error-stream condition)))) + (when (integerp pos) + (values file pos)))) + (t + (let ((loc (getf (slot-value condition 'excl::plist) :loc))) + (when loc + (destructuring-bind (file . pos) loc + (let ((start (if (consp pos) ; 8.2 and newer + #+(version>= 10 1) + (if (typep condition 'excl::compiler-inconsistent-name-usage-warning) + (second pos) + (first pos)) + #-(version>= 10 1) + (first pos) + pos))) + (values file start))))))))) + +(defun compiler-warning-location (condition) + (multiple-value-bind (pathname position) + (condition-pathname-and-position condition) + (cond (*buffer-name* + (make-location + (list :buffer *buffer-name*) + (if position + (list :offset 1 (1- position)) + (list :offset *buffer-start-position* 0)))) + (pathname + (make-location + (list :file (namestring (truename pathname))) + #+(version>= 10 1) + (list :offset 1 position) + #-(version>= 10 1) + (list :position (1+ position)))) + (t + (make-error-location "No error location available."))))) + +;; TODO: report it as a bug to Franz that the condition's plist +;; slot contains (:loc nil). +(defun handle-undefined-functions-warning (condition) + (let ((fargs (slot-value condition 'excl::format-arguments))) + (loop for (fname . locs) in (car fargs) do + (dolist (loc locs) + (multiple-value-bind (pos file) (ecase (length loc) + (2 (values-list loc)) + (3 (destructuring-bind + (start end file) loc + (declare (ignore end)) + (values start file)))) + (signal-compiler-condition + :original-condition condition + :severity :warning + :message (format nil "Undefined function referenced: ~S" + fname) + :location (make-location (list :file file) + #+(version>= 9 0) + (list :offset 1 pos) + #-(version>= 9 0) + (list :position (1+ pos))))))))) + +(defimplementation call-with-compilation-hooks (function) + (handler-bind ((warning #'handle-compiler-warning) + (compiler-note #'handle-compiler-warning) + (reader-error #'handle-compiler-warning)) + (funcall function))) + +(defimplementation swank-compile-file (input-file output-file + load-p external-format + &key policy) + (declare (ignore policy)) + (handler-case + (with-compilation-hooks () + (let ((*buffer-name* nil) + (*compile-filename* input-file) + #+(version>= 8 2) + (compiler:save-source-level-debug-info-switch t) + (excl:*load-source-file-info* t) + #+(version>= 8 2) + (excl:*load-source-debug-info* t)) + (compile-file *compile-filename* + :output-file output-file + :load-after-compile load-p + :external-format external-format))) + (reader-error () (values nil nil t)))) + +(defun call-with-temp-file (fn) + (let ((tmpname (system:make-temp-file-name))) + (unwind-protect + (with-open-file (file tmpname :direction :output :if-exists :error) + (funcall fn file tmpname)) + (delete-file tmpname)))) + +(defvar *temp-file-map* (make-hash-table :test #'equal) + "A mapping from tempfile names to Emacs buffer names.") + +(defun write-tracking-preamble (stream file file-offset) + "Instrument the top of the temporary file to be compiled. + +The header tells allegro that any definitions compiled in the temp +file should be found in FILE exactly at FILE-OFFSET. To get Allegro +to do this, this factors in the length of the inserted header itself." + (with-standard-io-syntax + (let* ((*package* (find-package :keyword)) + (source-pathname-form + `(cl:eval-when (:compile-toplevel :load-toplevel :execute) + (cl:setq excl::*source-pathname* + (pathname ,(sys::frob-source-file file))))) + (source-pathname-string (write-to-string source-pathname-form)) + (position-form-length-bound 160) ; should be enough for everyone + (header-length (+ (length source-pathname-string) + position-form-length-bound)) + (position-form + `(cl:eval-when (:compile-toplevel :load-toplevel :execute) + (cl:setq excl::*partial-source-file-p* ,(- file-offset + header-length + 1 ; for the newline + )))) + (position-form-string (write-to-string position-form)) + (padding-string (make-string (- position-form-length-bound + (length position-form-string)) + :initial-element #\;))) + (write-string source-pathname-string stream) + (write-string position-form-string stream) + (write-string padding-string stream) + (write-char #\newline stream)))) + +(defun compile-from-temp-file (string buffer offset file) + (call-with-temp-file + (lambda (stream filename) + (when (and file offset (probe-file file)) + (write-tracking-preamble stream file offset)) + (write-string string stream) + (finish-output stream) + (multiple-value-bind (binary-filename warnings? failure?) + (let ((sys:*source-file-types* '(nil)) ; suppress .lisp extension + #+(version>= 8 2) + (compiler:save-source-level-debug-info-switch t) + (excl:*redefinition-warnings* nil)) + (compile-file filename)) + (declare (ignore warnings?)) + (when binary-filename + (let ((excl:*load-source-file-info* t) + #+(version>= 8 2) + (excl:*load-source-debug-info* t)) + excl::*source-pathname* + (load binary-filename)) + (when (and buffer offset (or (not file) + (not (probe-file file)))) + (setf (gethash (pathname stream) *temp-file-map*) + (list buffer offset))) + (delete-file binary-filename)) + (not failure?))))) + +(defimplementation swank-compile-string (string &key buffer position filename + policy) + (declare (ignore policy)) + (handler-case + (with-compilation-hooks () + (let ((*buffer-name* buffer) + (*buffer-start-position* position) + (*buffer-string* string)) + (compile-from-temp-file string buffer position filename))) + (reader-error () nil))) + +;;;; Definition Finding + +(defun buffer-or-file (file file-fun buffer-fun) + (let* ((probe (gethash file *temp-file-map*))) + (cond (probe + (destructuring-bind (buffer start) probe + (funcall buffer-fun buffer start))) + (t (funcall file-fun (namestring (truename file))))))) + +(defun buffer-or-file-location (file offset) + (buffer-or-file file + (lambda (filename) + (make-location `(:file ,filename) + `(:position ,(1+ offset)))) + (lambda (buffer start) + (make-location `(:buffer ,buffer) + `(:offset ,start ,offset))))) + +(defun fspec-primary-name (fspec) + (etypecase fspec + (symbol fspec) + (list (fspec-primary-name (second fspec))))) + +(defun find-definition-in-file (fspec type file top-level) + (let* ((part + (or (scm::find-definition-in-definition-group + fspec type (scm:section-file :file file) + :top-level top-level) + (scm::find-definition-in-definition-group + (fspec-primary-name fspec) + type (scm:section-file :file file) + :top-level top-level))) + (start (and part + (scm::source-part-start part))) + (pos (if start + (list :offset 1 start) + (list :function-name (string (fspec-primary-name fspec)))))) + (make-location (list :file (namestring (truename file))) + pos))) + +(defun find-fspec-location (fspec type file top-level) + (handler-case + (etypecase file + (pathname + (let ((probe (gethash file *temp-file-map*))) + (cond (probe + (destructuring-bind (buffer offset) probe + (make-location `(:buffer ,buffer) + `(:offset ,offset 0)))) + (t + (find-definition-in-file fspec type file top-level))))) + ((member :top-level) + (make-error-location "Defined at toplevel: ~A" + (fspec->string fspec)))) + (error (e) + (make-error-location "Error: ~A" e)))) + +(defun fspec->string (fspec) + (typecase fspec + (symbol (let ((*package* (find-package :keyword))) + (prin1-to-string fspec))) + (list (format nil "(~A ~A)" + (prin1-to-string (first fspec)) + (let ((*package* (find-package :keyword))) + (prin1-to-string (second fspec))))) + (t (princ-to-string fspec)))) + +(defun fspec-definition-locations (fspec) + (cond + ((and (listp fspec) (eq (car fspec) :internal)) + (destructuring-bind (_internal next _n) fspec + (declare (ignore _internal _n)) + (fspec-definition-locations next))) + (t + (let ((defs (excl::find-source-file fspec))) + (when (and (null defs) + (listp fspec) + (string= (car fspec) '#:method)) + ;; If methods are defined in a defgeneric form, the source location is + ;; recorded for the gf but not for the methods. Therefore fall back to + ;; the gf as the likely place of definition. + (setq defs (excl::find-source-file (second fspec)))) + (if (null defs) + (list + (list fspec + (make-error-location "Unknown source location for ~A" + (fspec->string fspec)))) + (loop for (fspec type file top-level) in defs collect + (list (list type fspec) + (find-fspec-location fspec type file top-level)))))))) + +(defimplementation find-definitions (symbol) + (fspec-definition-locations symbol)) + +(defimplementation find-source-location (obj) + (first (rest (first (fspec-definition-locations obj))))) + +;;;; XREF + +(defmacro defxref (name relation name1 name2) + `(defimplementation ,name (x) + (xref-result (xref:get-relation ,relation ,name1 ,name2)))) + +(defxref who-calls :calls :wild x) +(defxref calls-who :calls x :wild) +(defxref who-references :uses :wild x) +(defxref who-binds :binds :wild x) +(defxref who-macroexpands :macro-calls :wild x) +(defxref who-sets :sets :wild x) + +(defun xref-result (fspecs) + (loop for fspec in fspecs + append (fspec-definition-locations fspec))) + +;; list-callers implemented by groveling through all fbound symbols. +;; Only symbols are considered. Functions in the constant pool are +;; searched recursively. Closure environments are ignored at the +;; moment (constants in methods are therefore not found). + +(defun map-function-constants (function fn depth) + "Call FN with the elements of FUNCTION's constant pool." + (do ((i 0 (1+ i)) + (max (excl::function-constant-count function))) + ((= i max)) + (let ((c (excl::function-constant function i))) + (cond ((and (functionp c) + (not (eq c function)) + (plusp depth)) + (map-function-constants c fn (1- depth))) + (t + (funcall fn c)))))) + +(defun in-constants-p (fun symbol) + (map-function-constants fun + (lambda (c) + (when (eq c symbol) + (return-from in-constants-p t))) + 3)) + +(defun function-callers (name) + (let ((callers '())) + (do-all-symbols (sym) + (when (fboundp sym) + (let ((fn (fdefinition sym))) + (when (in-constants-p fn name) + (push sym callers))))) + callers)) + +(defimplementation list-callers (name) + (xref-result (function-callers name))) + +(defimplementation list-callees (name) + (let ((result '())) + (map-function-constants (fdefinition name) + (lambda (c) + (when (fboundp c) + (push c result))) + 2) + (xref-result result))) + +;;;; Profiling + +;; Per-function profiling based on description in +;; http://www.franz.com/support/documentation/8.0/\ +;; doc/runtime-analyzer.htm#data-collection-control-2 + +(defvar *profiled-functions* ()) +(defvar *profile-depth* 0) + +(defmacro with-redirected-y-or-n-p (&body body) + ;; If the profiler is restarted when the data from the previous + ;; session is not reported yet, the user is warned via Y-OR-N-P. + ;; As the CL:Y-OR-N-P question is (for some reason) not directly + ;; sent to the Slime user, the function CL:Y-OR-N-P is temporarily + ;; overruled. + `(let* ((pkg (find-package :common-lisp)) + (saved-pdl (excl::package-definition-lock pkg)) + (saved-ynp (symbol-function 'cl:y-or-n-p))) + (setf (excl::package-definition-lock pkg) nil + (symbol-function 'cl:y-or-n-p) + (symbol-function (read-from-string "swank:y-or-n-p-in-emacs"))) + (unwind-protect + (progn ,@body) + (setf (symbol-function 'cl:y-or-n-p) saved-ynp + (excl::package-definition-lock pkg) saved-pdl)))) + +(defun start-acl-profiler () + (with-redirected-y-or-n-p + (prof:start-profiler :type :time :count t + :start-sampling-p nil :verbose nil))) +(defun acl-profiler-active-p () + (not (eq (prof:profiler-status :verbose nil) :inactive))) + +(defun stop-acl-profiler () + (prof:stop-profiler :verbose nil)) + +(excl:def-fwrapper profile-fwrapper (&rest args) + ;; Ensures sampling is done during the execution of the function, + ;; taking into account recursion. + (declare (ignore args)) + (cond ((zerop *profile-depth*) + (let ((*profile-depth* (1+ *profile-depth*))) + (prof:start-sampling) + (unwind-protect (excl:call-next-fwrapper) + (prof:stop-sampling)))) + (t + (excl:call-next-fwrapper)))) + +(defimplementation profile (fname) + (unless (acl-profiler-active-p) + (start-acl-profiler)) + (excl:fwrap fname 'profile-fwrapper 'profile-fwrapper) + (push fname *profiled-functions*)) + +(defimplementation profiled-functions () + *profiled-functions*) + +(defimplementation unprofile (fname) + (excl:funwrap fname 'profile-fwrapper) + (setq *profiled-functions* (remove fname *profiled-functions*))) + +(defimplementation profile-report () + (prof:show-flat-profile :verbose nil) + (when *profiled-functions* + (start-acl-profiler))) + +(defimplementation profile-reset () + (when (acl-profiler-active-p) + (stop-acl-profiler) + (start-acl-profiler)) + "Reset profiling counters.") + +;;;; Inspecting + +(excl:without-redefinition-warnings +(defmethod emacs-inspect ((o t)) + (allegro-inspect o))) + +(defmethod emacs-inspect ((o function)) + (allegro-inspect o)) + +(defmethod emacs-inspect ((o standard-object)) + (allegro-inspect o)) + +(defun allegro-inspect (o) + (loop for (d dd) on (inspect::inspect-ctl o) + append (frob-allegro-field-def o d) + until (eq d dd))) + +(defun frob-allegro-field-def (object def) + (with-struct (inspect::field-def- name type access) def + (ecase type + ((:unsigned-word :unsigned-byte :unsigned-natural + :unsigned-long :unsigned-half-long + :unsigned-3byte :unsigned-long32) + (label-value-line name (inspect::component-ref-v object access type))) + ((:lisp :value :func) + (label-value-line name (inspect::component-ref object access))) + (:indirect + (destructuring-bind (prefix count ref set) access + (declare (ignore set prefix)) + (loop for i below (funcall count object) + append (label-value-line (format nil "~A-~D" name i) + (funcall ref object i)))))))) + +;;;; Multithreading + +(defimplementation initialize-multiprocessing (continuation) + (mp:start-scheduler) + (funcall continuation)) + +(defimplementation spawn (fn &key name) + (mp:process-run-function name fn)) + +(defvar *id-lock* (mp:make-process-lock :name "id lock")) +(defvar *thread-id-counter* 0) + +(defimplementation thread-id (thread) + (mp:with-process-lock (*id-lock*) + (or (getf (mp:process-property-list thread) 'id) + (setf (getf (mp:process-property-list thread) 'id) + (incf *thread-id-counter*))))) + +(defimplementation find-thread (id) + (find id mp:*all-processes* + :key (lambda (p) (getf (mp:process-property-list p) 'id)))) + +(defimplementation thread-name (thread) + (mp:process-name thread)) + +(defimplementation thread-status (thread) + (princ-to-string (mp:process-whostate thread))) + +(defimplementation thread-attributes (thread) + (list :priority (mp:process-priority thread) + :times-resumed (mp:process-times-resumed thread))) + +(defimplementation make-lock (&key name) + (mp:make-process-lock :name name)) + +(defimplementation call-with-lock-held (lock function) + (mp:with-process-lock (lock) (funcall function))) + +(defimplementation current-thread () + mp:*current-process*) + +(defimplementation all-threads () + (copy-list mp:*all-processes*)) + +(defimplementation interrupt-thread (thread fn) + (mp:process-interrupt thread fn)) + +(defimplementation kill-thread (thread) + (mp:process-kill thread)) + +(defvar *mailbox-lock* (mp:make-process-lock :name "mailbox lock")) + +(defstruct (mailbox (:conc-name mailbox.)) + (lock (mp:make-process-lock :name "process mailbox")) + (queue '() :type list) + (gate (mp:make-gate nil))) + +(defun mailbox (thread) + "Return THREAD's mailbox." + (mp:with-process-lock (*mailbox-lock*) + (or (getf (mp:process-property-list thread) 'mailbox) + (setf (getf (mp:process-property-list thread) 'mailbox) + (make-mailbox))))) + +(defimplementation send (thread message) + (let* ((mbox (mailbox thread))) + (mp:with-process-lock ((mailbox.lock mbox)) + (setf (mailbox.queue mbox) + (nconc (mailbox.queue mbox) (list message))) + (mp:open-gate (mailbox.gate mbox))))) + +(defimplementation receive-if (test &optional timeout) + (let ((mbox (mailbox mp:*current-process*))) + (assert (or (not timeout) (eq timeout t))) + (loop + (check-slime-interrupts) + (mp:with-process-lock ((mailbox.lock mbox)) + (let* ((q (mailbox.queue mbox)) + (tail (member-if test q))) + (when tail + (setf (mailbox.queue mbox) (nconc (ldiff q tail) (cdr tail))) + (return (car tail))) + (mp:close-gate (mailbox.gate mbox)))) + (when (eq timeout t) (return (values nil t))) + (mp:process-wait-with-timeout "receive-if" 0.5 + #'mp:gate-open-p (mailbox.gate mbox))))) + +(let ((alist '()) + (lock (mp:make-process-lock :name "register-thread"))) + + (defimplementation register-thread (name thread) + (declare (type symbol name)) + (mp:with-process-lock (lock) + (etypecase thread + (null + (setf alist (delete name alist :key #'car))) + (mp:process + (let ((probe (assoc name alist))) + (cond (probe (setf (cdr probe) thread)) + (t (setf alist (acons name thread alist)))))))) + nil) + + (defimplementation find-registered (name) + (mp:with-process-lock (lock) + (cdr (assoc name alist))))) + +(defimplementation set-default-initial-binding (var form) + (push (cons var form) + #+(version>= 9 0) + excl:*required-thread-bindings* + #-(version>= 9 0) + excl::required-thread-bindings)) + +(defimplementation quit-lisp () + (excl:exit 0 :quiet t)) + + +;;Trace implementations +;;In Allegro 7.0, we have: +;; (trace ) +;; (trace ((method ? (+)))) +;; (trace ((labels ))) +;; (trace ((labels (method (+)) ))) +;; can be a normal name or a (setf name) + +(defimplementation toggle-trace (spec) + (ecase (car spec) + ((setf) + (toggle-trace-aux spec)) + (:defgeneric (toggle-trace-generic-function-methods (second spec))) + ((setf :defmethod :labels :flet) + (toggle-trace-aux (process-fspec-for-allegro spec))) + (:call + (destructuring-bind (caller callee) (cdr spec) + (toggle-trace-aux callee + :inside (list (process-fspec-for-allegro caller))))))) + +(defun tracedp (fspec) + (member fspec (eval '(trace)) :test #'equal)) + +(defun toggle-trace-aux (fspec &rest args) + (cond ((tracedp fspec) + (eval `(untrace ,fspec)) + (format nil "~S is now untraced." fspec)) + (t + (eval `(trace (,fspec ,@args))) + (format nil "~S is now traced." fspec)))) + +(defun toggle-trace-generic-function-methods (name) + (let ((methods (mop:generic-function-methods (fdefinition name)))) + (cond ((tracedp name) + (eval `(untrace ,name)) + (dolist (method methods (format nil "~S is now untraced." name)) + (excl:funtrace (mop:method-function method)))) + (t + (eval `(trace (,name))) + (dolist (method methods (format nil "~S is now traced." name)) + (excl:ftrace (mop:method-function method))))))) + +(defun process-fspec-for-allegro (fspec) + (cond ((consp fspec) + (ecase (first fspec) + ((setf) fspec) + ((:defun :defgeneric) (second fspec)) + ((:defmethod) `(method ,@(rest fspec))) + ((:labels) `(labels ,(process-fspec-for-allegro (second fspec)) + ,(third fspec))) + ((:flet) `(flet ,(process-fspec-for-allegro (second fspec)) + ,(third fspec))))) + (t + fspec))) + + +;;;; Weak hashtables + +(defimplementation make-weak-key-hash-table (&rest args) + (apply #'make-hash-table :weak-keys t args)) + +(defimplementation make-weak-value-hash-table (&rest args) + (apply #'make-hash-table :values :weak args)) + +(defimplementation hash-table-weakness (hashtable) + (cond ((excl:hash-table-weak-keys hashtable) :key) + ((eq (excl:hash-table-values hashtable) :weak) :value))) + + + +;;;; Character names + +(defimplementation character-completion-set (prefix matchp) + (loop for name being the hash-keys of excl::*name-to-char-table* + when (funcall matchp prefix name) + collect (string-capitalize name))) + + +;;;; wrap interface implementation + +(defimplementation wrap (spec indicator &key before after replace) + (let ((allegro-spec (process-fspec-for-allegro spec))) + (excl:fwrap allegro-spec + indicator + (excl:def-fwrapper allegro-wrapper (&rest args) + (let (retlist completed) + (unwind-protect + (progn + (when before + (funcall before args)) + (setq retlist (multiple-value-list + (if replace + (funcall replace args) + (excl:call-next-fwrapper)))) + (setq completed t) + (values-list retlist)) + (when after + (funcall after (if completed + retlist + :exited-non-locally))))))) + allegro-spec)) + +(defimplementation unwrap (spec indicator) + (let ((allegro-spec (process-fspec-for-allegro spec))) + (excl:funwrap allegro-spec indicator) + allegro-spec)) + +(defimplementation wrapped-p (spec indicator) + (getf (excl:fwrap-order (process-fspec-for-allegro spec)) indicator)) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/backend.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/backend.lisp new file mode 100644 index 0000000..eca348e --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/backend.lisp @@ -0,0 +1,1579 @@ +;;; -*- indent-tabs-mode: nil; outline-regexp: ";;;;;*" -*- +;;; +;;; slime-backend.lisp --- SLIME backend interface. +;;; +;;; Created by James Bielman in 2003. Released into the public domain. +;;; +;;;; Frontmatter +;;; +;;; This file defines the functions that must be implemented +;;; separately for each Lisp. Each is declared as a generic function +;;; for which swank-.lisp provides methods. + +(in-package swank/backend) + + +;;;; Metacode + +(defparameter *debug-swank-backend* nil + "If this is true, backends should not catch errors but enter the +debugger where appropriate. Also, they should not perform backtrace +magic but really show every frame including SWANK related ones.") + +(defparameter *interface-functions* '() + "The names of all interface functions.") + +(defparameter *unimplemented-interfaces* '() + "List of interface functions that are not implemented. +DEFINTERFACE adds to this list and DEFIMPLEMENTATION removes.") + +(defvar *log-output* nil) ; should be nil for image dumpers + +(defmacro definterface (name args documentation &rest default-body) + "Define an interface function for the backend to implement. +A function is defined with NAME, ARGS, and DOCUMENTATION. This +function first looks for a function to call in NAME's property list +that is indicated by 'IMPLEMENTATION; failing that, it looks for a +function indicated by 'DEFAULT. If neither is present, an error is +signaled. + +If a DEFAULT-BODY is supplied, then a function with the same body and +ARGS will be added to NAME's property list as the property indicated +by 'DEFAULT. + +Backends implement these functions using DEFIMPLEMENTATION." + (check-type documentation string "a documentation string") + (assert (every #'symbolp args) () + "Complex lambda-list not supported: ~S ~S" name args) + (labels ((gen-default-impl () + `(setf (get ',name 'default) (lambda ,args ,@default-body))) + (args-as-list (args) + (destructuring-bind (req opt key rest) (parse-lambda-list args) + `(,@req ,@opt + ,@(loop for k in key append `(,(kw k) ,k)) + ,@(or rest '(()))))) + (parse-lambda-list (args) + (parse args '(&optional &key &rest) + (make-array 4 :initial-element nil))) + (parse (args keywords vars) + (cond ((null args) + (reverse (map 'list #'reverse vars))) + ((member (car args) keywords) + (parse (cdr args) (cdr (member (car args) keywords)) vars)) + (t (push (car args) (aref vars (length keywords))) + (parse (cdr args) keywords vars)))) + (kw (s) (intern (string s) :keyword))) + `(progn + (defun ,name ,args + ,documentation + (let ((f (or (get ',name 'implementation) + (get ',name 'default)))) + (cond (f (apply f ,@(args-as-list args))) + (t (error "~S not implemented" ',name))))) + (pushnew ',name *interface-functions*) + ,(if (null default-body) + `(pushnew ',name *unimplemented-interfaces*) + (gen-default-impl)) + (eval-when (:compile-toplevel :load-toplevel :execute) + (export ',name :swank/backend)) + ',name))) + +(defmacro defimplementation (name args &body body) + (assert (every #'symbolp args) () + "Complex lambda-list not supported: ~S ~S" name args) + `(progn + (setf (get ',name 'implementation) + ;; For implicit BLOCK. FLET because of interplay w/ decls. + (flet ((,name ,args ,@body)) #',name)) + (if (member ',name *interface-functions*) + (setq *unimplemented-interfaces* + (remove ',name *unimplemented-interfaces*)) + (warn "DEFIMPLEMENTATION of undefined interface (~S)" ',name)) + ',name)) + +(defun warn-unimplemented-interfaces () + "Warn the user about unimplemented backend features. +The portable code calls this function at startup." + (let ((*print-pretty* t)) + (warn "These Swank interfaces are unimplemented:~% ~:<~{~A~^ ~:_~}~:>" + (list (sort (copy-list *unimplemented-interfaces*) #'string<))))) + +(defun import-to-swank-mop (symbol-list) + (dolist (sym symbol-list) + (let* ((swank-mop-sym (find-symbol (symbol-name sym) :swank-mop))) + (when swank-mop-sym + (unintern swank-mop-sym :swank-mop)) + (import sym :swank-mop) + (export sym :swank-mop)))) + +(defun import-swank-mop-symbols (package except) + "Import the mop symbols from PACKAGE to SWANK-MOP. +EXCEPT is a list of symbol names which should be ignored." + (do-symbols (s :swank-mop) + (unless (member s except :test #'string=) + (let ((real-symbol (find-symbol (string s) package))) + (assert real-symbol () "Symbol ~A not found in package ~A" s package) + (unintern s :swank-mop) + (import real-symbol :swank-mop) + (export real-symbol :swank-mop))))) + +(definterface gray-package-name () + "Return a package-name that contains the Gray stream symbols. +This will be used like so: + (defpackage foo + (:import-from #.(gray-package-name) . #.*gray-stream-symbols*)") + + +;;;; Utilities + +(defmacro with-struct ((conc-name &rest names) obj &body body) + "Like with-slots but works only for structs." + (check-type conc-name symbol) + (flet ((reader (slot) + (intern (concatenate 'string + (symbol-name conc-name) + (symbol-name slot)) + (symbol-package conc-name)))) + (let ((tmp (gensym "OO-"))) + ` (let ((,tmp ,obj)) + (symbol-macrolet + ,(loop for name in names collect + (typecase name + (symbol `(,name (,(reader name) ,tmp))) + (cons `(,(first name) (,(reader (second name)) ,tmp))) + (t (error "Malformed syntax in WITH-STRUCT: ~A" name)))) + ,@body))))) + +(defmacro when-let ((var value) &body body) + `(let ((,var ,value)) + (when ,var ,@body))) + +(defun boolean-to-feature-expression (value) + "Converts a boolean VALUE to a form suitable for testing with #+." + (if value + '(:and) + '(:or))) + +(defun with-symbol (name package) + "Check if a symbol with a given NAME exists in PACKAGE and returns a +form suitable for testing with #+." + (boolean-to-feature-expression + (and (find-package package) + (find-symbol (string name) package)))) + +(defun choose-symbol (package name alt-package alt-name) + "If symbol package:name exists return that symbol, otherwise alt-package:alt-name. + Suitable for use with #." + (or (and (find-package package) + (find-symbol (string name) package)) + (find-symbol (string alt-name) alt-package))) + + +;;;; UFT8 + +(deftype octet () '(unsigned-byte 8)) +(deftype octets () '(simple-array octet (*))) + +;; Helper function. Decode the next N bytes starting from INDEX. +;; Return the decoded char and the new index. +(defun utf8-decode-aux (buffer index limit byte0 n) + (declare (type octets buffer) (fixnum index limit byte0 n)) + (if (< (- limit index) n) + (values nil index) + (do ((i 0 (1+ i)) + (code byte0 (let ((byte (aref buffer (+ index i)))) + (cond ((= (ldb (byte 2 6) byte) #b10) + (+ (ash code 6) (ldb (byte 6 0) byte))) + (t + (error "Invalid encoding")))))) + ((= i n) + (values (cond ((<= code #xff) (code-char code)) + ((<= #xd800 code #xdfff) + (error "Invalid Unicode code point: #x~x" code)) + ((and (< code char-code-limit) + (code-char code))) + (t + (error + "Can't represent code point: #x~x ~ + (char-code-limit is #x~x)" + code char-code-limit))) + (+ index n)))))) + +;; Decode one character in BUFFER starting at INDEX. +;; Return 2 values: the character and the new index. +;; If there aren't enough bytes between INDEX and LIMIT return nil. +(defun utf8-decode (buffer index limit) + (declare (type octets buffer) (fixnum index limit)) + (if (= index limit) + (values nil index) + (let ((b (aref buffer index))) + (if (<= b #x7f) + (values (code-char b) (1+ index)) + (macrolet ((try (marker else) + (let* ((l (integer-length marker)) + (n (- l 2))) + `(if (= (ldb (byte ,l ,(- 8 l)) b) ,marker) + (utf8-decode-aux buffer (1+ index) limit + (ldb (byte ,(- 8 l) 0) b) + ,n) + ,else)))) + (try #b110 + (try #b1110 + (try #b11110 + (try #b111110 + (try #b1111110 + (error "Invalid encoding"))))))))))) + +;; Decode characters from BUFFER and write them to STRING. +;; Return 2 values: LASTINDEX and LASTSTART where +;; LASTINDEX is the last index in BUFFER that was not decoded +;; and LASTSTART is the last index in STRING not written. +(defun utf8-decode-into (buffer index limit string start end) + (declare (string string) (fixnum index limit start end) (type octets buffer)) + (loop + (cond ((= start end) + (return (values index start))) + (t + (multiple-value-bind (c i) (utf8-decode buffer index limit) + (cond (c + (setf (aref string start) c) + (setq index i) + (setq start (1+ start))) + (t + (return (values index start))))))))) + +(defun default-utf8-to-string (octets) + (let* ((limit (length octets)) + (str (make-string limit))) + (multiple-value-bind (i s) (utf8-decode-into octets 0 limit str 0 limit) + (if (= i limit) + (if (= limit s) + str + (adjust-array str s)) + (loop + (let ((end (+ (length str) (- limit i)))) + (setq str (adjust-array str end)) + (multiple-value-bind (i2 s2) + (utf8-decode-into octets i limit str s end) + (cond ((= i2 limit) + (return (adjust-array str s2))) + (t + (setq i i2) + (setq s s2)))))))))) + +(defmacro utf8-encode-aux (code buffer start end n) + `(cond ((< (- ,end ,start) ,n) + ,start) + (t + (setf (aref ,buffer ,start) + (dpb (ldb (byte ,(- 7 n) ,(* 6 (1- n))) ,code) + (byte ,(- 7 n) 0) + ,(dpb 0 (byte 1 (- 7 n)) #xff))) + ,@(loop for i from 0 upto (- n 2) collect + `(setf (aref ,buffer (+ ,start ,(- n 1 i))) + (dpb (ldb (byte 6 ,(* 6 i)) ,code) + (byte 6 0) + #b10111111))) + (+ ,start ,n)))) + +(defun %utf8-encode (code buffer start end) + (declare (type (unsigned-byte 31) code) (type octets buffer) + (type (and fixnum unsigned-byte) start end)) + (cond ((<= code #x7f) + (cond ((< start end) + (setf (aref buffer start) code) + (1+ start)) + (t start))) + ((<= code #x7ff) (utf8-encode-aux code buffer start end 2)) + ((<= #xd800 code #xdfff) + (error "Invalid Unicode code point (surrogate): #x~x" code)) + ((<= code #xffff) (utf8-encode-aux code buffer start end 3)) + ((<= code #x1fffff) (utf8-encode-aux code buffer start end 4)) + ((<= code #x3ffffff) (utf8-encode-aux code buffer start end 5)) + (t (utf8-encode-aux code buffer start end 6)))) + +(defun utf8-encode (char buffer start end) + (declare (type character char) (type octets buffer) + (type (and fixnum unsigned-byte) start end)) + (%utf8-encode (char-code char) buffer start end)) + +(defun utf8-encode-into (string start end buffer index limit) + (declare (string string) (type octets buffer) (fixnum start end index limit)) + (loop + (cond ((= start end) + (return (values start index))) + ((= index limit) + (return (values start index))) + (t + (let ((i2 (utf8-encode (char string start) buffer index limit))) + (cond ((= i2 index) + (return (values start index))) + (t + (setq index i2) + (incf start)))))))) + +(defun default-string-to-utf8 (string) + (let* ((len (length string)) + (b (make-array len :element-type 'octet))) + (multiple-value-bind (s i) (utf8-encode-into string 0 len b 0 len) + (if (= s len) + b + (loop + (let ((limit (+ (length b) (- len s)))) + (setq b (coerce (adjust-array b limit) 'octets)) + (multiple-value-bind (s2 i2) + (utf8-encode-into string s len b i limit) + (cond ((= s2 len) + (return (coerce (adjust-array b i2) 'octets))) + (t + (setq i i2) + (setq s s2)))))))))) + +(definterface string-to-utf8 (string) + "Convert the string STRING to a (simple-array (unsigned-byte 8))" + (default-string-to-utf8 string)) + +(definterface utf8-to-string (octets) + "Convert the (simple-array (unsigned-byte 8)) OCTETS to a string." + (default-utf8-to-string octets)) + + +;;;; TCP server + +(definterface create-socket (host port &key backlog) + "Create a listening TCP socket on interface HOST and port PORT. +BACKLOG queue length for incoming connections.") + +(definterface local-port (socket) + "Return the local port number of SOCKET.") + +(definterface close-socket (socket) + "Close the socket SOCKET.") + +(definterface accept-connection (socket &key external-format + buffering timeout) + "Accept a client connection on the listening socket SOCKET. +Return a stream for the new connection. +If EXTERNAL-FORMAT is nil return a binary stream +otherwise create a character stream. +BUFFERING can be one of: + nil ... no buffering + t ... enable buffering + :line ... enable buffering with automatic flushing on eol.") + +(definterface add-sigio-handler (socket fn) + "Call FN whenever SOCKET is readable.") + +(definterface remove-sigio-handlers (socket) + "Remove all sigio handlers for SOCKET.") + +(definterface add-fd-handler (socket fn) + "Call FN when Lisp is waiting for input and SOCKET is readable.") + +(definterface remove-fd-handlers (socket) + "Remove all fd-handlers for SOCKET.") + +(definterface preferred-communication-style () + "Return one of the symbols :spawn, :sigio, :fd-handler, or NIL." + nil) + +(definterface set-stream-timeout (stream timeout) + "Set the 'stream 'timeout. The timeout is either the real number + specifying the timeout in seconds or 'nil for no timeout." + (declare (ignore stream timeout)) + nil) + +;;; Base condition for networking errors. +(define-condition network-error (simple-error) ()) + +(definterface emacs-connected () + "Hook called when the first connection from Emacs is established. +Called from the INIT-FN of the socket server that accepts the +connection. + +This is intended for setting up extra context, e.g. to discover +that the calling thread is the one that interacts with Emacs." + nil) + + +;;;; Unix signals + +(defconstant +sigint+ 2) + +(definterface getpid () + "Return the (Unix) process ID of this superior Lisp.") + +(definterface install-sigint-handler (function) + "Call FUNCTION on SIGINT (instead of invoking the debugger). +Return old signal handler." + (declare (ignore function)) + nil) + +(definterface call-with-user-break-handler (handler function) + "Install the break handler HANDLER while executing FUNCTION." + (let ((old-handler (install-sigint-handler handler))) + (unwind-protect (funcall function) + (install-sigint-handler old-handler)))) + +(definterface quit-lisp () + "Exit the current lisp image.") + +(definterface lisp-implementation-type-name () + "Return a short name for the Lisp implementation." + (lisp-implementation-type)) + +(definterface lisp-implementation-program () + "Return the argv[0] of the running Lisp process, or NIL." + (let ((file (car (command-line-args)))) + (when (and file (probe-file file)) + (namestring (truename file))))) + +(definterface socket-fd (socket-stream) + "Return the file descriptor for SOCKET-STREAM.") + +(definterface make-fd-stream (fd external-format) + "Create a character stream for the file descriptor FD.") + +(definterface dup (fd) + "Duplicate a file descriptor. +If the syscall fails, signal a condition. +See dup(2).") + +(definterface exec-image (image-file args) + "Replace the current process with a new process image. +The new image is created by loading the previously dumped +core file IMAGE-FILE. +ARGS is a list of strings passed as arguments to +the new image. +This is thin wrapper around exec(3).") + +(definterface command-line-args () + "Return a list of strings as passed by the OS." + nil) + + +;; pathnames are sooo useless + +(definterface filename-to-pathname (filename) + "Return a pathname for FILENAME. +A filename in Emacs may for example contain asterisks which should not +be translated to wildcards." + (parse-namestring filename)) + +(definterface pathname-to-filename (pathname) + "Return the filename for PATHNAME." + (namestring pathname)) + +(definterface default-directory () + "Return the default directory." + (directory-namestring (truename *default-pathname-defaults*))) + +(definterface set-default-directory (directory) + "Set the default directory. +This is used to resolve filenames without directory component." + (setf *default-pathname-defaults* (truename (merge-pathnames directory))) + (default-directory)) + + +(definterface call-with-syntax-hooks (fn) + "Call FN with hooks to handle special syntax." + (funcall fn)) + +(definterface default-readtable-alist () + "Return a suitable initial value for SWANK:*READTABLE-ALIST*." + '()) + + +;;;; Packages + +(definterface package-local-nicknames (package) + "Returns an alist of (local-nickname . actual-package) describing the +nicknames local to the designated package." + (declare (ignore package)) + nil) + +(definterface find-locally-nicknamed-package (name base-package) + "Return the package whose local nickname in BASE-PACKAGE matches NAME. +Return NIL if local nicknames are not implemented or if there is no +such package." + (cdr (assoc name (package-local-nicknames base-package) :test #'string-equal))) + + +;;;; Compilation + +(definterface call-with-compilation-hooks (func) + "Call FUNC with hooks to record compiler conditions.") + +(defmacro with-compilation-hooks ((&rest ignore) &body body) + "Execute BODY as in CALL-WITH-COMPILATION-HOOKS." + (declare (ignore ignore)) + `(call-with-compilation-hooks (lambda () (progn ,@body)))) + +(definterface swank-compile-string (string &key buffer position filename + policy) + "Compile source from STRING. +During compilation, compiler conditions must be trapped and +resignalled as COMPILER-CONDITIONs. + +If supplied, BUFFER and POSITION specify the source location in Emacs. + +Additionally, if POSITION is supplied, it must be added to source +positions reported in compiler conditions. + +If FILENAME is specified it may be used by certain implementations to +rebind *DEFAULT-PATHNAME-DEFAULTS* which may improve the recording of +source information. + +If POLICY is supplied, and non-NIL, it may be used by certain +implementations to compile with optimization qualities of its +value. + +Should return T on successful compilation, NIL otherwise. +") + +(definterface swank-compile-file (input-file output-file load-p + external-format + &key policy) + "Compile INPUT-FILE signalling COMPILE-CONDITIONs. +If LOAD-P is true, load the file after compilation. +EXTERNAL-FORMAT is a value returned by find-external-format or +:default. + +If POLICY is supplied, and non-NIL, it may be used by certain +implementations to compile with optimization qualities of its +value. + +Should return OUTPUT-TRUENAME, WARNINGS-P and FAILURE-p +like `compile-file'") + +(deftype severity () + '(member :error :read-error :warning :style-warning :note :redefinition)) + +;; Base condition type for compiler errors, warnings and notes. +(define-condition compiler-condition (condition) + ((original-condition + ;; The original condition thrown by the compiler if appropriate. + ;; May be NIL if a compiler does not report using conditions. + :type (or null condition) + :initarg :original-condition + :accessor original-condition) + + (severity :type severity + :initarg :severity + :accessor severity) + + (message :initarg :message + :accessor message) + + ;; Macro expansion history etc. which may be helpful in some cases + ;; but is often very verbose. + (source-context :initarg :source-context + :type (or null string) + :initform nil + :accessor source-context) + + (references :initarg :references + :initform nil + :accessor references) + + (location :initarg :location + :accessor location))) + +(definterface find-external-format (coding-system) + "Return a \"external file format designator\" for CODING-SYSTEM. +CODING-SYSTEM is Emacs-style coding system name (a string), +e.g. \"latin-1-unix\"." + (if (equal coding-system "iso-latin-1-unix") + :default + nil)) + +(definterface guess-external-format (pathname) + "Detect the external format for the file with name pathname. +Return nil if the file contains no special markers." + ;; Look for a Emacs-style -*- coding: ... -*- or Local Variable: section. + (with-open-file (s pathname :if-does-not-exist nil + :external-format (or (find-external-format "latin-1-unix") + :default)) + (if s + (or (let* ((line (read-line s nil)) + (p (search "-*-" line))) + (when p + (let* ((start (+ p (length "-*-"))) + (end (search "-*-" line :start2 start))) + (when end + (%search-coding line start end))))) + (let* ((len (file-length s)) + (buf (make-string (min len 3000)))) + (file-position s (- len (length buf))) + (read-sequence buf s) + (let ((start (search "Local Variables:" buf :from-end t)) + (end (search "End:" buf :from-end t))) + (and start end (< start end) + (%search-coding buf start end)))))))) + +(defun %search-coding (str start end) + (let ((p (search "coding:" str :start2 start :end2 end))) + (when p + (incf p (length "coding:")) + (loop while (and (< p end) + (member (aref str p) '(#\space #\tab))) + do (incf p)) + (let ((end (position-if (lambda (c) (find c '(#\space #\tab #\newline #\;))) + str :start p))) + (find-external-format (subseq str p end)))))) + + +;;;; Streams + +(definterface make-output-stream (write-string) + "Return a new character output stream. +The stream calls WRITE-STRING when output is ready.") + +(definterface make-input-stream (read-string) + "Return a new character input stream. +The stream calls READ-STRING when input is needed.") + +(defvar *auto-flush-interval* 0.2) + +(defun auto-flush-loop (stream interval &optional receive) + (loop + (when (not (and (open-stream-p stream) + (output-stream-p stream))) + (return nil)) + (force-output stream) + (when receive + (receive-if #'identity)) + (sleep interval))) + +(definterface make-auto-flush-thread (stream) + "Make an auto-flush thread" + (spawn (lambda () (auto-flush-loop stream *auto-flush-interval* nil)) + :name "auto-flush-thread")) + + +;;;; Documentation + +(definterface arglist (name) + "Return the lambda list for the symbol NAME. NAME can also be +a lisp function object, on lisps which support this. + +The result can be a list or the :not-available keyword if the +arglist cannot be determined." + (declare (ignore name)) + :not-available) + +(defgeneric declaration-arglist (decl-identifier) + (:documentation + "Return the argument list of the declaration specifier belonging to the +declaration identifier DECL-IDENTIFIER. If the arglist cannot be determined, +the keyword :NOT-AVAILABLE is returned. + +The different SWANK backends can specialize this generic function to +include implementation-dependend declaration specifiers, or to provide +additional information on the specifiers defined in ANSI Common Lisp.") + (:method (decl-identifier) + (case decl-identifier + (dynamic-extent '(&rest variables)) + (ignore '(&rest variables)) + (ignorable '(&rest variables)) + (special '(&rest variables)) + (inline '(&rest function-names)) + (notinline '(&rest function-names)) + (declaration '(&rest names)) + (optimize '(&any compilation-speed debug safety space speed)) + (type '(type-specifier &rest args)) + (ftype '(type-specifier &rest function-names)) + (otherwise + (flet ((typespec-p (symbol) + (member :type (describe-symbol-for-emacs symbol)))) + (cond ((and (symbolp decl-identifier) (typespec-p decl-identifier)) + '(&rest variables)) + ((and (listp decl-identifier) + (typespec-p (first decl-identifier))) + '(&rest variables)) + (t :not-available))))))) + +(defgeneric type-specifier-arglist (typespec-operator) + (:documentation + "Return the argument list of the type specifier belonging to +TYPESPEC-OPERATOR.. If the arglist cannot be determined, the keyword +:NOT-AVAILABLE is returned. + +The different SWANK backends can specialize this generic function to +include implementation-dependend declaration specifiers, or to provide +additional information on the specifiers defined in ANSI Common Lisp.") + (:method (typespec-operator) + (declare (special *type-specifier-arglists*)) ; defined at end of file. + (typecase typespec-operator + (symbol (or (cdr (assoc typespec-operator *type-specifier-arglists*)) + :not-available)) + (t :not-available)))) + +(definterface type-specifier-p (symbol) + "Determine if SYMBOL is a type-specifier." + (or (documentation symbol 'type) + (not (eq (type-specifier-arglist symbol) :not-available)))) + +(definterface function-name (function) + "Return the name of the function object FUNCTION. + +The result is either a symbol, a list, or NIL if no function name is +available." + (declare (ignore function)) + nil) + +(definterface valid-function-name-p (form) + "Is FORM syntactically valid to name a function? + If true, FBOUNDP should not signal a type-error for FORM." + (flet ((length=2 (list) + (and (not (null (cdr list))) (null (cddr list))))) + (or (symbolp form) + (and (consp form) (length=2 form) + (eq (first form) 'setf) (symbolp (second form)))))) + +(definterface macroexpand-all (form &optional env) + "Recursively expand all macros in FORM. +Return the resulting form.") + +(definterface compiler-macroexpand-1 (form &optional env) + "Call the compiler-macro for form. +If FORM is a function call for which a compiler-macro has been +defined, invoke the expander function using *macroexpand-hook* and +return the results and T. Otherwise, return the original form and +NIL." + (let ((fun (and (consp form) + (valid-function-name-p (car form)) + (compiler-macro-function (car form) env)))) + (if fun + (let ((result (funcall *macroexpand-hook* fun form env))) + (values result (not (eq result form)))) + (values form nil)))) + +(definterface compiler-macroexpand (form &optional env) + "Repetitively call `compiler-macroexpand-1'." + (labels ((frob (form expanded) + (multiple-value-bind (new-form newly-expanded) + (compiler-macroexpand-1 form env) + (if newly-expanded + (frob new-form t) + (values new-form expanded))))) + (frob form env))) + +(defmacro with-collected-macro-forms + ((forms &optional result) instrumented-form &body body) + "Collect macro forms by locally binding *MACROEXPAND-HOOK*. + +Evaluates INSTRUMENTED-FORM and collects any forms which undergo +macro-expansion into a list. Then evaluates BODY with FORMS bound to +the list of forms, and RESULT (optionally) bound to the value of +INSTRUMENTED-FORM." + (assert (and (symbolp forms) (not (null forms)))) + (assert (symbolp result)) + (let ((result-symbol (or result (gensym)))) + `(call-with-collected-macro-forms + (lambda (,forms ,result-symbol) + (declare (ignore ,@(and (not result) + `(,result-symbol)))) + ,@body) + (lambda () ,instrumented-form)))) + +(defun call-with-collected-macro-forms (body-fn instrumented-fn) + (let ((return-value nil) + (collected-forms '())) + (let* ((real-macroexpand-hook *macroexpand-hook*) + (*macroexpand-hook* + (lambda (macro-function form environment) + (let ((result (funcall real-macroexpand-hook + macro-function form environment))) + (unless (eq result form) + (push form collected-forms)) + result)))) + (setf return-value (funcall instrumented-fn))) + (funcall body-fn collected-forms return-value))) + +(definterface collect-macro-forms (form &optional env) + "Collect subforms of FORM which undergo (compiler-)macro expansion. +Returns two values: a list of macro forms and a list of compiler macro +forms." + (with-collected-macro-forms (macro-forms expansion) + (ignore-errors (macroexpand-all form env)) + (with-collected-macro-forms (compiler-macro-forms) + (handler-bind ((warning #'muffle-warning)) + (ignore-errors + (compile nil `(lambda () ,expansion)))) + (values macro-forms compiler-macro-forms)))) + +(definterface format-string-expand (control-string) + "Expand the format string CONTROL-STRING." + (macroexpand `(formatter ,control-string))) + +(definterface describe-symbol-for-emacs (symbol) + "Return a property list describing SYMBOL. + +The property list has an entry for each interesting aspect of the +symbol. The recognised keys are: + + :VARIABLE :FUNCTION :SETF :SPECIAL-OPERATOR :MACRO :COMPILER-MACRO + :TYPE :CLASS :ALIEN-TYPE :ALIEN-STRUCT :ALIEN-UNION :ALIEN-ENUM + +The value of each property is the corresponding documentation string, +or NIL (or the obsolete :NOT-DOCUMENTED). It is legal to include keys +not listed here (but slime-print-apropos in Emacs must know about +them). + +Properties should be included if and only if they are applicable to +the symbol. For example, only (and all) fbound symbols should include +the :FUNCTION property. + +Example: +\(describe-symbol-for-emacs 'vector) + => (:CLASS :NOT-DOCUMENTED + :TYPE :NOT-DOCUMENTED + :FUNCTION \"Constructs a simple-vector from the given objects.\")") + +(definterface describe-definition (name type) + "Describe the definition NAME of TYPE. +TYPE can be any value returned by DESCRIBE-SYMBOL-FOR-EMACS. + +Return a documentation string, or NIL if none is available.") + + +;;;; Debugging + +(definterface install-debugger-globally (function) + "Install FUNCTION as the debugger for all threads/processes. This +usually involves setting *DEBUGGER-HOOK* and, if the implementation +permits, hooking into BREAK as well." + (setq *debugger-hook* function)) + +(definterface call-with-debugging-environment (debugger-loop-fn) + "Call DEBUGGER-LOOP-FN in a suitable debugging environment. + +This function is called recursively at each debug level to invoke the +debugger loop. The purpose is to setup any necessary environment for +other debugger callbacks that will be called within the debugger loop. + +For example, this is a reasonable place to compute a backtrace, switch +to safe reader/printer settings, and so on.") + +(definterface call-with-debugger-hook (hook fun) + "Call FUN and use HOOK as debugger hook. HOOK can be NIL. + +HOOK should be called for both BREAK and INVOKE-DEBUGGER." + (let ((*debugger-hook* hook)) + (funcall fun))) + +(define-condition sldb-condition (condition) + ((original-condition + :initarg :original-condition + :accessor original-condition)) + (:report (lambda (condition stream) + (format stream "Condition in debugger code~@[: ~A~]" + (original-condition condition)))) + (:documentation + "Wrapper for conditions that should not be debugged. + +When a condition arises from the internals of the debugger, it is not +desirable to debug it -- we'd risk entering an endless loop trying to +debug the debugger! Instead, such conditions can be reported to the +user without (re)entering the debugger by wrapping them as +`sldb-condition's.")) + +;;; The following functions in this section are supposed to be called +;;; within the dynamic contour of CALL-WITH-DEBUGGING-ENVIRONMENT only. + +(definterface compute-backtrace (start end) + "Returns a backtrace of the condition currently being debugged, +that is an ordered list consisting of frames. ``Ordered list'' +means that an integer I can be mapped back to the i-th frame of this +backtrace. + +START and END are zero-based indices constraining the number of frames +returned. Frame zero is defined as the frame which invoked the +debugger. If END is nil, return the frames from START to the end of +the stack.") + +(definterface print-frame (frame stream) + "Print frame to stream.") + +(definterface frame-restartable-p (frame) + "Is the frame FRAME restartable?. +Return T if `restart-frame' can safely be called on the frame." + (declare (ignore frame)) + nil) + +(definterface frame-source-location (frame-number) + "Return the source location for the frame associated to FRAME-NUMBER.") + +(definterface frame-catch-tags (frame-number) + "Return a list of catch tags for being printed in a debugger stack +frame." + (declare (ignore frame-number)) + '()) + +(definterface frame-locals (frame-number) + "Return a list of ((&key NAME ID VALUE) ...) where each element of +the list represents a local variable in the stack frame associated to +FRAME-NUMBER. + +NAME, a symbol; the name of the local variable. + +ID, an integer; used as primary key for the local variable, unique +relatively to the frame under operation. + +value, an object; the value of the local variable.") + +(definterface frame-var-value (frame-number var-id) + "Return the value of the local variable associated to VAR-ID +relatively to the frame associated to FRAME-NUMBER.") + +(definterface disassemble-frame (frame-number) + "Disassemble the code for the FRAME-NUMBER. +The output should be written to standard output. +FRAME-NUMBER is a non-negative integer.") + +(definterface eval-in-frame (form frame-number) + "Evaluate a Lisp form in the lexical context of a stack frame +in the debugger. + +FRAME-NUMBER must be a positive integer with 0 indicating the +frame which invoked the debugger. + +The return value is the result of evaulating FORM in the +appropriate context.") + +(definterface frame-package (frame-number) + "Return the package corresponding to the frame at FRAME-NUMBER. +Return nil if the backend can't figure it out." + (declare (ignore frame-number)) + nil) + +(definterface frame-call (frame-number) + "Return a string representing a call to the entry point of a frame.") + +(definterface return-from-frame (frame-number form) + "Unwind the stack to the frame FRAME-NUMBER and return the value(s) +produced by evaluating FORM in the frame context to its caller. + +Execute any clean-up code from unwind-protect forms above the frame +during unwinding. + +Return a string describing the error if it's not possible to return +from the frame.") + +(definterface restart-frame (frame-number) + "Restart execution of the frame FRAME-NUMBER with the same arguments +as it was called originally.") + +(definterface print-condition (condition stream) + "Print a condition for display in SLDB." + (princ condition stream)) + +(definterface condition-extras (condition) + "Return a list of extra for the debugger. +The allowed elements are of the form: + (:SHOW-FRAME-SOURCE frame-number) + (:REFERENCES &rest refs) +" + (declare (ignore condition)) + '()) + +(definterface gdb-initial-commands () + "List of gdb commands supposed to be executed first for the + ATTACH-GDB restart." + nil) + +(definterface activate-stepping (frame-number) + "Prepare the frame FRAME-NUMBER for stepping.") + +(definterface sldb-break-on-return (frame-number) + "Set a breakpoint in the frame FRAME-NUMBER.") + +(definterface sldb-break-at-start (symbol) + "Set a breakpoint on the beginning of the function for SYMBOL.") + +(definterface sldb-stepper-condition-p (condition) + "Return true if SLDB was invoked due to a single-stepping condition, +false otherwise. " + (declare (ignore condition)) + nil) + +(definterface sldb-step-into () + "Step into the current single-stepper form.") + +(definterface sldb-step-next () + "Step to the next form in the current function.") + +(definterface sldb-step-out () + "Stop single-stepping temporarily, but resume it once the current function +returns.") + + +;;;; Definition finding + +(defstruct (location (:type list) + (:constructor make-location + (buffer position &optional hints))) + (type :location) + buffer position + ;; Hints is a property list optionally containing: + ;; :snippet SOURCE-TEXT + ;; This is a snippet of the actual source text at the start of + ;; the definition, which could be used in a text search. + hints) + +(defmacro converting-errors-to-error-location (&body body) + "Catches errors during BODY and converts them to an error location." + (let ((gblock (gensym "CONVERTING-ERRORS+"))) + `(block ,gblock + (handler-bind ((error + #'(lambda (e) + (if *debug-swank-backend* + nil ;decline + (return-from ,gblock + (make-error-location e)))))) + ,@body)))) + +(defun make-error-location (datum &rest args) + (cond ((typep datum 'condition) + `(:error ,(format nil "Error: ~A" datum))) + ((symbolp datum) + `(:error ,(format nil "Error: ~A" + (apply #'make-condition datum args)))) + (t + (assert (stringp datum)) + `(:error ,(apply #'format nil datum args))))) + +(definterface find-definitions (name) + "Return a list ((DSPEC LOCATION) ...) for NAME's definitions. + +NAME is a \"definition specifier\". + +DSPEC is a \"definition specifier\" describing the +definition, e.g., FOO or (METHOD FOO (STRING NUMBER)) or +\(DEFVAR FOO). + +LOCATION is the source location for the definition.") + +(definterface find-source-location (object) + "Returns the source location of OBJECT, or NIL. + +That is the source location of the underlying datastructure of +OBJECT. E.g. on a STANDARD-OBJECT, the source location of the +respective DEFCLASS definition is returned, on a STRUCTURE-CLASS the +respective DEFSTRUCT definition, and so on." + ;; This returns one source location and not a list of locations. It's + ;; supposed to return the location of the DEFGENERIC definition on + ;; #'SOME-GENERIC-FUNCTION. + (declare (ignore object)) + (make-error-location "FIND-SOURCE-LOCATION is not yet implemented on ~ + this implementation.")) + +(definterface buffer-first-change (filename) + "Called for effect the first time FILENAME's buffer is modified. +CMUCL/SBCL use this to cache the unmodified file and use the +unmodified text to improve the precision of source locations." + (declare (ignore filename)) + nil) + + + +;;;; XREF + +(definterface who-calls (function-name) + "Return the call sites of FUNCTION-NAME (a symbol). +The results is a list ((DSPEC LOCATION) ...)." + (declare (ignore function-name)) + :not-implemented) + +(definterface calls-who (function-name) + "Return the call sites of FUNCTION-NAME (a symbol). +The results is a list ((DSPEC LOCATION) ...)." + (declare (ignore function-name)) + :not-implemented) + +(definterface who-references (variable-name) + "Return the locations where VARIABLE-NAME (a symbol) is referenced. +See WHO-CALLS for a description of the return value." + (declare (ignore variable-name)) + :not-implemented) + +(definterface who-binds (variable-name) + "Return the locations where VARIABLE-NAME (a symbol) is bound. +See WHO-CALLS for a description of the return value." + (declare (ignore variable-name)) + :not-implemented) + +(definterface who-sets (variable-name) + "Return the locations where VARIABLE-NAME (a symbol) is set. +See WHO-CALLS for a description of the return value." + (declare (ignore variable-name)) + :not-implemented) + +(definterface who-macroexpands (macro-name) + "Return the locations where MACRO-NAME (a symbol) is expanded. +See WHO-CALLS for a description of the return value." + (declare (ignore macro-name)) + :not-implemented) + +(definterface who-specializes (class-name) + "Return the locations where CLASS-NAME (a symbol) is specialized. +See WHO-CALLS for a description of the return value." + (declare (ignore class-name)) + :not-implemented) + +;;; Simpler variants. + +(definterface list-callers (function-name) + "List the callers of FUNCTION-NAME. +This function is like WHO-CALLS except that it is expected to use +lower-level means. Whereas WHO-CALLS is usually implemented with +special compiler support, LIST-CALLERS is usually implemented by +groveling for constants in function objects throughout the heap. + +The return value is as for WHO-CALLS.") + +(definterface list-callees (function-name) + "List the functions called by FUNCTION-NAME. +See LIST-CALLERS for a description of the return value.") + + +;;;; Profiling + +;;; The following functions define a minimal profiling interface. + +(definterface profile (fname) + "Marks symbol FNAME for profiling.") + +(definterface profiled-functions () + "Returns a list of profiled functions.") + +(definterface unprofile (fname) + "Marks symbol FNAME as not profiled.") + +(definterface unprofile-all () + "Marks all currently profiled functions as not profiled." + (dolist (f (profiled-functions)) + (unprofile f))) + +(definterface profile-report () + "Prints profile report.") + +(definterface profile-reset () + "Resets profile counters.") + +(definterface profile-package (package callers-p methods) + "Wrap profiling code around all functions in PACKAGE. If a function +is already profiled, then unprofile and reprofile (useful to notice +function redefinition.) + +If CALLERS-P is T names have counts of the most common calling +functions recorded. + +When called with arguments :METHODS T, profile all methods of all +generic functions having names in the given package. Generic functions +themselves, that is, their dispatch functions, are left alone.") + + +;;;; Trace + +(definterface toggle-trace (spec) + "Toggle tracing of the function(s) given with SPEC. +SPEC can be: + (setf NAME) ; a setf function + (:defmethod NAME QUALIFIER... (SPECIALIZER...)) ; a specific method + (:defgeneric NAME) ; a generic function with all methods + (:call CALLER CALLEE) ; trace calls from CALLER to CALLEE. + (:labels TOPLEVEL LOCAL) + (:flet TOPLEVEL LOCAL) ") + + +;;;; Inspector + +(defgeneric emacs-inspect (object) + (:documentation + "Explain to Emacs how to inspect OBJECT. + +Returns a list specifying how to render the object for inspection. + +Every element of the list must be either a string, which will be +inserted into the buffer as is, or a list of the form: + + (:value object &optional format) - Render an inspectable + object. If format is provided it must be a string and will be + rendered in place of the value, otherwise use princ-to-string. + + (:newline) - Render a \\n + + (:action label lambda &key (refresh t)) - Render LABEL (a text + string) which when clicked will call LAMBDA. If REFRESH is + non-NIL the currently inspected object will be re-inspected + after calling the lambda. +")) + +(defmethod emacs-inspect ((object t)) + "Generic method for inspecting any kind of object. + +Since we don't know how to deal with OBJECT we simply dump the +output of CL:DESCRIBE." + `("Type: " (:value ,(type-of object)) (:newline) + "Don't know how to inspect the object, dumping output of CL:DESCRIBE:" + (:newline) (:newline) + ,(with-output-to-string (desc) (describe object desc)))) + +(definterface eval-context (object) + "Return a list of bindings corresponding to OBJECT's slots." + (declare (ignore object)) + '()) + +;;; Utilities for inspector methods. +;;; + +(defun label-value-line (label value &key (newline t)) + "Create a control list which prints \"LABEL: VALUE\" in the inspector. +If NEWLINE is non-NIL a `(:newline)' is added to the result." + (list* (princ-to-string label) ": " `(:value ,value) + (if newline '((:newline)) nil))) + +(defmacro label-value-line* (&rest label-values) + ` (append ,@(loop for (label value) in label-values + collect `(label-value-line ,label ,value)))) + +(definterface describe-primitive-type (object) + "Return a string describing the primitive type of object." + (declare (ignore object)) + "N/A") + + +;;;; Multithreading +;;; +;;; The default implementations are sufficient for non-multiprocessing +;;; implementations. + +(definterface initialize-multiprocessing (continuation) + "Initialize multiprocessing, if necessary and then invoke CONTINUATION. + +Depending on the impleimentaion, this function may never return." + (funcall continuation)) + +(definterface spawn (fn &key name) + "Create a new thread to call FN.") + +(definterface thread-id (thread) + "Return an Emacs-parsable object to identify THREAD. + +Ids should be comparable with equal, i.e.: + (equal (thread-id ) (thread-id )) <==> (eq )" + thread) + +(definterface find-thread (id) + "Return the thread for ID. +ID should be an id previously obtained with THREAD-ID. +Can return nil if the thread no longer exists." + (declare (ignore id)) + (current-thread)) + +(definterface thread-name (thread) + "Return the name of THREAD. +Thread names are short strings meaningful to the user. They do not +have to be unique." + (declare (ignore thread)) + "The One True Thread") + +(definterface thread-status (thread) + "Return a string describing THREAD's state." + (declare (ignore thread)) + "") + +(definterface thread-attributes (thread) + "Return a plist of implementation-dependent attributes for THREAD" + (declare (ignore thread)) + '()) + +(definterface current-thread () + "Return the currently executing thread." + 0) + +(definterface all-threads () + "Return a fresh list of all threads." + '()) + +(definterface thread-alive-p (thread) + "Test if THREAD is termintated." + (member thread (all-threads))) + +(definterface interrupt-thread (thread fn) + "Cause THREAD to execute FN.") + +(definterface kill-thread (thread) + "Terminate THREAD immediately. +Don't execute unwind-protected sections, don't raise conditions. +(Do not pass go, do not collect $200.)" + (declare (ignore thread)) + nil) + +(definterface send (thread object) + "Send OBJECT to thread THREAD." + (declare (ignore thread)) + object) + +(definterface receive (&optional timeout) + "Return the next message from current thread's mailbox." + (receive-if (constantly t) timeout)) + +(definterface receive-if (predicate &optional timeout) + "Return the first message satisfiying PREDICATE.") + +(definterface wake-thread (thread) + "Trigger a call to CHECK-SLIME-INTERRUPTS in THREAD without using +asynchronous interrupts." + (declare (ignore thread)) + ;; Doesn't have to implement this if RECEIVE-IF periodically calls + ;; CHECK-SLIME-INTERRUPTS, but that's energy inefficient + nil) + +(definterface register-thread (name thread) + "Associate the thread THREAD with the symbol NAME. +The thread can then be retrieved with `find-registered'. +If THREAD is nil delete the association." + (declare (ignore name thread)) + nil) + +(definterface find-registered (name) + "Find the thread that was registered for the symbol NAME. +Return nil if the no thread was registred or if the tread is dead." + (declare (ignore name)) + nil) + +(definterface set-default-initial-binding (var form) + "Initialize special variable VAR by default with FORM. + +Some implementations initialize certain variables in each newly +created thread. This function sets the form which is used to produce +the initial value." + (set var (eval form))) + +;; List of delayed interrupts. +;; This should only have thread-local bindings, so no init form. +(defvar *pending-slime-interrupts*) + +(defun check-slime-interrupts () + "Execute pending interrupts if any. +This should be called periodically in operations which +can take a long time to complete. +Return a boolean indicating whether any interrupts was processed." + (when (and (boundp '*pending-slime-interrupts*) + *pending-slime-interrupts*) + (funcall (pop *pending-slime-interrupts*)) + t)) + +(defvar *interrupt-queued-handler* nil + "Function to call on queued interrupts. +Interrupts get queued when an interrupt occurs while interrupt +handling is disabled. + +Backends can use this function to abort slow operations.") + +(definterface wait-for-input (streams &optional timeout) + "Wait for input on a list of streams. Return those that are ready. +STREAMS is a list of streams +TIMEOUT nil, t, or real number. If TIMEOUT is t, return those streams +which are ready (or have reached end-of-file) without waiting. +If TIMEOUT is a number and no streams is ready after TIMEOUT seconds, +return nil. + +Return :interrupt if an interrupt occurs while waiting." + (declare (ignore streams timeout)) + ;; Invoking the slime debugger will just endlessly loop. + (call-with-debugger-hook + nil + (lambda () + (error "~s not implemented. Check if ~s = ~s is supported by the implementation." + 'wait-for-input 'swank:*communication-style* swank:*communication-style*)))) + + +;;;; Locks + +;; Please use locks only in swank-gray.lisp. Locks are too low-level +;; for our taste. + +(definterface make-lock (&key name) + "Make a lock for thread synchronization. +Only one thread may hold the lock (via CALL-WITH-LOCK-HELD) at a time +but that thread may hold it more than once." + (declare (ignore name)) + :null-lock) + +(definterface call-with-lock-held (lock function) + "Call FUNCTION with LOCK held, queueing if necessary." + (declare (ignore lock) + (type function function)) + (funcall function)) + + +;;;; Weak datastructures + +(definterface make-weak-key-hash-table (&rest args) + "Like MAKE-HASH-TABLE, but weak w.r.t. the keys." + (apply #'make-hash-table args)) + +(definterface make-weak-value-hash-table (&rest args) + "Like MAKE-HASH-TABLE, but weak w.r.t. the values." + (apply #'make-hash-table args)) + +(definterface hash-table-weakness (hashtable) + "Return nil or one of :key :value :key-or-value :key-and-value" + (declare (ignore hashtable)) + nil) + + +;;;; Floating point + +(definterface float-nan-p (float) + "Return true if FLOAT is a NaN value (Not a Number)." + ;; When the float type implements IEEE-754 floats, two NaN values + ;; are never equal; when the implementation does not support NaN, + ;; the predicate should return false. An implementation can + ;; implement comparison with "unordered-signaling predicates", which + ;; emit floating point exceptions. + (handler-case (not (= float float)) + ;; Comparisons never signal an exception other than the invalid + ;; operation exception (5.11 Details of comparison predicates). + (floating-point-invalid-operation () t))) + +(definterface float-infinity-p (float) + "Return true if FLOAT is positive or negative infinity." + (not (< most-negative-long-float + float + most-positive-long-float))) + + +;;;; Character names + +(definterface character-completion-set (prefix matchp) + "Return a list of names of characters that match PREFIX." + ;; Handle the standard and semi-standard characters. + (loop for name in '("Newline" "Space" "Tab" "Page" "Rubout" + "Linefeed" "Return" "Backspace") + when (funcall matchp prefix name) + collect name)) + + +(defparameter *type-specifier-arglists* + '((and . (&rest type-specifiers)) + (array . (&optional element-type dimension-spec)) + (base-string . (&optional size)) + (bit-vector . (&optional size)) + (complex . (&optional type-specifier)) + (cons . (&optional car-typespec cdr-typespec)) + (double-float . (&optional lower-limit upper-limit)) + (eql . (object)) + (float . (&optional lower-limit upper-limit)) + (function . (&optional arg-typespec value-typespec)) + (integer . (&optional lower-limit upper-limit)) + (long-float . (&optional lower-limit upper-limit)) + (member . (&rest eql-objects)) + (mod . (n)) + (not . (type-specifier)) + (or . (&rest type-specifiers)) + (rational . (&optional lower-limit upper-limit)) + (real . (&optional lower-limit upper-limit)) + (satisfies . (predicate-symbol)) + (short-float . (&optional lower-limit upper-limit)) + (signed-byte . (&optional size)) + (simple-array . (&optional element-type dimension-spec)) + (simple-base-string . (&optional size)) + (simple-bit-vector . (&optional size)) + (simple-string . (&optional size)) + (single-float . (&optional lower-limit upper-limit)) + (simple-vector . (&optional size)) + (string . (&optional size)) + (unsigned-byte . (&optional size)) + (values . (&rest typespecs)) + (vector . (&optional element-type size)) + )) + +;;; Heap dumps + +(definterface save-image (filename &optional restart-function) + "Save a heap image to the file FILENAME. +RESTART-FUNCTION, if non-nil, should be called when the image is loaded.") + +(definterface background-save-image (filename &key restart-function + completion-function) + "Request saving a heap image to the file FILENAME. +RESTART-FUNCTION, if non-nil, should be called when the image is loaded. +COMPLETION-FUNCTION, if non-nil, should be called after saving the image.") + +(defun deinit-log-output () + ;; Can't hang on to an fd-stream from a previous session. + (setf *log-output* nil)) + + +;;;; Wrapping + +(definterface wrap (spec indicator &key before after replace) + "Intercept future calls to SPEC and surround them in callbacks. + +INDICATOR is a symbol identifying a particular wrapping, and is used +to differentiate between multiple wrappings. + +Implementations intercept calls to SPEC and call, in this order: + +* the BEFORE callback, if it's provided, with a single argument set to + the list of arguments passed to the intercepted call; + +* the original definition of SPEC recursively honouring any wrappings + previously established under different values of INDICATOR. If the + compatible function REPLACE is provided, call that instead. + +* the AFTER callback, if it's provided, with a single set to the list + of values returned by the previous call, or, if that call exited + non-locally, a single descriptive symbol, like :EXITED-NON-LOCALLY." + (declare (ignore indicator)) + (assert (symbolp spec) nil + "The default implementation for WRAP allows only simple names") + (assert (null (get spec 'slime-wrap)) nil + "The default implementation for WRAP allows a single wrapping") + (let* ((saved (symbol-function spec)) + (replacement (lambda (&rest args) + (let (retlist completed) + (unwind-protect + (progn + (when before + (funcall before args)) + (setq retlist (multiple-value-list + (apply (or replace + saved) args))) + (setq completed t) + (values-list retlist)) + (when after + (funcall after (if completed + retlist + :exited-non-locally)))))))) + (setf (get spec 'slime-wrap) (list saved replacement)) + (setf (symbol-function spec) replacement)) + spec) + +(definterface unwrap (spec indicator) + "Remove from SPEC any wrappings tagged with INDICATOR." + (if (wrapped-p spec indicator) + (setf (symbol-function spec) (first (get spec 'slime-wrap))) + (cerror "All right, so I did" + "Hmmm, ~a is not correctly wrapped, you probably redefined it" + spec)) + (setf (get spec 'slime-wrap) nil) + spec) + +(definterface wrapped-p (spec indicator) + "Returns true if SPEC is wrapped with INDICATOR." + (declare (ignore indicator)) + (and (symbolp spec) + (let ((prop-value (get spec 'slime-wrap))) + (cond ((and prop-value + (not (eq (second prop-value) + (symbol-function spec)))) + (warn "~a appears to be incorrectly wrapped" spec) + nil) + (prop-value t) + (t nil))))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/ccl.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/ccl.lisp new file mode 100644 index 0000000..61f3f5e --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/ccl.lisp @@ -0,0 +1,868 @@ +;;;; -*- indent-tabs-mode: nil -*- +;;; +;;; swank-ccl.lisp --- SLIME backend for Clozure CL. +;;; +;;; Copyright (C) 2003, James Bielman +;;; +;;; This program is licensed under the terms of the Lisp Lesser GNU +;;; Public License, known as the LLGPL, and distributed with Clozure CL +;;; as the file "LICENSE". The LLGPL consists of a preamble and the +;;; LGPL, which is distributed with Clozure CL as the file "LGPL". Where +;;; these conflict, the preamble takes precedence. +;;; +;;; The LLGPL is also available online at +;;; http://opensource.franz.com/preamble.html + +(defpackage swank/ccl + (:use cl swank/backend)) + +(in-package swank/ccl) + +(eval-when (:compile-toplevel :execute :load-toplevel) + (assert (and (= ccl::*openmcl-major-version* 1) + (>= ccl::*openmcl-minor-version* 4)) + () "This file needs CCL version 1.4 or newer")) + +(defimplementation gray-package-name () + "CCL") + +(eval-when (:compile-toplevel :load-toplevel :execute) + (multiple-value-bind (ok err) (ignore-errors (require 'xref)) + (unless ok + (warn "~a~%" err)))) + +;;; swank-mop + +(import-to-swank-mop + '( ;; classes + cl:standard-generic-function + ccl:standard-slot-definition + cl:method + cl:standard-class + ccl:eql-specializer + openmcl-mop:finalize-inheritance + openmcl-mop:compute-applicable-methods-using-classes + ;; standard-class readers + openmcl-mop:class-default-initargs + openmcl-mop:class-direct-default-initargs + openmcl-mop:class-direct-slots + openmcl-mop:class-direct-subclasses + openmcl-mop:class-direct-superclasses + openmcl-mop:class-finalized-p + cl:class-name + openmcl-mop:class-precedence-list + openmcl-mop:class-prototype + openmcl-mop:class-slots + openmcl-mop:specializer-direct-methods + ;; eql-specializer accessors + openmcl-mop:eql-specializer-object + ;; generic function readers + openmcl-mop:generic-function-argument-precedence-order + openmcl-mop:generic-function-declarations + openmcl-mop:generic-function-lambda-list + openmcl-mop:generic-function-methods + openmcl-mop:generic-function-method-class + openmcl-mop:generic-function-method-combination + openmcl-mop:generic-function-name + ;; method readers + openmcl-mop:method-generic-function + openmcl-mop:method-function + openmcl-mop:method-lambda-list + openmcl-mop:method-specializers + openmcl-mop:method-qualifiers + ;; slot readers + openmcl-mop:slot-definition-allocation + openmcl-mop:slot-definition-documentation + openmcl-mop:slot-value-using-class + openmcl-mop:slot-definition-initargs + openmcl-mop:slot-definition-initform + openmcl-mop:slot-definition-initfunction + openmcl-mop:slot-definition-name + openmcl-mop:slot-definition-type + openmcl-mop:slot-definition-readers + openmcl-mop:slot-definition-writers + openmcl-mop:slot-boundp-using-class + openmcl-mop:slot-makunbound-using-class)) + +;;; UTF8 + +(defimplementation string-to-utf8 (string) + (ccl:encode-string-to-octets string :external-format :utf-8)) + +(defimplementation utf8-to-string (octets) + (ccl:decode-string-from-octets octets :external-format :utf-8)) + +;;; TCP Server + +(defimplementation preferred-communication-style () + :spawn) + +(defimplementation create-socket (host port &key backlog) + (ccl:make-socket :connect :passive :local-port port + :local-host host :reuse-address t + :backlog (or backlog 5))) + +(defimplementation local-port (socket) + (ccl:local-port socket)) + +(defimplementation close-socket (socket) + (close socket)) + +(defimplementation accept-connection (socket &key external-format + buffering timeout) + (declare (ignore buffering timeout)) + (let ((stream-args (and external-format + `(:external-format ,external-format)))) + (ccl:accept-connection socket :wait t :stream-args stream-args))) + +(defvar *external-format-to-coding-system* + '((:iso-8859-1 + "latin-1" "latin-1-unix" "iso-latin-1-unix" + "iso-8859-1" "iso-8859-1-unix") + (:utf-8 "utf-8" "utf-8-unix"))) + +(defimplementation find-external-format (coding-system) + (car (rassoc-if (lambda (x) (member coding-system x :test #'equal)) + *external-format-to-coding-system*))) + +(defimplementation socket-fd (stream) + (ccl::ioblock-device (ccl::stream-ioblock stream t))) + +;;; Unix signals + +(defimplementation getpid () + (ccl::getpid)) + +(defimplementation lisp-implementation-type-name () + "ccl") + +;;; Arglist + +(defimplementation arglist (fname) + (multiple-value-bind (arglist binding) (let ((*break-on-signals* nil)) + (ccl:arglist fname)) + (if binding + arglist + :not-available))) + +(defimplementation function-name (function) + (ccl:function-name function)) + +(defmethod declaration-arglist ((decl-identifier (eql 'optimize))) + (let ((flags (ccl:declaration-information decl-identifier))) + (if flags + `(&any ,flags) + (call-next-method)))) + +;;; Compilation + +(defun handle-compiler-warning (condition) + "Resignal a ccl:compiler-warning as swank/backend:compiler-warning." + (signal 'compiler-condition + :original-condition condition + :message (compiler-warning-short-message condition) + :source-context nil + :severity (compiler-warning-severity condition) + :location (source-note-to-source-location + (ccl:compiler-warning-source-note condition) + (lambda () "Unknown source") + (ccl:compiler-warning-function-name condition)))) + +(defgeneric compiler-warning-severity (condition)) +(defmethod compiler-warning-severity ((c ccl:compiler-warning)) :warning) +(defmethod compiler-warning-severity ((c ccl:style-warning)) :style-warning) + +(defgeneric compiler-warning-short-message (condition)) + +;; Pretty much the same as ccl:report-compiler-warning but +;; without the source position and function name stuff. +(defmethod compiler-warning-short-message ((c ccl:compiler-warning)) + (with-output-to-string (stream) + (ccl:report-compiler-warning c stream :short t))) + +;; Needed because `ccl:report-compiler-warning' would return +;; "Nonspecific warning". +(defmethod compiler-warning-short-message ((c ccl::shadowed-typecase-clause)) + (princ-to-string c)) + +(defimplementation call-with-compilation-hooks (function) + (handler-bind ((ccl:compiler-warning 'handle-compiler-warning)) + (let ((ccl:*merge-compiler-warnings* nil)) + (funcall function)))) + +(defimplementation swank-compile-file (input-file output-file + load-p external-format + &key policy) + (declare (ignore policy)) + (with-compilation-hooks () + (compile-file input-file + :output-file output-file + :load load-p + :external-format external-format))) + +;; Use a temp file rather than in-core compilation in order to handle +;; eval-when's as compile-time. +(defimplementation swank-compile-string (string &key buffer position filename + policy) + (declare (ignore policy)) + (with-compilation-hooks () + (let ((temp-file-name (ccl:temp-pathname)) + (ccl:*save-source-locations* t)) + (unwind-protect + (progn + (with-open-file (s temp-file-name :direction :output + :if-exists :error :external-format :utf-8) + (write-string string s)) + (let ((binary-filename (compile-temp-file + temp-file-name filename buffer position))) + (delete-file binary-filename))) + (delete-file temp-file-name))))) + +(defvar *temp-file-map* (make-hash-table :test #'equal) + "A mapping from tempfile names to Emacs buffer names.") + +(defun compile-temp-file (temp-file-name buffer-file-name buffer-name offset) + (compile-file temp-file-name + :load t + :compile-file-original-truename + (or buffer-file-name + (progn + (setf (gethash temp-file-name *temp-file-map*) + buffer-name) + temp-file-name)) + :compile-file-original-buffer-offset (1- offset) + :external-format :utf-8)) + +(defimplementation save-image (filename &optional restart-function) + (ccl:save-application filename :toplevel-function restart-function)) + +;;; Cross-referencing + +(defun xref-locations (relation name &optional inverse) + (delete-duplicates + (mapcan #'find-definitions + (if inverse + (ccl::get-relation relation name :wild :exhaustive t) + (ccl::get-relation relation :wild name :exhaustive t))) + :test 'equal)) + +(defimplementation who-binds (name) + (xref-locations :binds name)) + +(defimplementation who-macroexpands (name) + (xref-locations :macro-calls name t)) + +(defimplementation who-references (name) + (remove-duplicates + (append (xref-locations :references name) + (xref-locations :sets name) + (xref-locations :binds name)) + :test 'equal)) + +(defimplementation who-sets (name) + (xref-locations :sets name)) + +(defimplementation who-calls (name) + (remove-duplicates + (append + (xref-locations :direct-calls name) + (xref-locations :indirect-calls name) + (xref-locations :macro-calls name t)) + :test 'equal)) + +(defimplementation who-specializes (class) + (when (symbolp class) + (setq class (find-class class nil))) + (when class + (delete-duplicates + (mapcar (lambda (m) + (car (find-definitions m))) + (ccl:specializer-direct-methods class)) + :test 'equal))) + +(defimplementation list-callees (name) + (remove-duplicates + (append + (xref-locations :direct-calls name t) + (xref-locations :macro-calls name nil)) + :test 'equal)) + +(defimplementation list-callers (symbol) + (delete-duplicates + (mapcan #'find-definitions (ccl:caller-functions symbol)) + :test #'equal)) + +;;; Profiling (alanr: lifted from swank-clisp) + +(defimplementation profile (fname) + (eval `(swank-monitor:monitor ,fname))) ;monitor is a macro + +(defimplementation profiled-functions () + swank-monitor:*monitored-functions*) + +(defimplementation unprofile (fname) + (eval `(swank-monitor:unmonitor ,fname))) ;unmonitor is a macro + +(defimplementation unprofile-all () + (swank-monitor:unmonitor)) + +(defimplementation profile-report () + (swank-monitor:report-monitoring)) + +(defimplementation profile-reset () + (swank-monitor:reset-all-monitoring)) + +(defimplementation profile-package (package callers-p methods) + (declare (ignore callers-p methods)) + (swank-monitor:monitor-all package)) + +;;; Debugging + +(defimplementation call-with-debugging-environment (debugger-loop-fn) + (let* (;;(*debugger-hook* nil) + ;; don't let error while printing error take us down + (ccl:*signal-printing-errors* nil)) + (funcall debugger-loop-fn))) + +;; This is called for an async interrupt and is running in a random +;; thread not selected by the user, so don't use thread-local vars +;; such as *emacs-connection*. +(defun find-repl-thread () + (let* ((*break-on-signals* nil) + (conn (swank::default-connection))) + (and (swank::multithreaded-connection-p conn) + (swank::mconn.repl-thread conn)))) + +(defimplementation call-with-debugger-hook (hook fun) + (let ((*debugger-hook* hook) + (ccl:*break-hook* hook) + (ccl:*select-interactive-process-hook* 'find-repl-thread)) + (funcall fun))) + +(defimplementation install-debugger-globally (function) + (setq *debugger-hook* function) + (setq ccl:*break-hook* function) + (setq ccl:*select-interactive-process-hook* 'find-repl-thread) + ) + +(defun map-backtrace (function &optional + (start-frame-number 0) + end-frame-number) + "Call FUNCTION passing information about each stack frame + from frames START-FRAME-NUMBER to END-FRAME-NUMBER." + (let ((end-frame-number (or end-frame-number most-positive-fixnum))) + (ccl:map-call-frames function + :origin ccl:*top-error-frame* + :start-frame-number start-frame-number + :count (- end-frame-number start-frame-number)))) + +(defimplementation compute-backtrace (start-frame-number end-frame-number) + (let (result) + (map-backtrace (lambda (p context) + (push (list :frame p context) result)) + start-frame-number end-frame-number) + (nreverse result))) + +(defimplementation print-frame (frame stream) + (assert (eq (first frame) :frame)) + (destructuring-bind (p context) (rest frame) + (let ((lfun (ccl:frame-function p context))) + (format stream "(~S" (or (ccl:function-name lfun) lfun)) + (let* ((unavailable (cons nil nil)) + (args (ccl:frame-supplied-arguments p context + :unknown-marker unavailable))) + (declare (dynamic-extent unavailable)) + (if (eq args unavailable) + (format stream " #") + (dolist (arg args) + (if (eq arg unavailable) + (format stream " #") + (format stream " ~s" arg))))) + (format stream ")")))) + +(defmacro with-frame ((p context) frame-number &body body) + `(call/frame ,frame-number (lambda (,p ,context) . ,body))) + +(defun call/frame (frame-number if-found) + (map-backtrace + (lambda (p context) + (return-from call/frame + (funcall if-found p context))) + frame-number)) + +(defimplementation frame-call (frame-number) + (with-frame (p context) frame-number + (with-output-to-string (stream) + (print-frame (list :frame p context) stream)))) + +(defimplementation frame-var-value (frame var) + (with-frame (p context) frame + (cdr (nth var (ccl:frame-named-variables p context))))) + +(defimplementation frame-locals (index) + (with-frame (p context) index + (loop for (name . value) in (ccl:frame-named-variables p context) + collect (list :name name :value value :id 0)))) + +(defimplementation frame-source-location (index) + (with-frame (p context) index + (multiple-value-bind (lfun pc) (ccl:frame-function p context) + (if pc + (pc-source-location lfun pc) + (function-source-location lfun))))) + +(defun function-name-package (name) + (etypecase name + (null nil) + (symbol (symbol-package name)) + ((cons (eql ccl::traced)) (function-name-package (second name))) + ((cons (eql setf)) (symbol-package (second name))) + ((cons (eql :internal)) (function-name-package (car (last name)))) + ((cons (and symbol (not keyword)) (or (cons list null) + (cons keyword (cons list null)))) + (symbol-package (car name))) + (standard-method (function-name-package (ccl:method-name name))))) + +(defimplementation frame-package (frame-number) + (with-frame (p context) frame-number + (let* ((lfun (ccl:frame-function p context)) + (name (ccl:function-name lfun))) + (function-name-package name)))) + +(defimplementation eval-in-frame (form index) + (with-frame (p context) index + (let ((vars (ccl:frame-named-variables p context))) + (eval `(let ,(loop for (var . val) in vars collect `(,var ',val)) + (declare (ignorable ,@(mapcar #'car vars))) + ,form))))) + +(defimplementation return-from-frame (index form) + (let ((values (multiple-value-list (eval-in-frame form index)))) + (with-frame (p context) index + (declare (ignore context)) + (ccl:apply-in-frame p #'values values)))) + +(defimplementation restart-frame (index) + (with-frame (p context) index + (ccl:apply-in-frame p + (ccl:frame-function p context) + (ccl:frame-supplied-arguments p context)))) + +(defimplementation disassemble-frame (the-frame-number) + (with-frame (p context) the-frame-number + (multiple-value-bind (lfun pc) (ccl:frame-function p context) + (format t "LFUN: ~a~%PC: ~a FP: #x~x CONTEXT: ~a~%" lfun pc p context) + (disassemble lfun)))) + +;; CCL commit r11373 | gz | 2008-11-16 16:35:28 +0100 (Sun, 16 Nov 2008) +;; contains some interesting details: +;; +;; Source location are recorded in CCL:SOURCE-NOTE's, which are objects +;; with accessors CCL:SOURCE-NOTE-FILENAME, CCL:SOURCE-NOTE-START-POS, +;; CCL:SOURCE-NOTE-END-POS and CCL:SOURCE-NOTE-TEXT. The start and end +;; positions are file positions (not character positions). The text will +;; be NIL unless text recording was on at read-time. If the original +;; file is still available, you can force missing source text to be read +;; from the file at runtime via CCL:ENSURE-SOURCE-NOTE-TEXT. +;; +;; Source-note's are associated with definitions (via record-source-file) +;; and also stored in function objects (including anonymous and nested +;; functions). The former can be retrieved via +;; CCL:FIND-DEFINITION-SOURCES, the latter via CCL:FUNCTION-SOURCE-NOTE. +;; +;; The recording behavior is controlled by the new variable +;; CCL:*SAVE-SOURCE-LOCATIONS*: +;; +;; If NIL, don't store source-notes in function objects, and store only +;; the filename for definitions (the latter only if +;; *record-source-file* is true). +;; +;; If T, store source-notes, including a copy of the original source +;; text, for function objects and definitions (the latter only if +;; *record-source-file* is true). +;; +;; If :NO-TEXT, store source-notes, but without saved text, for +;; function objects and defintions (the latter only if +;; *record-source-file* is true). This is the default. +;; +;; PC to source mapping is controlled by the new variable +;; CCL:*RECORD-PC-MAPPING*. If true (the default), functions store a +;; compressed table mapping pc offsets to corresponding source locations. +;; This can be retrieved by (CCL:FIND-SOURCE-NOTE-AT-PC function pc) +;; which returns a source-note for the source at offset pc in the +;; function. + +(defun function-source-location (function) + (source-note-to-source-location + (or (ccl:function-source-note function) + (function-name-source-note function)) + (lambda () + (format nil "Function has no source note: ~A" function)) + (ccl:function-name function))) + +(defun pc-source-location (function pc) + (source-note-to-source-location + (or (ccl:find-source-note-at-pc function pc) + (ccl:function-source-note function) + (function-name-source-note function)) + (lambda () + (format nil "No source note at PC: ~a[~d]" function pc)) + (ccl:function-name function))) + +(defun function-name-source-note (fun) + (let ((defs (ccl:find-definition-sources (ccl:function-name fun) 'function))) + (and defs + (destructuring-bind ((type . name) srcloc . srclocs) (car defs) + (declare (ignore type name srclocs)) + srcloc)))) + +(defun source-note-to-source-location (source if-nil-thunk &optional name) + (labels ((filename-to-buffer (filename) + (cond ((gethash filename *temp-file-map*) + (list :buffer (gethash filename *temp-file-map*))) + ((probe-file filename) + (list :file (ccl:native-translated-namestring + (truename filename)))) + (t (error "File ~s doesn't exist" filename))))) + (handler-case + (cond ((ccl:source-note-p source) + (let* ((full-text (ccl:source-note-text source)) + (file-name (ccl:source-note-filename source)) + (start-pos (ccl:source-note-start-pos source))) + (make-location + (when file-name (filename-to-buffer (pathname file-name))) + (when start-pos (list :position (1+ start-pos))) + (when full-text + (list :snippet (subseq full-text 0 + (min 40 (length full-text)))))))) + ((and source name) + ;; This branch is probably never used + (make-location + (filename-to-buffer source) + (list :function-name (princ-to-string + (if (functionp name) + (ccl:function-name name) + name))))) + (t `(:error ,(funcall if-nil-thunk)))) + (error (c) `(:error ,(princ-to-string c)))))) + +(defun alphatizer-definitions (name) + (let ((alpha (gethash name ccl::*nx1-alphatizers*))) + (and alpha (ccl:find-definition-sources alpha)))) + +(defun p2-definitions (name) + (let ((nx1-op (gethash name ccl::*nx1-operators*))) + (and nx1-op + (let ((dispatch (ccl::backend-p2-dispatch ccl::*target-backend*)) ) + (and (array-in-bounds-p dispatch nx1-op) + (let ((p2 (aref dispatch nx1-op))) + (and p2 + (ccl:find-definition-sources p2)))))))) + +(defimplementation find-definitions (name) + (let ((defs (append (or (ccl:find-definition-sources name) + (and (symbolp name) + (fboundp name) + (ccl:find-definition-sources + (symbol-function name)))) + (alphatizer-definitions name) + (p2-definitions name)))) + (loop for ((type . name) . sources) in defs + collect (list (definition-name type name) + (source-note-to-source-location + (find-if-not #'null sources) + (lambda () "No source-note available") + name))))) + +(defimplementation find-source-location (obj) + (let* ((defs (ccl:find-definition-sources obj)) + (best-def (or (find (ccl:name-of obj) defs :key #'cdar :test #'equal) + (car defs))) + (note (find-if-not #'null (cdr best-def)))) + (when note + (source-note-to-source-location + note + (lambda () "No source note available"))))) + +(defun definition-name (type object) + (case (ccl:definition-type-name type) + (method (ccl:name-of object)) + (t (list (ccl:definition-type-name type) (ccl:name-of object))))) + +;;; Utilities + +(defimplementation describe-symbol-for-emacs (symbol) + (let ((result '())) + (flet ((doc (kind &optional (sym symbol)) + (or (documentation sym kind) :not-documented)) + (maybe-push (property value) + (when value + (setf result (list* property value result))))) + (maybe-push + :variable (when (boundp symbol) + (doc 'variable))) + (maybe-push + :function (if (fboundp symbol) + (doc 'function))) + (maybe-push + :setf (let ((setf-function-name (ccl:setf-function-spec-name + `(setf ,symbol)))) + (when (fboundp setf-function-name) + (doc 'function setf-function-name)))) + (maybe-push + :type (when (ccl:type-specifier-p symbol) + (doc 'type))) + result))) + +(defimplementation describe-definition (symbol namespace) + (ecase namespace + (:variable + (describe symbol)) + ((:function :generic-function) + (describe (symbol-function symbol))) + (:setf + (describe (ccl:setf-function-spec-name `(setf ,symbol)))) + (:class + (describe (find-class symbol))) + (:type + (describe (or (find-class symbol nil) symbol))))) + +;; spec ::= (:defmethod {}* ({}*)) +(defun parse-defmethod-spec (spec) + (values (second spec) + (subseq spec 2 (position-if #'consp spec)) + (find-if #'consp (cddr spec)))) + +(defimplementation toggle-trace (spec) + "We currently ignore just about everything." + (let ((what (ecase (first spec) + ((setf) + spec) + ((:defgeneric) + (second spec)) + ((:defmethod) + (multiple-value-bind (name qualifiers specializers) + (parse-defmethod-spec spec) + (find-method (fdefinition name) + qualifiers + specializers)))))) + (cond ((member what (trace) :test #'equal) + (ccl::%untrace what) + (format nil "~S is now untraced." what)) + (t + (ccl:trace-function what) + (format nil "~S is now traced." what))))) + +;;; Macroexpansion + +(defimplementation macroexpand-all (form &optional env) + (ccl:macroexpand-all form env)) + +;;;; Inspection + +(defun comment-type-p (type) + (or (eq type :comment) + (and (consp type) (eq (car type) :comment)))) + +(defmethod emacs-inspect ((o t)) + (let* ((inspector:*inspector-disassembly* t) + (i (inspector:make-inspector o)) + (count (inspector:compute-line-count i))) + (loop for l from 0 below count append + (multiple-value-bind (value label type) (inspector:line-n i l) + (etypecase type + ((member nil :normal) + `(,(or label "") (:value ,value) (:newline))) + ((member :colon) + (label-value-line label value)) + ((member :static) + (list (princ-to-string label) " " `(:value ,value) '(:newline))) + ((satisfies comment-type-p) + (list (princ-to-string label) '(:newline)))))))) + +(defmethod emacs-inspect :around ((o t)) + (if (or (uvector-inspector-p o) + (not (ccl:uvectorp o))) + (call-next-method) + (let ((value (call-next-method))) + (cond ((listp value) + (append value + `((:newline) + (:value ,(make-instance 'uvector-inspector :object o) + "Underlying UVECTOR")))) + (t value))))) + +(defmethod emacs-inspect ((f function)) + (append + (label-value-line "Name" (function-name f)) + `("Its argument list is: " + ,(princ-to-string (arglist f)) (:newline)) + (label-value-line "Documentation" (documentation f t)) + (when (function-lambda-expression f) + (label-value-line "Lambda Expression" + (function-lambda-expression f))) + (when (ccl:function-source-note f) + (label-value-line "Source note" + (ccl:function-source-note f))) + (when (typep f 'ccl:compiled-lexical-closure) + (append + (label-value-line "Inner function" (ccl::closure-function f)) + '("Closed over values:" (:newline)) + (loop for (name value) in (ccl::closure-closed-over-values f) + append (label-value-line (format nil " ~a" name) + value)))))) + +(defclass uvector-inspector () + ((object :initarg :object))) + +(defgeneric uvector-inspector-p (object) + (:method ((object t)) nil) + (:method ((object uvector-inspector)) t)) + +(defmethod emacs-inspect ((uv uvector-inspector)) + (with-slots (object) uv + (loop for i below (ccl:uvsize object) append + (label-value-line (princ-to-string i) (ccl:uvref object i))))) + +(defimplementation type-specifier-p (symbol) + (or (ccl:type-specifier-p symbol) + (not (eq (type-specifier-arglist symbol) :not-available)))) + +;;; Multiprocessing + +(defvar *known-processes* + (make-hash-table :size 20 :weak :key :test #'eq) + "A map from threads to mailboxes.") + +(defvar *known-processes-lock* (ccl:make-lock "*known-processes-lock*")) + +(defstruct (mailbox (:conc-name mailbox.)) + (mutex (ccl:make-lock "thread mailbox")) + (semaphore (ccl:make-semaphore)) + (queue '() :type list)) + +(defimplementation spawn (fun &key name) + (ccl:process-run-function (or name "Anonymous (Swank)") + fun)) + +(defimplementation thread-id (thread) + (ccl:process-serial-number thread)) + +(defimplementation find-thread (id) + (find id (ccl:all-processes) :key #'ccl:process-serial-number)) + +(defimplementation thread-name (thread) + (ccl:process-name thread)) + +(defimplementation thread-status (thread) + (format nil "~A" (ccl:process-whostate thread))) + +(defimplementation thread-attributes (thread) + (list :priority (ccl:process-priority thread))) + +(defimplementation make-lock (&key name) + (ccl:make-lock name)) + +(defimplementation call-with-lock-held (lock function) + (ccl:with-lock-grabbed (lock) + (funcall function))) + +(defimplementation current-thread () + ccl:*current-process*) + +(defimplementation all-threads () + (ccl:all-processes)) + +(defimplementation kill-thread (thread) + ;;(ccl:process-kill thread) ; doesn't cut it + (ccl::process-initial-form-exited thread :kill)) + +(defimplementation thread-alive-p (thread) + (not (ccl:process-exhausted-p thread))) + +(defimplementation interrupt-thread (thread function) + (ccl:process-interrupt + thread + (lambda () + (let ((ccl:*top-error-frame* (ccl::%current-exception-frame))) + (funcall function))))) + +(defun mailbox (thread) + (ccl:with-lock-grabbed (*known-processes-lock*) + (or (gethash thread *known-processes*) + (setf (gethash thread *known-processes*) (make-mailbox))))) + +(defimplementation send (thread message) + (assert message) + (let* ((mbox (mailbox thread)) + (mutex (mailbox.mutex mbox))) + (ccl:with-lock-grabbed (mutex) + (setf (mailbox.queue mbox) + (nconc (mailbox.queue mbox) (list message))) + (ccl:signal-semaphore (mailbox.semaphore mbox))))) + +(defimplementation wake-thread (thread) + (let* ((mbox (mailbox thread)) + (mutex (mailbox.mutex mbox))) + (ccl:with-lock-grabbed (mutex) + (ccl:signal-semaphore (mailbox.semaphore mbox))))) + +(defimplementation receive-if (test &optional timeout) + (let* ((mbox (mailbox ccl:*current-process*)) + (mutex (mailbox.mutex mbox))) + (assert (or (not timeout) (eq timeout t))) + (loop + (check-slime-interrupts) + (ccl:with-lock-grabbed (mutex) + (let* ((q (mailbox.queue mbox)) + (tail (member-if test q))) + (when tail + (setf (mailbox.queue mbox) + (nconc (ldiff q tail) (cdr tail))) + (return (car tail))))) + (when (eq timeout t) (return (values nil t))) + (ccl:wait-on-semaphore (mailbox.semaphore mbox))))) + +(let ((alist '()) + (lock (ccl:make-lock "register-thread"))) + + (defimplementation register-thread (name thread) + (declare (type symbol name)) + (ccl:with-lock-grabbed (lock) + (etypecase thread + (null + (setf alist (delete name alist :key #'car))) + (ccl:process + (let ((probe (assoc name alist))) + (cond (probe (setf (cdr probe) thread)) + (t (setf alist (acons name thread alist)))))))) + nil) + + (defimplementation find-registered (name) + (ccl:with-lock-grabbed (lock) + (cdr (assoc name alist))))) + +(defimplementation set-default-initial-binding (var form) + (eval `(ccl::def-standard-initial-binding ,var ,form))) + +(defimplementation quit-lisp () + (ccl:quit)) + +(defimplementation set-default-directory (directory) + (let ((dir (truename (merge-pathnames directory)))) + (setf *default-pathname-defaults* (truename (merge-pathnames directory))) + (ccl:cwd dir) + (default-directory))) + +;;; Weak datastructures + +(defimplementation make-weak-key-hash-table (&rest args) + (apply #'make-hash-table :weak :key args)) + +(defimplementation make-weak-value-hash-table (&rest args) + (apply #'make-hash-table :weak :value args)) + +(defimplementation hash-table-weakness (hashtable) + (ccl:hash-table-weak-p hashtable)) + +(pushnew 'deinit-log-output ccl:*save-exit-functions*) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/clasp.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/clasp.lisp new file mode 100644 index 0000000..cc1705c --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/clasp.lisp @@ -0,0 +1,809 @@ +;;;; -*- indent-tabs-mode: nil -*- +;;; +;;; swank-clasp.lisp --- SLIME backend for CLASP. +;;; +;;; This code has been placed in the Public Domain. All warranties +;;; are disclaimed. +;;; + +;;; Administrivia + +(defpackage swank/clasp + (:use cl swank/backend)) + +(in-package swank/clasp) + +#+(or) +(eval-when (:compile-toplevel :load-toplevel :execute) + (setq swank::*log-output* (open "/tmp/slime.log" :direction :output)) + (setq swank:*log-events* t)) + +(defmacro slime-dbg (fmt &rest args) + `(swank::log-event "slime-dbg ~a ~a~%" mp:*current-process* (apply #'format nil ,fmt ,args))) + +;; Hard dependencies. +(eval-when (:compile-toplevel :load-toplevel :execute) + (require 'sockets)) + +;; Soft dependencies. +(eval-when (:compile-toplevel :load-toplevel :execute) + (when (probe-file "sys:profile.fas") + (require :profile) + (pushnew :profile *features*)) + (when (probe-file "sys:serve-event") + (require :serve-event) + (pushnew :serve-event *features*))) + +(declaim (optimize (debug 3))) + +;;; Swank-mop + +(eval-when (:compile-toplevel :load-toplevel :execute) + (import-swank-mop-symbols + :clos + nil + #+(or)`(:eql-specializer + :eql-specializer-object + :generic-function-declarations + :specializer-direct-methods + ,@(unless (fboundp 'clos:compute-applicable-methods-using-classes) + '(:compute-applicable-methods-using-classes))))) + +(defimplementation gray-package-name () + "GRAY") + + +;;;; TCP Server + +(defimplementation preferred-communication-style () + ;; As of March 2017 CLASP provides threads. + ;; But it's experimental. + ;; ECLs swank implementation says that CLOS is not thread safe and + ;; I use ECLs CLOS implementation - this is a worry for the future. + ;; nil or :spawn + ;; nil + :spawn +#| #+threads :spawn + #-threads nil +|# + ) + +(defun resolve-hostname (name) + (car (sb-bsd-sockets:host-ent-addresses + (sb-bsd-sockets:get-host-by-name name)))) + +(defimplementation create-socket (host port &key backlog) + (let ((socket (make-instance 'sb-bsd-sockets:inet-socket + :type :stream + :protocol :tcp))) + (setf (sb-bsd-sockets:sockopt-reuse-address socket) t) + (sb-bsd-sockets:socket-bind socket (resolve-hostname host) port) + (sb-bsd-sockets:socket-listen socket (or backlog 5)) + socket)) + +(defimplementation local-port (socket) + (nth-value 1 (sb-bsd-sockets:socket-name socket))) + +(defimplementation close-socket (socket) + (sb-bsd-sockets:socket-close socket)) + +(defimplementation accept-connection (socket + &key external-format + buffering timeout) + (declare (ignore timeout)) + (sb-bsd-sockets:socket-make-stream (accept socket) + :output t + :input t + :buffering (ecase buffering + ((t) :full) + ((nil) :none) + (:line :line)) + :element-type (if external-format + 'character + '(unsigned-byte 8)) + :external-format external-format)) +(defun accept (socket) + "Like socket-accept, but retry on EAGAIN." + (loop (handler-case + (return (sb-bsd-sockets:socket-accept socket)) + (sb-bsd-sockets:interrupted-error ())))) + +(defimplementation socket-fd (socket) + (etypecase socket + (fixnum socket) + (two-way-stream (socket-fd (two-way-stream-input-stream socket))) + (sb-bsd-sockets:socket (sb-bsd-sockets:socket-file-descriptor socket)) + (file-stream (si:file-stream-fd socket)))) + +(defvar *external-format-to-coding-system* + '((:latin-1 + "latin-1" "latin-1-unix" "iso-latin-1-unix" + "iso-8859-1" "iso-8859-1-unix") + (:utf-8 "utf-8" "utf-8-unix"))) + +(defun external-format (coding-system) + (or (car (rassoc-if (lambda (x) (member coding-system x :test #'equal)) + *external-format-to-coding-system*)) + (find coding-system (ext:all-encodings) :test #'string-equal))) + +(defimplementation find-external-format (coding-system) + #+unicode (external-format coding-system) + ;; Without unicode support, CLASP uses the one-byte encoding of the + ;; underlying OS, and will barf on anything except :DEFAULT. We + ;; return NIL here for known multibyte encodings, so + ;; SWANK:CREATE-SERVER will barf. + #-unicode (let ((xf (external-format coding-system))) + (if (member xf '(:utf-8)) + nil + :default))) + + +;;;; Unix Integration + +;;; If CLASP is built with thread support, it'll spawn a helper thread +;;; executing the SIGINT handler. We do not want to BREAK into that +;;; helper but into the main thread, though. This is coupled with the +;;; current choice of NIL as communication-style in so far as CLASP's +;;; main-thread is also the Slime's REPL thread. + +#+clasp-working +(defimplementation call-with-user-break-handler (real-handler function) + (let ((old-handler #'si:terminal-interrupt)) + (setf (symbol-function 'si:terminal-interrupt) + (make-interrupt-handler real-handler)) + (unwind-protect (funcall function) + (setf (symbol-function 'si:terminal-interrupt) old-handler)))) + +#+threads +(defun make-interrupt-handler (real-handler) + (let ((main-thread (find 'si:top-level (mp:all-processes) + :key #'mp:process-name))) + #'(lambda (&rest args) + (declare (ignore args)) + (mp:interrupt-process main-thread real-handler)))) + +#-threads +(defun make-interrupt-handler (real-handler) + #'(lambda (&rest args) + (declare (ignore args)) + (funcall real-handler))) + + +(defimplementation getpid () + (si:getpid)) + +(defimplementation set-default-directory (directory) + (ext:chdir (namestring directory)) ; adapts *DEFAULT-PATHNAME-DEFAULTS*. + (default-directory)) + +(defimplementation default-directory () + (namestring (ext:getcwd))) + +(defimplementation quit-lisp () + (core:quit)) + + + +;;; Instead of busy waiting with communication-style NIL, use select() +;;; on the sockets' streams. +#+serve-event +(progn + (defun poll-streams (streams timeout) + (let* ((serve-event::*descriptor-handlers* + (copy-list serve-event::*descriptor-handlers*)) + (active-fds '()) + (fd-stream-alist + (loop for s in streams + for fd = (socket-fd s) + collect (cons fd s) + do (serve-event:add-fd-handler fd :input + #'(lambda (fd) + (push fd active-fds)))))) + (serve-event:serve-event timeout) + (loop for fd in active-fds collect (cdr (assoc fd fd-stream-alist))))) + + (defimplementation wait-for-input (streams &optional timeout) + (assert (member timeout '(nil t))) + (loop + (cond ((check-slime-interrupts) (return :interrupt)) + (timeout (return (poll-streams streams 0))) + (t + (when-let (ready (poll-streams streams 0.2)) + (return ready)))))) + +) ; #+serve-event (progn ... + +#-serve-event +(defimplementation wait-for-input (streams &optional timeout) + (assert (member timeout '(nil t))) + (loop + (cond ((check-slime-interrupts) (return :interrupt)) + (timeout (return (remove-if-not #'listen streams))) + (t + (let ((ready (remove-if-not #'listen streams))) + (if ready (return ready)) + (sleep 0.1)))))) + + +;;;; Compilation + +(defvar *buffer-name* nil) +(defvar *buffer-start-position*) + +(defun signal-compiler-condition (&rest args) + (apply #'signal 'compiler-condition args)) + +#-clasp-bytecmp +(defun handle-compiler-message (condition) + ;; CLASP emits lots of noise in compiler-notes, like "Invoking + ;; external command". + (unless (typep condition 'c::compiler-note) + (signal-compiler-condition + :original-condition condition + :message (princ-to-string condition) + :severity (etypecase condition + (cmp:compiler-fatal-error :error) + (cmp:compiler-error :error) + (error :error) + (style-warning :style-warning) + (warning :warning)) + :location (condition-location condition)))) + +#-clasp-bytecmp +(defun condition-location (condition) + (let ((file (cmp:compiler-message-file condition)) + (position (cmp:compiler-message-file-position condition))) + (if (and position (not (minusp position))) + (if *buffer-name* + (make-buffer-location *buffer-name* + *buffer-start-position* + position) + (make-file-location file position)) + (make-error-location "No location found.")))) + +(defimplementation call-with-compilation-hooks (function) + (funcall function)) +#|| #-clasp-bytecmp + (handler-bind ((c:compiler-message #'handle-compiler-message)) + (funcall function))) +||# + + +(defimplementation swank-compile-file (input-file output-file + load-p external-format + &key policy) + (declare (ignore policy)) + (format t "Compiling file input-file = ~a output-file = ~a~%" input-file output-file) + ;; Ignore the output-file and generate our own + (let ((tmp-output-file (compile-file-pathname (si:mkstemp "TMP:clasp-swank-compile-file-")))) + (format t "Using tmp-output-file: ~a~%" tmp-output-file) + (multiple-value-bind (fasl warnings-p failure-p) + (with-compilation-hooks () + (compile-file input-file :output-file tmp-output-file + :external-format external-format)) + (values fasl warnings-p + (or failure-p + (when load-p + (not (load fasl)))))))) + +(defvar *tmpfile-map* (make-hash-table :test #'equal)) + +(defun note-buffer-tmpfile (tmp-file buffer-name) + ;; EXT:COMPILED-FUNCTION-FILE below will return a namestring. + (let ((tmp-namestring (namestring (truename tmp-file)))) + (setf (gethash tmp-namestring *tmpfile-map*) buffer-name) + tmp-namestring)) + +(defun tmpfile-to-buffer (tmp-file) + (gethash tmp-file *tmpfile-map*)) + +(defimplementation swank-compile-string (string &key buffer position filename policy) + (declare (ignore policy)) + (with-compilation-hooks () + (let ((*buffer-name* buffer) ; for compilation hooks + (*buffer-start-position* position)) + (let ((tmp-file (si:mkstemp "TMP:clasp-swank-tmpfile-")) + (fasl-file) + (warnings-p) + (failure-p)) + (unwind-protect + (with-open-file (tmp-stream tmp-file :direction :output + :if-exists :supersede) + (write-string string tmp-stream) + (finish-output tmp-stream) + (multiple-value-setq (fasl-file warnings-p failure-p) + (let ((truename (or filename (note-buffer-tmpfile tmp-file buffer)))) + (compile-file tmp-file + :source-debug-pathname (pathname truename) + :source-debug-offset (1- position))))) + (when fasl-file (load fasl-file)) + (when (probe-file tmp-file) + (delete-file tmp-file)) + (when fasl-file + (delete-file fasl-file))) + (not failure-p))))) + +;;;; Documentation + +(defimplementation arglist (name) + (multiple-value-bind (arglist foundp) + (core:function-lambda-list name) ;; Uses bc-split + (if foundp arglist :not-available))) + +(defimplementation function-name (f) + (typecase f + (generic-function (clos::generic-function-name f)) + (function (ext:compiled-function-name f)))) + +;; FIXME +(defimplementation macroexpand-all (form &optional env) + (declare (ignore env)) + (macroexpand form)) + +;;; modified from sbcl.lisp +(defimplementation collect-macro-forms (form &optional environment) + (let ((macro-forms '()) + (compiler-macro-forms '()) + (function-quoted-forms '())) + (format t "In collect-macro-forms~%") + (cmp:code-walk + form environment + :code-walker-function + (lambda (form environment) + (when (and (consp form) + (symbolp (car form))) + (cond ((eq (car form) 'function) + (push (cadr form) function-quoted-forms)) + ((member form function-quoted-forms) + nil) + ((macro-function (car form) environment) + (push form macro-forms)) + ((not (eq form (core:compiler-macroexpand-1 form environment))) + (push form compiler-macro-forms)))) + form)) + (values macro-forms compiler-macro-forms))) + + + + + +(defimplementation describe-symbol-for-emacs (symbol) + (let ((result '())) + (flet ((frob (type boundp) + (when (funcall boundp symbol) + (let ((doc (describe-definition symbol type))) + (setf result (list* type doc result)))))) + (frob :VARIABLE #'boundp) + (frob :FUNCTION #'fboundp) + (frob :CLASS (lambda (x) (find-class x nil)))) + result)) + +(defimplementation describe-definition (name type) + (case type + (:variable (documentation name 'variable)) + (:function (documentation name 'function)) + (:class (documentation name 'class)) + (t nil))) + +(defimplementation type-specifier-p (symbol) + (or (subtypep nil symbol) + (not (eq (type-specifier-arglist symbol) :not-available)))) + + +;;; Debugging + +(eval-when (:compile-toplevel :load-toplevel :execute) + (import + '(si::*break-env* + si::*ihs-top* + si::*ihs-current* + si::*ihs-base* +#+frs si::*frs-base* +#+frs si::*frs-top* + si::*tpl-commands* + si::*tpl-level* +#+frs si::frs-top + si::ihs-top + si::ihs-fun + si::ihs-env +#+frs si::sch-frs-base + si::set-break-env + si::set-current-ihs + si::tpl-commands))) + +(defun make-invoke-debugger-hook (hook) + (when hook + #'(lambda (condition old-hook) + ;; Regard *debugger-hook* if set by user. + (if *debugger-hook* + nil ; decline, *DEBUGGER-HOOK* will be tried next. + (funcall hook condition old-hook))))) + +(defimplementation install-debugger-globally (function) + (setq *debugger-hook* function) + (setq ext:*invoke-debugger-hook* (make-invoke-debugger-hook function)) + ) + +(defimplementation call-with-debugger-hook (hook fun) + (let ((*debugger-hook* hook) + (ext:*invoke-debugger-hook* (make-invoke-debugger-hook hook))) + (funcall fun)) + ) + +(defvar *backtrace* '()) + +;;; Commented out; it's not clear this is a good way of doing it. In +;;; particular because it makes errors stemming from this file harder +;;; to debug, and given the "young" age of CLASP's swank backend, that's +;;; a bad idea. + +;; (defun in-swank-package-p (x) +;; (and +;; (symbolp x) +;; (member (symbol-package x) +;; (list #.(find-package :swank) +;; #.(find-package :swank/backend) +;; #.(ignore-errors (find-package :swank-mop)) +;; #.(ignore-errors (find-package :swank-loader)))) +;; t)) + +;; (defun is-swank-source-p (name) +;; (setf name (pathname name)) +;; (pathname-match-p +;; name +;; (make-pathname :defaults swank-loader::*source-directory* +;; :name (pathname-name name) +;; :type (pathname-type name) +;; :version (pathname-version name)))) + +;; (defun is-ignorable-fun-p (x) +;; (or +;; (in-swank-package-p (frame-name x)) +;; (multiple-value-bind (file position) +;; (ignore-errors (si::bc-file (car x))) +;; (declare (ignore position)) +;; (if file (is-swank-source-p file))))) + +(defimplementation call-with-debugging-environment (debugger-loop-fn) + (declare (type function debugger-loop-fn)) + (let* ((*ihs-top* 0) + (*ihs-current* *ihs-top*) + #+frs (*frs-base* (or (sch-frs-base *frs-top* *ihs-base*) (1+ (frs-top)))) + #+frs (*frs-top* (frs-top)) + (*tpl-level* (1+ *tpl-level*))) + (core:call-with-backtrace + (lambda (raw-backtrace) + (let ((*backtrace* + (let ((backtrace (core::common-lisp-backtrace-frames + raw-backtrace + :gather-start-trigger + (lambda (frame) + (let ((function-name (core::backtrace-frame-function-name frame))) + (and (symbolp function-name) + (eq function-name 'core::universal-error-handler)))) + :gather-all-frames nil))) + (unless backtrace + (setq backtrace (core::common-lisp-backtrace-frames + :gather-all-frames nil))) + backtrace))) + (declare (special *ihs-current*)) + (set-break-env) + (set-current-ihs) + (let ((*ihs-base* *ihs-top*)) + (funcall debugger-loop-fn))))))) + +(defimplementation compute-backtrace (start end) + (subseq *backtrace* start + (and (numberp end) + (min end (length *backtrace*))))) + +(defun frame-name (frame) + (let ((x (core::backtrace-frame-function-name frame))) + (if (symbolp x) + x + (function-name x)))) + +(defun frame-function (frame-number) + (let ((x (core::backtrace-frame-function-name (elt *backtrace* frame-number)))) + (etypecase x + (symbol + (and (fboundp x) + (fdefinition x))) + (cons + (if (eq (car x) 'cl:setf) + (fdefinition x) + nil)) + (function + x)))) + +(defimplementation print-frame (frame stream) + (if (core::backtrace-frame-arguments frame) + (format stream "(~a~{ ~s~})" (core::backtrace-frame-print-name frame) + (coerce (core::backtrace-frame-arguments frame) 'list)) + (format stream "~a" (core::backtrace-frame-print-name frame)))) + +(defimplementation frame-source-location (frame-number) + (let* ((address (core::backtrace-frame-return-address (elt *backtrace* frame-number))) + (code-source-location (ext::code-source-position address))) + (format t "code-source-location ~s~%" code-source-location) + ;; (core::source-info-backtrace *backtrace*) + (make-location (list :file (namestring (ext::code-source-line-source-pathname code-source-location))) + (list :line (ext::code-source-line-line-number code-source-location)) + '(:align t)))) + +#+clasp-working +(defimplementation frame-catch-tags (frame-number) + (third (elt *backtrace* frame-number))) + +(defun ihs-frame-id (frame-number) + (- (core:ihs-top) frame-number)) + +(defimplementation frame-locals (frame-number) + (let* ((frame (elt *backtrace* frame-number)) + (env nil) ; no env yet + (locals (loop for x = env then (core:get-parent-environment x) + while x + nconc (loop for name across (core:environment-debug-names x) + for value across (core:environment-debug-values x) + collect (list :name name :id 0 :value value))))) + (nconc + (loop for arg across (core::backtrace-frame-arguments frame) + for i from 0 + collect (list :name (intern (format nil "ARG~d" i) :cl-user) + :id 0 + :value arg)) + locals))) + +(defimplementation frame-var-value (frame-number var-number) + (let* ((frame (elt *backtrace* frame-number)) + (env nil) + (args (core::backtrace-frame-arguments frame))) + (if (< var-number (length args)) + (svref args var-number) + (elt (frame-locals frame-number) var-number)))) + +(defimplementation disassemble-frame (frame-number) + (let ((fun (frame-function frame-number))) + (disassemble fun))) + +(defimplementation eval-in-frame (form frame-number) + (let* ((frame (elt *backtrace* frame-number)) + (raw-arg-values (coerce (core::backtrace-frame-arguments frame) 'list))) + (if (and (= (length raw-arg-values) 2) (core:vaslistp (car raw-arg-values))) + (let* ((arg-values (core:list-from-va-list (car raw-arg-values))) + (bindings (append (loop for i from 0 for value in arg-values collect `(,(intern (core:bformat nil "ARG%d" i) :cl-user) ',value)) + (list (list (intern "NEXT-METHODS" :cl-user) (cadr raw-arg-values)))))) + (eval + `(let (,@bindings) ,form))) + (let* ((arg-values raw-arg-values) + (bindings (loop for i from 0 for value in arg-values collect `(,(intern (core:bformat nil "ARG%d" i) :cl-user) ',value)))) + (eval + `(let (,@bindings) ,form)))))) + + +#+clasp-working +(defimplementation gdb-initial-commands () + ;; These signals are used by the GC. + #+linux '("handle SIGPWR noprint nostop" + "handle SIGXCPU noprint nostop")) + +#+clasp-working +(defimplementation command-line-args () + (loop for n from 0 below (si:argc) collect (si:argv n))) + + +;;;; Inspector + +;;; FIXME: Would be nice if it was possible to inspect objects +;;; implemented in C. + + +;;;; Definitions + +(defun make-file-location (file file-position) + ;; File positions in CL start at 0, but Emacs' buffer positions + ;; start at 1. We specify (:ALIGN T) because the positions comming + ;; from CLASP point at right after the toplevel form appearing before + ;; the actual target toplevel form; (:ALIGN T) will DTRT in that case. + (make-location `(:file ,(namestring (translate-logical-pathname file))) + `(:position ,(1+ file-position)) + `(:align t))) + +(defun make-buffer-location (buffer-name start-position &optional (offset 0)) + (make-location `(:buffer ,buffer-name) + `(:offset ,start-position ,offset) + `(:align t))) + +(defun translate-location (location) + (make-location (list :file (namestring (ext:source-location-pathname location))) + (list :position (ext:source-location-offset location)) + '(:align t))) + +(defimplementation find-definitions (name) + (loop for kind in ext:*source-location-kinds* + for locations = (ext:source-location name kind) + when locations + nconc (loop for location in locations + collect (list kind (translate-location location))))) + +(defun source-location (object) + (let ((location (ext:source-location object t))) + (when location + (translate-location (car location))))) + +(defimplementation find-source-location (object) + (or (source-location object) + (make-error-location "Source definition of ~S not found." object))) + + +;;;; Profiling + +#+profile +(progn + +(defimplementation profile (fname) + (when fname (eval `(profile:profile ,fname)))) + +(defimplementation unprofile (fname) + (when fname (eval `(profile:unprofile ,fname)))) + +(defimplementation unprofile-all () + (profile:unprofile-all) + "All functions unprofiled.") + +(defimplementation profile-report () + (profile:report)) + +(defimplementation profile-reset () + (profile:reset) + "Reset profiling counters.") + +(defimplementation profiled-functions () + (profile:profile)) + +(defimplementation profile-package (package callers methods) + (declare (ignore callers methods)) + (eval `(profile:profile ,(package-name (find-package package))))) +) ; #+profile (progn ... + + +;;;; Threads + +#+threads +(progn + (defvar *thread-id-counter* 0) + + (defparameter *thread-id-map* (make-hash-table)) + + (defvar *thread-id-map-lock* + (mp:make-lock :name "thread id map lock")) + + (defimplementation spawn (fn &key name) + (mp:process-run-function name fn)) + + (defimplementation thread-id (target-thread) + (block thread-id + (mp:with-lock (*thread-id-map-lock*) + ;; Does TARGET-THREAD have an id already? + (maphash (lambda (id thread-pointer) + (let ((thread (si:weak-pointer-value thread-pointer))) + (cond ((not thread) + (remhash id *thread-id-map*)) + ((eq thread target-thread) + (return-from thread-id id))))) + *thread-id-map*) + ;; TARGET-THREAD not found in *THREAD-ID-MAP* + (let ((id (incf *thread-id-counter*)) + (thread-pointer (si:make-weak-pointer target-thread))) + (setf (gethash id *thread-id-map*) thread-pointer) + id)))) + + (defimplementation find-thread (id) + (mp:with-lock (*thread-id-map-lock*) + (let* ((thread-ptr (gethash id *thread-id-map*)) + (thread (and thread-ptr (si:weak-pointer-value thread-ptr)))) + (unless thread + (remhash id *thread-id-map*)) + thread))) + + (defimplementation thread-name (thread) + (mp:process-name thread)) + + (defimplementation thread-status (thread) + (if (mp:process-active-p thread) + "RUNNING" + "STOPPED")) + + (defimplementation make-lock (&key name) + (mp:make-lock :name name :recursive t)) + + (defimplementation call-with-lock-held (lock function) + (declare (type function function)) + (mp:with-lock (lock) (funcall function))) + + (defimplementation current-thread () + mp:*current-process*) + + (defimplementation all-threads () + (mp:all-processes)) + + (defimplementation interrupt-thread (thread fn) + (mp:interrupt-process thread fn)) + + (defimplementation kill-thread (thread) + (mp:process-kill thread)) + + (defimplementation thread-alive-p (thread) + (mp:process-active-p thread)) + + (defvar *mailbox-lock* (mp:make-lock :name "mailbox lock")) + (defvar *mailboxes* (list)) + (declaim (type list *mailboxes*)) + + (defstruct (mailbox (:conc-name mailbox.)) + thread + (mutex (mp:make-lock :name "SLIMELCK")) + (cvar (mp:make-condition-variable)) + (queue '() :type list)) + + (defun mailbox (thread) + "Return THREAD's mailbox." + (mp:with-lock (*mailbox-lock*) + (or (find thread *mailboxes* :key #'mailbox.thread) + (let ((mb (make-mailbox :thread thread))) + (push mb *mailboxes*) + mb)))) + + (defimplementation wake-thread (thread) + (let* ((mbox (mailbox thread)) + (mutex (mailbox.mutex mbox))) + (format t "About to with-lock in wake-thread~%") + (mp:with-lock (mutex) + (format t "In wake-thread~%") + (mp:condition-variable-broadcast (mailbox.cvar mbox))))) + + (defimplementation send (thread message) + (let* ((mbox (mailbox thread)) + (mutex (mailbox.mutex mbox))) + (swank::log-event "clasp.lisp: send message ~a mutex: ~a~%" message mutex) + (swank::log-event "clasp.lisp: (lock-owner mutex) -> ~a~%" (mp:lock-owner mutex)) + (swank::log-event "clasp.lisp: (lock-count mutex) -> ~a~%" (mp:lock-count mutex)) + (mp:with-lock (mutex) + (swank::log-event "clasp.lisp: in with-lock (lock-owner mutex) -> ~a~%" (mp:lock-owner mutex)) + (swank::log-event "clasp.lisp: in with-lock (lock-count mutex) -> ~a~%" (mp:lock-count mutex)) + (setf (mailbox.queue mbox) + (nconc (mailbox.queue mbox) (list message))) + (swank::log-event "clasp.lisp: send about to broadcast~%") + (mp:condition-variable-broadcast (mailbox.cvar mbox))))) + + + (defimplementation receive-if (test &optional timeout) + (slime-dbg "Entered receive-if") + (let* ((mbox (mailbox (current-thread))) + (mutex (mailbox.mutex mbox))) + (slime-dbg "receive-if assert") + (assert (or (not timeout) (eq timeout t))) + (loop + (slime-dbg "receive-if check-slime-interrupts") + (check-slime-interrupts) + (slime-dbg "receive-if with-lock") + (mp:with-lock (mutex) + (let* ((q (mailbox.queue mbox)) + (tail (member-if test q))) + (when tail + (setf (mailbox.queue mbox) (nconc (ldiff q tail) (cdr tail))) + (return (car tail)))) + (slime-dbg "receive-if when (eq") + (when (eq timeout t) (return (values nil t))) + (slime-dbg "receive-if condition-variable-timedwait") + (mp:condition-variable-wait (mailbox.cvar mbox) mutex) ; timedwait 0.2 + (slime-dbg "came out of condition-variable-timedwait") + (core:check-pending-interrupts))))) + + ) ; #+threads (progn ... + + +(defmethod emacs-inspect ((object core:cxx-object)) + (let ((encoded (core:encode object))) + (loop for (key . value) in encoded + append (list (string key) ": " (list :value value) (list :newline))))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/clisp.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/clisp.lisp new file mode 100644 index 0000000..27ae688 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/clisp.lisp @@ -0,0 +1,930 @@ +;;;; -*- indent-tabs-mode: nil -*- + +;;;; SWANK support for CLISP. + +;;;; Copyright (C) 2003, 2004 W. Jenkner, V. Sedach + +;;;; This program is free software; you can redistribute it and/or +;;;; modify it under the terms of the GNU General Public License as +;;;; published by the Free Software Foundation; either version 2 of +;;;; the License, or (at your option) any later version. + +;;;; This program is distributed in the hope that it will be useful, +;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;;; GNU General Public License for more details. + +;;;; You should have received a copy of the GNU General Public +;;;; License along with this program; if not, write to the Free +;;;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +;;;; MA 02111-1307, USA. + +;;; This is work in progress, but it's already usable. Many things +;;; are adapted from other swank-*.lisp, in particular from +;;; swank-allegro (I don't use allegro at all, but it's the shortest +;;; one and I found Helmut Eller's code there enlightening). + +;;; This code will work better with recent versions of CLISP (say, the +;;; last release or CVS HEAD) while it may not work at all with older +;;; versions. It is reasonable to expect it to work on platforms with +;;; a "SOCKET" package, in particular on GNU/Linux or Unix-like +;;; systems, but also on Win32. This backend uses the portable xref +;;; from the CMU AI repository and metering.lisp from CLOCC [1], which +;;; are conveniently included in SLIME. + +;;; [1] http://cvs.sourceforge.net/viewcvs.py/clocc/clocc/src/tools/metering/ + +(defpackage swank/clisp + (:use cl swank/backend)) + +(in-package swank/clisp) + +(eval-when (:compile-toplevel) + (unless (string< "2.44" (lisp-implementation-version)) + (error "Need at least CLISP version 2.44"))) + +(defimplementation gray-package-name () + "GRAY") + +;;;; if this lisp has the complete CLOS then we use it, otherwise we +;;;; build up a "fake" swank-mop and then override the methods in the +;;;; inspector. + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defvar *have-mop* + (and (find-package :clos) + (eql :external + (nth-value 1 (find-symbol (string ':standard-slot-definition) + :clos)))) + "True in those CLISP images which have a complete MOP implementation.")) + +#+#.(cl:if swank/clisp::*have-mop* '(cl:and) '(cl:or)) +(progn + (import-swank-mop-symbols :clos '(:slot-definition-documentation)) + + (defun swank-mop:slot-definition-documentation (slot) + (clos::slot-definition-documentation slot))) + +#-#.(cl:if swank/clisp::*have-mop* '(and) '(or)) +(defclass swank-mop:standard-slot-definition () + () + (:documentation + "Dummy class created so that swank.lisp will compile and load.")) + +(let ((getpid (or (find-symbol "PROCESS-ID" :system) + ;; old name prior to 2005-03-01, clisp <= 2.33.2 + (find-symbol "PROGRAM-ID" :system) + #+win32 ; integrated into the above since 2005-02-24 + (and (find-package :win32) ; optional modules/win32 + (find-symbol "GetCurrentProcessId" :win32))))) + (defimplementation getpid () ; a required interface + (cond + (getpid (funcall getpid)) + #+win32 ((ext:getenv "PID")) ; where does that come from? + (t -1)))) + +(defimplementation call-with-user-break-handler (handler function) + (handler-bind ((system::simple-interrupt-condition + (lambda (c) + (declare (ignore c)) + (funcall handler) + (when (find-restart 'socket-status) + (invoke-restart (find-restart 'socket-status))) + (continue)))) + (funcall function))) + +(defimplementation lisp-implementation-type-name () + "clisp") + +(defimplementation set-default-directory (directory) + (setf (ext:default-directory) directory) + (namestring (setf *default-pathname-defaults* (ext:default-directory)))) + +(defimplementation filename-to-pathname (string) + (cond ((member :cygwin *features*) + (parse-cygwin-filename string)) + (t (parse-namestring string)))) + +(defun parse-cygwin-filename (string) + (multiple-value-bind (match _ drive absolute) + (regexp:match "^(([a-zA-Z\\]+):)?([\\/])?" string :extended t) + (declare (ignore _)) + (assert (and match (if drive absolute t)) () + "Invalid filename syntax: ~a" string) + (let* ((sans-prefix (subseq string (regexp:match-end match))) + (path (remove "" (regexp:regexp-split "[\\/]" sans-prefix))) + (path (loop for name in path collect + (cond ((equal name "..") ':back) + (t name)))) + (directoryp (or (equal string "") + (find (aref string (1- (length string))) "\\/")))) + (multiple-value-bind (file type) + (cond ((and (not directoryp) (last path)) + (let* ((file (car (last path))) + (pos (position #\. file :from-end t))) + (cond ((and pos (> pos 0)) + (values (subseq file 0 pos) + (subseq file (1+ pos)))) + (t file))))) + (make-pathname :host nil + :device nil + :directory (cons + (if absolute :absolute :relative) + (let ((path (if directoryp + path + (butlast path)))) + (if drive + (cons + (regexp:match-string string drive) + path) + path))) + :name file + :type type))))) + +;;;; UTF + +(defimplementation string-to-utf8 (string) + (let ((enc (load-time-value + (ext:make-encoding :charset "utf-8" :line-terminator :unix) + t))) + (ext:convert-string-to-bytes string enc))) + +(defimplementation utf8-to-string (octets) + (let ((enc (load-time-value + (ext:make-encoding :charset "utf-8" :line-terminator :unix) + t))) + (ext:convert-string-from-bytes octets enc))) + +;;;; TCP Server + +(defimplementation create-socket (host port &key backlog) + (socket:socket-server port :interface host :backlog (or backlog 5))) + +(defimplementation local-port (socket) + (socket:socket-server-port socket)) + +(defimplementation close-socket (socket) + (socket:socket-server-close socket)) + +(defimplementation accept-connection (socket + &key external-format buffering timeout) + (declare (ignore buffering timeout)) + (socket:socket-accept socket + :buffered buffering ;; XXX may not work if t + :element-type (if external-format + 'character + '(unsigned-byte 8)) + :external-format (or external-format :default))) + +#-win32 +(defimplementation wait-for-input (streams &optional timeout) + (assert (member timeout '(nil t))) + (let ((streams (mapcar (lambda (s) (list* s :input nil)) streams))) + (loop + (cond ((check-slime-interrupts) (return :interrupt)) + (timeout + (socket:socket-status streams 0 0) + (return (loop for (s nil . x) in streams + if x collect s))) + (t + (with-simple-restart (socket-status "Return from socket-status.") + (socket:socket-status streams 0 500000)) + (let ((ready (loop for (s nil . x) in streams + if x collect s))) + (when ready (return ready)))))))) + +#+win32 +(defimplementation wait-for-input (streams &optional timeout) + (assert (member timeout '(nil t))) + (loop + (cond ((check-slime-interrupts) (return :interrupt)) + (t + (let ((ready (remove-if-not #'input-available-p streams))) + (when ready (return ready))) + (when timeout (return nil)) + (sleep 0.1))))) + +#+win32 +;; Some facts to remember (for the next time we need to debug this): +;; - interactive-sream-p returns t for socket-streams +;; - listen returns nil for socket-streams +;; - (type-of ) is 'stream +;; - (type-of *terminal-io*) is 'two-way-stream +;; - stream-element-type on our sockets is usually (UNSIGNED-BYTE 8) +;; - calling socket:socket-status on non sockets signals an error, +;; but seems to mess up something internally. +;; - calling read-char-no-hang on sockets does not signal an error, +;; but seems to mess up something internally. +(defun input-available-p (stream) + (case (stream-element-type stream) + (character + (let ((c (read-char-no-hang stream nil nil))) + (cond ((not c) + nil) + (t + (unread-char c stream) + t)))) + (t + (eq (socket:socket-status (cons stream :input) 0 0) + :input)))) + +;;;; Coding systems + +(defvar *external-format-to-coding-system* + '(((:charset "iso-8859-1" :line-terminator :unix) + "latin-1-unix" "iso-latin-1-unix" "iso-8859-1-unix") + ((:charset "iso-8859-1") + "latin-1" "iso-latin-1" "iso-8859-1") + ((:charset "utf-8") "utf-8") + ((:charset "utf-8" :line-terminator :unix) "utf-8-unix") + ((:charset "euc-jp") "euc-jp") + ((:charset "euc-jp" :line-terminator :unix) "euc-jp-unix") + ((:charset "us-ascii") "us-ascii") + ((:charset "us-ascii" :line-terminator :unix) "us-ascii-unix"))) + +(defimplementation find-external-format (coding-system) + (let ((args (car (rassoc-if (lambda (x) + (member coding-system x :test #'equal)) + *external-format-to-coding-system*)))) + (and args (apply #'ext:make-encoding args)))) + + +;;;; Swank functions + +(defimplementation arglist (fname) + (block nil + (or (ignore-errors + (let ((exp (function-lambda-expression fname))) + (and exp (return (second exp))))) + (ignore-errors + (return (ext:arglist fname))) + :not-available))) + +(defimplementation macroexpand-all (form &optional env) + (declare (ignore env)) + (ext:expand-form form)) + +(defimplementation collect-macro-forms (form &optional env) + ;; Currently detects only normal macros, not compiler macros. + (declare (ignore env)) + (with-collected-macro-forms (macro-forms) + (handler-bind ((warning #'muffle-warning)) + (ignore-errors + (compile nil `(lambda () ,form)))) + (values macro-forms nil))) + +(defimplementation describe-symbol-for-emacs (symbol) + "Return a plist describing SYMBOL. +Return NIL if the symbol is unbound." + (let ((result ())) + (flet ((doc (kind) + (or (documentation symbol kind) :not-documented)) + (maybe-push (property value) + (when value + (setf result (list* property value result))))) + (maybe-push :variable (when (boundp symbol) (doc 'variable))) + (when (fboundp symbol) + (maybe-push + ;; Report WHEN etc. as macros, even though they may be + ;; implemented as special operators. + (if (macro-function symbol) :macro + (typecase (fdefinition symbol) + (generic-function :generic-function) + (function :function) + ;; (type-of 'progn) -> ext:special-operator + (t :special-operator))) + (doc 'function))) + (when (or (get symbol 'system::setf-function) ; e.g. #'(setf elt) + (get symbol 'system::setf-expander)); defsetf + (maybe-push :setf (doc 'setf))) + (when (or (get symbol 'system::type-symbol); cf. clisp/src/describe.lisp + (get symbol 'system::defstruct-description) + (get symbol 'system::deftype-expander)) + (maybe-push :type (doc 'type))) ; even for 'structure + (when (find-class symbol nil) + (maybe-push :class (doc 'type))) + ;; Let this code work compiled in images without FFI + (let ((types (load-time-value + (and (find-package "FFI") + (symbol-value + (find-symbol "*C-TYPE-TABLE*" "FFI")))))) + ;; Use ffi::*c-type-table* so as not to suffer the overhead of + ;; (ignore-errors (ffi:parse-c-type symbol)) for 99.9% of symbols + ;; which are not FFI type names. + (when (and types (nth-value 1 (gethash symbol types))) + ;; Maybe use (case (head (ffi:deparse-c-type))) + ;; to distinguish struct and union types? + (maybe-push :alien-type :not-documented))) + result))) + +(defimplementation describe-definition (symbol namespace) + (ecase namespace + (:variable (describe symbol)) + (:macro (describe (macro-function symbol))) + (:function (describe (symbol-function symbol))) + (:class (describe (find-class symbol))))) + +(defimplementation type-specifier-p (symbol) + (or (ignore-errors + (subtypep nil symbol)) + (not (eq (type-specifier-arglist symbol) :not-available)))) + +(defun fspec-pathname (spec) + (let ((path spec) + type + lines) + (when (consp path) + (psetq type (car path) + path (cadr path) + lines (cddr path))) + (when (and path + (member (pathname-type path) + custom:*compiled-file-types* :test #'equal)) + (setq path + (loop for suffix in custom:*source-file-types* + thereis (probe-file (make-pathname :defaults path + :type suffix))))) + (values path type lines))) + +(defun fspec-location (name fspec) + (multiple-value-bind (file type lines) + (fspec-pathname fspec) + (list (if type (list name type) name) + (cond (file + (multiple-value-bind (truename c) + (ignore-errors (truename file)) + (cond (truename + (make-location + (list :file (namestring truename)) + (if (consp lines) + (list* :line lines) + (list :function-name (string name))) + (when (consp type) + (list :snippet (format nil "~A" type))))) + (t (list :error (princ-to-string c)))))) + (t (list :error + (format nil "No source information available for: ~S" + fspec))))))) + +(defimplementation find-definitions (name) + (mapcar #'(lambda (e) (fspec-location name e)) + (documentation name 'sys::file))) + +(defun trim-whitespace (string) + (string-trim #(#\newline #\space #\tab) string)) + +(defvar *sldb-backtrace*) + +(defun sldb-backtrace () + "Return a list ((ADDRESS . DESCRIPTION) ...) of frames." + (let* ((modes '((:all-stack-elements 1) + (:all-frames 2) + (:only-lexical-frames 3) + (:only-eval-and-apply-frames 4) + (:only-apply-frames 5))) + (mode (cadr (assoc :all-stack-elements modes)))) + (do ((frames '()) + (last nil frame) + (frame (sys::the-frame) + (sys::frame-up 1 frame mode))) + ((eq frame last) (nreverse frames)) + (unless (boring-frame-p frame) + (push frame frames))))) + +(defimplementation call-with-debugging-environment (debugger-loop-fn) + (let* (;;(sys::*break-count* (1+ sys::*break-count*)) + ;;(sys::*driver* debugger-loop-fn) + ;;(sys::*fasoutput-stream* nil) + (*sldb-backtrace* + (let* ((f (sys::the-frame)) + (bt (sldb-backtrace)) + (rest (member f bt))) + (if rest (nthcdr 8 rest) bt)))) + (funcall debugger-loop-fn))) + +(defun nth-frame (index) + (nth index *sldb-backtrace*)) + +(defun boring-frame-p (frame) + (member (frame-type frame) '(stack-value bind-var bind-env + compiled-tagbody compiled-block))) + +(defun frame-to-string (frame) + (with-output-to-string (s) + (sys::describe-frame s frame))) + +(defun frame-type (frame) + ;; FIXME: should bind *print-length* etc. to small values. + (frame-string-type (frame-to-string frame))) + +;; FIXME: they changed the layout in 2.44 and not all patterns have +;; been updated. +(defvar *frame-prefixes* + '(("\\[[0-9]\\+\\] frame binding variables" bind-var) + ("<1> # # # " fun) + ("<2> " 2nd-frame) + )) + +(defun frame-string-type (string) + (cadr (assoc-if (lambda (pattern) (is-prefix-p pattern string)) + *frame-prefixes*))) + +(defimplementation compute-backtrace (start end) + (let* ((bt *sldb-backtrace*) + (len (length bt))) + (loop for f in (subseq bt start (min (or end len) len)) + collect f))) + +(defimplementation print-frame (frame stream) + (let* ((str (frame-to-string frame))) + (write-string (extract-frame-line str) + stream))) + +(defun extract-frame-line (frame-string) + (let ((s frame-string)) + (trim-whitespace + (case (frame-string-type s) + ((eval special-op) + (string-match "EVAL frame .*for form \\(.*\\)" s 1)) + (apply + (string-match "APPLY frame for call \\(.*\\)" s 1)) + ((compiled-fun sys-fun fun) + (extract-function-name s)) + (t s))))) + +(defun extract-function-name (string) + (let ((1st (car (split-frame-string string)))) + (or (string-match (format nil "^<1>[ ~%]*#<[-A-Za-z]* \\(.*\\)>") + 1st + 1) + (string-match (format nil "^<1>[ ~%]*\\(.*\\)") 1st 1) + 1st))) + +(defun split-frame-string (string) + (let ((rx (format nil "~%\\(~{~A~^\\|~}\\)" + (mapcar #'car *frame-prefixes*)))) + (loop for pos = 0 then (1+ (regexp:match-start match)) + for match = (regexp:match rx string :start pos) + if match collect (subseq string pos (regexp:match-start match)) + else collect (subseq string pos) + while match))) + +(defun string-match (pattern string n) + (let* ((match (nth-value n (regexp:match pattern string)))) + (if match (regexp:match-string string match)))) + +(defimplementation eval-in-frame (form frame-number) + (sys::eval-at (nth-frame frame-number) form)) + +(defimplementation frame-locals (frame-number) + (let ((frame (nth-frame frame-number))) + (loop for i below (%frame-count-vars frame) + collect (list :name (%frame-var-name frame i) + :value (%frame-var-value frame i) + :id 0)))) + +(defimplementation frame-var-value (frame var) + (%frame-var-value (nth-frame frame) var)) + +;;; Interpreter-Variablen-Environment has the shape +;;; NIL or #(v1 val1 ... vn valn NEXT-ENV). + +(defun %frame-count-vars (frame) + (cond ((sys::eval-frame-p frame) + (do ((venv (frame-venv frame) (next-venv venv)) + (count 0 (+ count (/ (1- (length venv)) 2)))) + ((not venv) count))) + ((member (frame-type frame) '(compiled-fun sys-fun fun special-op)) + (length (%parse-stack-values frame))) + (t 0))) + +(defun %frame-var-name (frame i) + (cond ((sys::eval-frame-p frame) + (nth-value 0 (venv-ref (frame-venv frame) i))) + (t (format nil "~D" i)))) + +(defun %frame-var-value (frame i) + (cond ((sys::eval-frame-p frame) + (let ((name (venv-ref (frame-venv frame) i))) + (multiple-value-bind (v c) (ignore-errors (sys::eval-at frame name)) + (if c + (format-sldb-condition c) + v)))) + ((member (frame-type frame) '(compiled-fun sys-fun fun special-op)) + (let ((str (nth i (%parse-stack-values frame)))) + (trim-whitespace (subseq str 2)))) + (t (break "Not implemented")))) + +(defun frame-venv (frame) + (let ((env (sys::eval-at frame '(sys::the-environment)))) + (svref env 0))) + +(defun next-venv (venv) (svref venv (1- (length venv)))) + +(defun venv-ref (env i) + "Reference the Ith binding in ENV. +Return two values: NAME and VALUE" + (let ((idx (* i 2))) + (if (< idx (1- (length env))) + (values (svref env idx) (svref env (1+ idx))) + (venv-ref (next-venv env) (- i (/ (1- (length env)) 2)))))) + +(defun %parse-stack-values (frame) + (labels ((next (fp) (sys::frame-down 1 fp 1)) + (parse (fp accu) + (let ((str (frame-to-string fp))) + (cond ((is-prefix-p "- " str) + (parse (next fp) (cons str accu))) + ((is-prefix-p "<1> " str) + ;;(when (eq (frame-type frame) 'compiled-fun) + ;; (pop accu)) + (dolist (str (cdr (split-frame-string str))) + (when (is-prefix-p "- " str) + (push str accu))) + (nreverse accu)) + (t (parse (next fp) accu)))))) + (parse (next frame) '()))) + +(defun is-prefix-p (regexp string) + (if (regexp:match (concatenate 'string "^" regexp) string) t)) + +(defimplementation return-from-frame (index form) + (sys::return-from-eval-frame (nth-frame index) form)) + +(defimplementation restart-frame (index) + (sys::redo-eval-frame (nth-frame index))) + +(defimplementation frame-source-location (index) + `(:error + ,(format nil "frame-source-location not implemented. (frame: ~A)" + (nth-frame index)))) + +;;;; Profiling + +(defimplementation profile (fname) + (eval `(swank-monitor:monitor ,fname))) ;monitor is a macro + +(defimplementation profiled-functions () + swank-monitor:*monitored-functions*) + +(defimplementation unprofile (fname) + (eval `(swank-monitor:unmonitor ,fname))) ;unmonitor is a macro + +(defimplementation unprofile-all () + (swank-monitor:unmonitor)) + +(defimplementation profile-report () + (swank-monitor:report-monitoring)) + +(defimplementation profile-reset () + (swank-monitor:reset-all-monitoring)) + +(defimplementation profile-package (package callers-p methods) + (declare (ignore callers-p methods)) + (swank-monitor:monitor-all package)) + +;;;; Handle compiler conditions (find out location of error etc.) + +(defmacro compile-file-frobbing-notes ((&rest args) &body body) + "Pass ARGS to COMPILE-FILE, send the compiler notes to +*STANDARD-INPUT* and frob them in BODY." + `(let ((*error-output* (make-string-output-stream)) + (*compile-verbose* t)) + (multiple-value-prog1 + (compile-file ,@args) + (handler-case + (with-input-from-string + (*standard-input* (get-output-stream-string *error-output*)) + ,@body) + (sys::simple-end-of-file () nil))))) + +(defvar *orig-c-warn* (symbol-function 'system::c-warn)) +(defvar *orig-c-style-warn* (symbol-function 'system::c-style-warn)) +(defvar *orig-c-error* (symbol-function 'system::c-error)) +(defvar *orig-c-report-problems* (symbol-function 'system::c-report-problems)) + +(defmacro dynamic-flet (names-functions &body body) + "(dynamic-flet ((NAME FUNCTION) ...) BODY ...) +Execute BODY with NAME's function slot set to FUNCTION." + `(ext:letf* ,(loop for (name function) in names-functions + collect `((symbol-function ',name) ,function)) + ,@body)) + +(defvar *buffer-name* nil) +(defvar *buffer-offset*) + +(defun compiler-note-location () + "Return the current compiler location." + (let ((lineno1 sys::*compile-file-lineno1*) + (lineno2 sys::*compile-file-lineno2*) + (file sys::*compile-file-truename*)) + (cond ((and file lineno1 lineno2) + (make-location (list ':file (namestring file)) + (list ':line lineno1))) + (*buffer-name* + (make-location (list ':buffer *buffer-name*) + (list ':offset *buffer-offset* 0))) + (t + (list :error "No error location available"))))) + +(defun signal-compiler-warning (cstring args severity orig-fn) + (signal 'compiler-condition + :severity severity + :message (apply #'format nil cstring args) + :location (compiler-note-location)) + (apply orig-fn cstring args)) + +(defun c-warn (cstring &rest args) + (signal-compiler-warning cstring args :warning *orig-c-warn*)) + +(defun c-style-warn (cstring &rest args) + (dynamic-flet ((sys::c-warn *orig-c-warn*)) + (signal-compiler-warning cstring args :style-warning *orig-c-style-warn*))) + +(defun c-error (&rest args) + (signal 'compiler-condition + :severity :error + :message (apply #'format nil + (if (= (length args) 3) + (cdr args) + args)) + :location (compiler-note-location)) + (apply *orig-c-error* args)) + +(defimplementation call-with-compilation-hooks (function) + (handler-bind ((warning #'handle-notification-condition)) + (dynamic-flet ((system::c-warn #'c-warn) + (system::c-style-warn #'c-style-warn) + (system::c-error #'c-error)) + (funcall function)))) + +(defun handle-notification-condition (condition) + "Handle a condition caused by a compiler warning." + (signal 'compiler-condition + :original-condition condition + :severity :warning + :message (princ-to-string condition) + :location (compiler-note-location))) + +(defimplementation swank-compile-file (input-file output-file + load-p external-format + &key policy) + (declare (ignore policy)) + (with-compilation-hooks () + (with-compilation-unit () + (multiple-value-bind (fasl-file warningsp failurep) + (compile-file input-file + :output-file output-file + :external-format external-format) + (values fasl-file warningsp + (or failurep + (and load-p + (not (load fasl-file))))))))) + +(defimplementation swank-compile-string (string &key buffer position filename + policy) + (declare (ignore filename policy)) + (with-compilation-hooks () + (let ((*buffer-name* buffer) + (*buffer-offset* position)) + (funcall (compile nil (read-from-string + (format nil "(~S () ~A)" 'lambda string)))) + t))) + +;;;; Portable XREF from the CMU AI repository. + +(setq pxref::*handle-package-forms* '(cl:in-package)) + +(defmacro defxref (name function) + `(defimplementation ,name (name) + (xref-results (,function name)))) + +(defxref who-calls pxref:list-callers) +(defxref who-references pxref:list-readers) +(defxref who-binds pxref:list-setters) +(defxref who-sets pxref:list-setters) +(defxref list-callers pxref:list-callers) +(defxref list-callees pxref:list-callees) + +(defun xref-results (symbols) + (let ((xrefs '())) + (dolist (symbol symbols) + (push (fspec-location symbol symbol) xrefs)) + xrefs)) + +(when (find-package :swank-loader) + (setf (symbol-function (intern "USER-INIT-FILE" :swank-loader)) + (lambda () + (let ((home (user-homedir-pathname))) + (and (ext:probe-directory home) + (probe-file (format nil "~A/.swank.lisp" + (namestring (truename home))))))))) + +;;; Don't set *debugger-hook* to nil on break. +(ext:without-package-lock () + (defun break (&optional (format-string "Break") &rest args) + (if (not sys::*use-clcs*) + (progn + (terpri *error-output*) + (apply #'format *error-output* + (concatenate 'string "*** - " format-string) + args) + (funcall ext:*break-driver* t)) + (let ((condition + (make-condition 'simple-condition + :format-control format-string + :format-arguments args)) + ;;(*debugger-hook* nil) + ;; Issue 91 + ) + (ext:with-restarts + ((continue + :report (lambda (stream) + (format stream (sys::text "Return from ~S loop") + 'break)) + ())) + (with-condition-restarts condition (list (find-restart 'continue)) + (invoke-debugger condition))))) + nil)) + +;;;; Inspecting + +(defmethod emacs-inspect ((o t)) + (let* ((*print-array* nil) (*print-pretty* t) + (*print-circle* t) (*print-escape* t) + (*print-lines* custom:*inspect-print-lines*) + (*print-level* custom:*inspect-print-level*) + (*print-length* custom:*inspect-print-length*) + (sys::*inspect-all* (make-array 10 :fill-pointer 0 :adjustable t)) + (tmp-pack (make-package (gensym "INSPECT-TMP-PACKAGE-"))) + (*package* tmp-pack) + (sys::*inspect-unbound-value* (intern "#" tmp-pack))) + (let ((inspection (sys::inspect-backend o))) + (append (list + (format nil "~S~% ~A~{~%~A~}~%" o + (sys::insp-title inspection) + (sys::insp-blurb inspection))) + (loop with count = (sys::insp-num-slots inspection) + for i below count + append (multiple-value-bind (value name) + (funcall (sys::insp-nth-slot inspection) + i) + `((:value ,name) " = " (:value ,value) + (:newline)))))))) + +(defimplementation quit-lisp () + #+lisp=cl (ext:quit) + #-lisp=cl (lisp:quit)) + + +(defimplementation preferred-communication-style () + nil) + +;;; FIXME +;;; +;;; Clisp 2.48 added experimental support for threads. Basically, you +;;; can use :SPAWN now, BUT: +;;; +;;; - there are problems with GC, and threads stuffed into weak +;;; hash-tables as is the case for *THREAD-PLIST-TABLE*. +;;; +;;; See test case at +;;; http://thread.gmane.org/gmane.lisp.clisp.devel/20429 +;;; +;;; Even though said to be fixed, it's not: +;;; +;;; http://thread.gmane.org/gmane.lisp.clisp.devel/20429/focus=20443 +;;; +;;; - The DYNAMIC-FLET above is an implementation technique that's +;;; probably not sustainable in light of threads. This got to be +;;; rewritten. +;;; +;;; TCR (2009-07-30) + +#+#.(cl:if (cl:find-package "MP") '(:and) '(:or)) +(progn + (defimplementation spawn (fn &key name) + (mp:make-thread fn :name name)) + + (defvar *thread-plist-table-lock* + (mp:make-mutex :name "THREAD-PLIST-TABLE-LOCK")) + + (defvar *thread-plist-table* (make-hash-table :weak :key) + "A hashtable mapping threads to a plist.") + + (defvar *thread-id-counter* 0) + + (defimplementation thread-id (thread) + (mp:with-mutex-lock (*thread-plist-table-lock*) + (or (getf (gethash thread *thread-plist-table*) 'thread-id) + (setf (getf (gethash thread *thread-plist-table*) 'thread-id) + (incf *thread-id-counter*))))) + + (defimplementation find-thread (id) + (find id (all-threads) + :key (lambda (thread) + (getf (gethash thread *thread-plist-table*) 'thread-id)))) + + (defimplementation thread-name (thread) + ;; To guard against returning #. + (princ-to-string (mp:thread-name thread))) + + (defimplementation thread-status (thread) + (if (thread-alive-p thread) + "RUNNING" + "STOPPED")) + + (defimplementation make-lock (&key name) + (mp:make-mutex :name name :recursive-p t)) + + (defimplementation call-with-lock-held (lock function) + (mp:with-mutex-lock (lock) + (funcall function))) + + (defimplementation current-thread () + (mp:current-thread)) + + (defimplementation all-threads () + (mp:list-threads)) + + (defimplementation interrupt-thread (thread fn) + (mp:thread-interrupt thread :function fn)) + + (defimplementation kill-thread (thread) + (mp:thread-interrupt thread :function t)) + + (defimplementation thread-alive-p (thread) + (mp:thread-active-p thread)) + + (defvar *mailboxes-lock* (make-lock :name "MAILBOXES-LOCK")) + (defvar *mailboxes* (list)) + + (defstruct (mailbox (:conc-name mailbox.)) + thread + (lock (make-lock :name "MAILBOX.LOCK")) + (waitqueue (mp:make-exemption :name "MAILBOX.WAITQUEUE")) + (queue '() :type list)) + + (defun mailbox (thread) + "Return THREAD's mailbox." + (mp:with-mutex-lock (*mailboxes-lock*) + (or (find thread *mailboxes* :key #'mailbox.thread) + (let ((mb (make-mailbox :thread thread))) + (push mb *mailboxes*) + mb)))) + + (defimplementation send (thread message) + (let* ((mbox (mailbox thread)) + (lock (mailbox.lock mbox))) + (mp:with-mutex-lock (lock) + (setf (mailbox.queue mbox) + (nconc (mailbox.queue mbox) (list message))) + (mp:exemption-broadcast (mailbox.waitqueue mbox))))) + + (defimplementation receive-if (test &optional timeout) + (let* ((mbox (mailbox (current-thread))) + (lock (mailbox.lock mbox))) + (assert (or (not timeout) (eq timeout t))) + (loop + (check-slime-interrupts) + (mp:with-mutex-lock (lock) + (let* ((q (mailbox.queue mbox)) + (tail (member-if test q))) + (when tail + (setf (mailbox.queue mbox) (nconc (ldiff q tail) (cdr tail))) + (return (car tail)))) + (when (eq timeout t) (return (values nil t))) + (mp:exemption-wait (mailbox.waitqueue mbox) lock :timeout 0.2)))))) + + +;;;; Weak hashtables + +(defimplementation make-weak-key-hash-table (&rest args) + (apply #'make-hash-table :weak :key args)) + +(defimplementation make-weak-value-hash-table (&rest args) + (apply #'make-hash-table :weak :value args)) + +(defimplementation save-image (filename &optional restart-function) + (let ((args `(,filename + ,@(if restart-function + `((:init-function ,restart-function)))))) + (apply #'ext:saveinitmem args))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/cmucl.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/cmucl.lisp new file mode 100644 index 0000000..12d4282 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/cmucl.lisp @@ -0,0 +1,2470 @@ +;;; -*- indent-tabs-mode: nil; outline-regexp: ";;;;+" -*- +;;; +;;; License: Public Domain +;;; +;;;; Introduction +;;; +;;; This is the CMUCL implementation of the `swank/backend' package. + +(defpackage swank/cmucl + (:use cl swank/backend swank/source-path-parser swank/source-file-cache + fwrappers)) + +(in-package swank/cmucl) + +(eval-when (:compile-toplevel :load-toplevel :execute) + + (let ((min-version #x20c)) + (assert (>= c:byte-fasl-file-version min-version) + () "This file requires CMUCL version ~x or newer" min-version)) + + (require 'gray-streams)) + + +(import-swank-mop-symbols :pcl '(:slot-definition-documentation)) + +(defun swank-mop:slot-definition-documentation (slot) + (documentation slot t)) + +;;; UTF8 + +(locally (declare (optimize (ext:inhibit-warnings 3))) + ;; Compile and load the utf8 format, if not already loaded. + (stream::find-external-format :utf-8)) + +(defimplementation string-to-utf8 (string) + (let ((ef (load-time-value (stream::find-external-format :utf-8) t))) + (stream:string-to-octets string :external-format ef))) + +(defimplementation utf8-to-string (octets) + (let ((ef (load-time-value (stream::find-external-format :utf-8) t))) + (stream:octets-to-string octets :external-format ef))) + + +;;;; TCP server +;;; +;;; In CMUCL we support all communication styles. By default we use +;;; `:SIGIO' because it is the most responsive, but it's somewhat +;;; dangerous: CMUCL is not in general "signal safe", and you don't +;;; know for sure what you'll be interrupting. Both `:FD-HANDLER' and +;;; `:SPAWN' are reasonable alternatives. + +(defimplementation preferred-communication-style () + :sigio) + +#-(or darwin mips) +(defimplementation create-socket (host port &key backlog) + (let* ((addr (resolve-hostname host)) + (addr (if (not (find-symbol "SOCKET-ERROR" :ext)) + (ext:htonl addr) + addr))) + (ext:create-inet-listener port :stream :reuse-address t :host addr + :backlog (or backlog 5)))) + +;; There seems to be a bug in create-inet-listener on Mac/OSX and Irix. +#+(or darwin mips) +(defimplementation create-socket (host port &key backlog) + (declare (ignore host)) + (ext:create-inet-listener port :stream :reuse-address t)) + +(defimplementation local-port (socket) + (nth-value 1 (ext::get-socket-host-and-port (socket-fd socket)))) + +(defimplementation close-socket (socket) + (let ((fd (socket-fd socket))) + (sys:invalidate-descriptor fd) + (ext:close-socket fd))) + +(defimplementation accept-connection (socket &key + external-format buffering timeout) + (declare (ignore timeout)) + (make-socket-io-stream (ext:accept-tcp-connection socket) + (ecase buffering + ((t) :full) + (:line :line) + ((nil) :none)) + external-format)) + +;;;;; Sockets + +(defimplementation socket-fd (socket) + "Return the filedescriptor for the socket represented by SOCKET." + (etypecase socket + (fixnum socket) + (sys:fd-stream (sys:fd-stream-fd socket)))) + +(defun resolve-hostname (hostname) + "Return the IP address of HOSTNAME as an integer (in host byte-order)." + (let ((hostent (ext:lookup-host-entry hostname))) + (car (ext:host-entry-addr-list hostent)))) + +(defvar *external-format-to-coding-system* + '((:iso-8859-1 "iso-latin-1-unix") + #+unicode + (:utf-8 "utf-8-unix"))) + +(defimplementation find-external-format (coding-system) + (car (rassoc-if (lambda (x) (member coding-system x :test #'equal)) + *external-format-to-coding-system*))) + +(defun make-socket-io-stream (fd buffering external-format) + "Create a new input/output fd-stream for FD." + (cond (external-format + (sys:make-fd-stream fd :input t :output t + :element-type 'character + :buffering buffering + :external-format external-format)) + (t + (sys:make-fd-stream fd :input t :output t + :element-type '(unsigned-byte 8) + :buffering buffering)))) + +(defimplementation make-fd-stream (fd external-format) + (make-socket-io-stream fd :full external-format)) + +(defimplementation dup (fd) + (multiple-value-bind (clone error) (unix:unix-dup fd) + (unless clone (error "dup failed: ~a" (unix:get-unix-error-msg error))) + clone)) + +(defimplementation command-line-args () + ext:*command-line-strings*) + +(defimplementation exec-image (image-file args) + (multiple-value-bind (ok error) + (unix:unix-execve (car (command-line-args)) + (list* (car (command-line-args)) + "-core" image-file + "-noinit" + args)) + (error "~a" (unix:get-unix-error-msg error)) + ok)) + +;;;;; Signal-driven I/O + +(defimplementation install-sigint-handler (function) + (sys:enable-interrupt :sigint (lambda (signal code scp) + (declare (ignore signal code scp)) + (funcall function)))) + +(defvar *sigio-handlers* '() + "List of (key . function) pairs. +All functions are called on SIGIO, and the key is used for removing +specific functions.") + +(defun reset-sigio-handlers () (setq *sigio-handlers* '())) +;; All file handlers are invalid afer reload. +(pushnew 'reset-sigio-handlers ext:*after-save-initializations*) + +(defun set-sigio-handler () + (sys:enable-interrupt :sigio (lambda (signal code scp) + (sigio-handler signal code scp)))) + +(defun sigio-handler (signal code scp) + (declare (ignore signal code scp)) + (mapc #'funcall (mapcar #'cdr *sigio-handlers*))) + +(defun fcntl (fd command arg) + "fcntl(2) - manipulate a file descriptor." + (multiple-value-bind (ok error) (unix:unix-fcntl fd command arg) + (cond (ok) + (t (error "fcntl: ~A" (unix:get-unix-error-msg error)))))) + +(defimplementation add-sigio-handler (socket fn) + (set-sigio-handler) + (let ((fd (socket-fd socket))) + (fcntl fd unix:f-setown (unix:unix-getpid)) + (let ((old-flags (fcntl fd unix:f-getfl 0))) + (fcntl fd unix:f-setfl (logior old-flags unix:fasync))) + (assert (not (assoc fd *sigio-handlers*))) + (push (cons fd fn) *sigio-handlers*))) + +(defimplementation remove-sigio-handlers (socket) + (let ((fd (socket-fd socket))) + (when (assoc fd *sigio-handlers*) + (setf *sigio-handlers* (remove fd *sigio-handlers* :key #'car)) + (let ((old-flags (fcntl fd unix:f-getfl 0))) + (fcntl fd unix:f-setfl (logandc2 old-flags unix:fasync))) + (sys:invalidate-descriptor fd)) + (assert (not (assoc fd *sigio-handlers*))) + (when (null *sigio-handlers*) + (sys:default-interrupt :sigio)))) + +;;;;; SERVE-EVENT + +(defimplementation add-fd-handler (socket fn) + (let ((fd (socket-fd socket))) + (sys:add-fd-handler fd :input (lambda (_) _ (funcall fn))))) + +(defimplementation remove-fd-handlers (socket) + (sys:invalidate-descriptor (socket-fd socket))) + +(defimplementation wait-for-input (streams &optional timeout) + (assert (member timeout '(nil t))) + (loop + (let ((ready (remove-if-not #'listen streams))) + (when ready (return ready))) + (when timeout (return nil)) + (multiple-value-bind (in out) (make-pipe) + (let* ((f (constantly t)) + (handlers (loop for s in (cons in (mapcar #'to-fd-stream streams)) + collect (add-one-shot-handler s f)))) + (unwind-protect + (let ((*interrupt-queued-handler* (lambda () + (write-char #\! out)))) + (when (check-slime-interrupts) (return :interrupt)) + (sys:serve-event)) + (mapc #'sys:remove-fd-handler handlers) + (close in) + (close out)))))) + +(defun to-fd-stream (stream) + (etypecase stream + (sys:fd-stream stream) + (synonym-stream + (to-fd-stream + (symbol-value (synonym-stream-symbol stream)))) + (two-way-stream + (to-fd-stream (two-way-stream-input-stream stream))))) + +(defun add-one-shot-handler (stream function) + (let (handler) + (setq handler (sys:add-fd-handler (sys:fd-stream-fd stream) :input + (lambda (fd) + (declare (ignore fd)) + (sys:remove-fd-handler handler) + (funcall function stream)))))) + +(defun make-pipe () + (multiple-value-bind (in out) (unix:unix-pipe) + (values (sys:make-fd-stream in :input t :buffering :none) + (sys:make-fd-stream out :output t :buffering :none)))) + + +;;;; Stream handling + +(defimplementation gray-package-name () + "EXT") + + +;;;; Compilation Commands + +(defvar *previous-compiler-condition* nil + "Used to detect duplicates.") + +(defvar *previous-context* nil + "Previous compiler error context.") + +(defvar *buffer-name* nil + "The name of the Emacs buffer we are compiling from. +NIL if we aren't compiling from a buffer.") + +(defvar *buffer-start-position* nil) +(defvar *buffer-substring* nil) + +(defimplementation call-with-compilation-hooks (function) + (let ((*previous-compiler-condition* nil) + (*previous-context* nil) + (*print-readably* nil)) + (handler-bind ((c::compiler-error #'handle-notification-condition) + (c::style-warning #'handle-notification-condition) + (c::warning #'handle-notification-condition)) + (funcall function)))) + +(defimplementation swank-compile-file (input-file output-file + load-p external-format + &key policy) + (declare (ignore policy)) + (clear-xref-info input-file) + (with-compilation-hooks () + (let ((*buffer-name* nil) + (ext:*ignore-extra-close-parentheses* nil)) + (multiple-value-bind (output-file warnings-p failure-p) + (compile-file input-file :output-file output-file + :external-format external-format) + (values output-file warnings-p + (or failure-p + (when load-p + ;; Cache the latest source file for definition-finding. + (source-cache-get input-file + (file-write-date input-file)) + (not (load output-file))))))))) + +(defimplementation swank-compile-string (string &key buffer position filename + policy) + (declare (ignore filename policy)) + (with-compilation-hooks () + (let ((*buffer-name* buffer) + (*buffer-start-position* position) + (*buffer-substring* string) + (source-info (list :emacs-buffer buffer + :emacs-buffer-offset position + :emacs-buffer-string string))) + (with-input-from-string (stream string) + (let ((failurep (ext:compile-from-stream stream :source-info + source-info))) + (not failurep)))))) + + +;;;;; Trapping notes +;;; +;;; We intercept conditions from the compiler and resignal them as +;;; `SWANK:COMPILER-CONDITION's. + +(defun handle-notification-condition (condition) + "Handle a condition caused by a compiler warning." + (unless (eq condition *previous-compiler-condition*) + (let ((context (c::find-error-context nil))) + (setq *previous-compiler-condition* condition) + (setq *previous-context* context) + (signal-compiler-condition condition context)))) + +(defun signal-compiler-condition (condition context) + (signal 'compiler-condition + :original-condition condition + :severity (severity-for-emacs condition) + :message (compiler-condition-message condition) + :source-context (compiler-error-context context) + :location (if (read-error-p condition) + (read-error-location condition) + (compiler-note-location context)))) + +(defun severity-for-emacs (condition) + "Return the severity of CONDITION." + (etypecase condition + ((satisfies read-error-p) :read-error) + (c::compiler-error :error) + (c::style-warning :note) + (c::warning :warning))) + +(defun read-error-p (condition) + (eq (type-of condition) 'c::compiler-read-error)) + +(defun compiler-condition-message (condition) + "Briefly describe a compiler error for Emacs. +When Emacs presents the message it already has the source popped up +and the source form highlighted. This makes much of the information in +the error-context redundant." + (princ-to-string condition)) + +(defun compiler-error-context (error-context) + "Describe context information for Emacs." + (declare (type (or c::compiler-error-context null) error-context)) + (multiple-value-bind (enclosing source) + (if error-context + (values (c::compiler-error-context-enclosing-source error-context) + (c::compiler-error-context-source error-context))) + (if (or enclosing source) + (format nil "~@[--> ~{~<~%--> ~1:;~A ~>~}~%~]~ + ~@[==>~{~&~A~}~]" + enclosing source)))) + +(defun read-error-location (condition) + (let* ((finfo (car (c::source-info-current-file c::*source-info*))) + (file (c::file-info-name finfo)) + (pos (c::compiler-read-error-position condition))) + (cond ((and (eq file :stream) *buffer-name*) + (make-location (list :buffer *buffer-name*) + (list :offset *buffer-start-position* pos))) + ((and (pathnamep file) (not *buffer-name*)) + (make-location (list :file (unix-truename file)) + (list :position (1+ pos)))) + (t (break))))) + +(defun compiler-note-location (context) + "Derive the location of a complier message from its context. +Return a `location' record, or (:error REASON) on failure." + (if (null context) + (note-error-location) + (with-struct (c::compiler-error-context- file-name + original-source + original-source-path) context + (or (locate-compiler-note file-name original-source + (reverse original-source-path)) + (note-error-location))))) + +(defun note-error-location () + "Pseudo-location for notes that can't be located." + (cond (*compile-file-truename* + (make-location (list :file (unix-truename *compile-file-truename*)) + (list :eof))) + (*buffer-name* + (make-location (list :buffer *buffer-name*) + (list :position *buffer-start-position*))) + (t (list :error "No error location available.")))) + +(defun locate-compiler-note (file source source-path) + (cond ((and (eq file :stream) *buffer-name*) + ;; Compiling from a buffer + (make-location (list :buffer *buffer-name*) + (list :offset *buffer-start-position* + (source-path-string-position + source-path *buffer-substring*)))) + ((and (pathnamep file) (null *buffer-name*)) + ;; Compiling from a file + (make-location (list :file (unix-truename file)) + (list :position (1+ (source-path-file-position + source-path file))))) + ((and (eq file :lisp) (stringp source)) + ;; No location known, but we have the source form. + ;; XXX How is this case triggered? -luke (16/May/2004) + ;; This can happen if the compiler needs to expand a macro + ;; but the macro-expander is not yet compiled. Calling the + ;; (interpreted) macro-expander triggers IR1 conversion of + ;; the lambda expression for the expander and invokes the + ;; compiler recursively. + (make-location (list :source-form source) + (list :position 1))))) + +(defun unix-truename (pathname) + (ext:unix-namestring (truename pathname))) + + +;;;; XREF +;;; +;;; Cross-reference support is based on the standard CMUCL `XREF' +;;; package. This package has some caveats: XREF information is +;;; recorded during compilation and not preserved in fasl files, and +;;; XREF recording is disabled by default. Redefining functions can +;;; also cause duplicate references to accumulate, but +;;; `swank-compile-file' will automatically clear out any old records +;;; from the same filename. +;;; +;;; To enable XREF recording, set `c:*record-xref-info*' to true. To +;;; clear out the XREF database call `xref:init-xref-database'. + +(defmacro defxref (name function) + `(defimplementation ,name (name) + (xref-results (,function name)))) + +(defxref who-calls xref:who-calls) +(defxref who-references xref:who-references) +(defxref who-binds xref:who-binds) +(defxref who-sets xref:who-sets) + +;;; More types of XREF information were added since 18e: +;;; + +(defxref who-macroexpands xref:who-macroexpands) +;; XXX +(defimplementation who-specializes (symbol) + (let* ((methods (xref::who-specializes (find-class symbol))) + (locations (mapcar #'method-location methods))) + (mapcar #'list methods locations))) + +(defun xref-results (contexts) + (mapcar (lambda (xref) + (list (xref:xref-context-name xref) + (resolve-xref-location xref))) + contexts)) + +(defun resolve-xref-location (xref) + (let ((name (xref:xref-context-name xref)) + (file (xref:xref-context-file xref)) + (source-path (xref:xref-context-source-path xref))) + (cond ((and file source-path) + (let ((position (source-path-file-position source-path file))) + (make-location (list :file (unix-truename file)) + (list :position (1+ position))))) + (file + (make-location (list :file (unix-truename file)) + (list :function-name (string name)))) + (t + `(:error ,(format nil "Unknown source location: ~S ~S ~S " + name file source-path)))))) + +(defun clear-xref-info (namestring) + "Clear XREF notes pertaining to NAMESTRING. +This is a workaround for a CMUCL bug: XREF records are cumulative." + (when c:*record-xref-info* + (let ((filename (truename namestring))) + (dolist (db (list xref::*who-calls* + xref::*who-is-called* + xref::*who-macroexpands* + xref::*who-references* + xref::*who-binds* + xref::*who-sets*)) + (maphash (lambda (target contexts) + ;; XXX update during traversal? + (setf (gethash target db) + (delete filename contexts + :key #'xref:xref-context-file + :test #'equalp))) + db))))) + + +;;;; Find callers and callees +;;; +;;; Find callers and callees by looking at the constant pool of +;;; compiled code objects. We assume every fdefn object in the +;;; constant pool corresponds to a call to that function. A better +;;; strategy would be to use the disassembler to find actual +;;; call-sites. + +(labels ((make-stack () (make-array 100 :fill-pointer 0 :adjustable t)) + (map-cpool (code fun) + (declare (type kernel:code-component code) (type function fun)) + (loop for i from vm:code-constants-offset + below (kernel:get-header-data code) + do (funcall fun (kernel:code-header-ref code i)))) + + (callees (fun) + (let ((callees (make-stack))) + (map-cpool (vm::find-code-object fun) + (lambda (o) + (when (kernel:fdefn-p o) + (vector-push-extend (kernel:fdefn-function o) + callees)))) + (coerce callees 'list))) + + (callers (fun) + (declare (function fun)) + (let ((callers (make-stack))) + (ext:gc :full t) + ;; scan :dynamic first to avoid the need for even more gcing + (dolist (space '(:dynamic :read-only :static)) + (vm::map-allocated-objects + (lambda (obj header size) + (declare (type fixnum header) (ignore size)) + (when (= vm:code-header-type header) + (map-cpool obj + (lambda (c) + (when (and (kernel:fdefn-p c) + (eq (kernel:fdefn-function c) fun)) + (vector-push-extend obj callers)))))) + space) + (ext:gc)) + (coerce callers 'list))) + + (entry-points (code) + (loop for entry = (kernel:%code-entry-points code) + then (kernel::%function-next entry) + while entry + collect entry)) + + (guess-main-entry-point (entry-points) + (or (find-if (lambda (fun) + (ext:valid-function-name-p + (kernel:%function-name fun))) + entry-points) + (car entry-points))) + + (fun-dspec (fun) + (list (kernel:%function-name fun) (function-location fun))) + + (code-dspec (code) + (let ((eps (entry-points code)) + (di (kernel:%code-debug-info code))) + (cond (eps (fun-dspec (guess-main-entry-point eps))) + (di (list (c::debug-info-name di) + (debug-info-function-name-location di))) + (t (list (princ-to-string code) + `(:error "No src-loc available"))))))) + (declare (inline map-cpool)) + + (defimplementation list-callers (symbol) + (mapcar #'code-dspec (callers (coerce symbol 'function) ))) + + (defimplementation list-callees (symbol) + (mapcar #'fun-dspec (callees symbol)))) + +(defun test-list-callers (count) + (let ((funsyms '())) + (do-all-symbols (s) + (when (and (fboundp s) + (functionp (symbol-function s)) + (not (macro-function s)) + (not (special-operator-p s))) + (push s funsyms))) + (let ((len (length funsyms))) + (dotimes (i count) + (let ((sym (nth (random len) funsyms))) + (format t "~s -> ~a~%" sym (mapcar #'car (list-callers sym)))))))) + +;; (test-list-callers 100) + + +;;;; Resolving source locations +;;; +;;; Our mission here is to "resolve" references to code locations into +;;; actual file/buffer names and character positions. The references +;;; we work from come out of the compiler's statically-generated debug +;;; information, such as `code-location''s and `debug-source''s. For +;;; more details, see the "Debugger Programmer's Interface" section of +;;; the CMUCL manual. +;;; +;;; The first step is usually to find the corresponding "source-path" +;;; for the location. Once we have the source-path we can pull up the +;;; source file and `READ' our way through to the right position. The +;;; main source-code groveling work is done in +;;; `source-path-parser.lisp'. + +(defvar *debug-definition-finding* nil + "When true don't handle errors while looking for definitions. +This is useful when debugging the definition-finding code.") + +(defmacro safe-definition-finding (&body body) + "Execute BODY and return the source-location it returns. +If an error occurs and `*debug-definition-finding*' is false, then +return an error pseudo-location. + +The second return value is NIL if no error occurs, otherwise it is the +condition object." + `(flet ((body () ,@body)) + (if *debug-definition-finding* + (body) + (handler-case (values (progn ,@body) nil) + (error (c) (values `(:error ,(trim-whitespace (princ-to-string c))) + c)))))) + +(defun trim-whitespace (string) + (string-trim #(#\newline #\space #\tab) string)) + +(defun code-location-source-location (code-location) + "Safe wrapper around `code-location-from-source-location'." + (safe-definition-finding + (source-location-from-code-location code-location))) + +(defun source-location-from-code-location (code-location) + "Return the source location for CODE-LOCATION." + (let ((debug-fun (di:code-location-debug-function code-location))) + (when (di::bogus-debug-function-p debug-fun) + ;; Those lousy cheapskates! They've put in a bogus debug source + ;; because the code was compiled at a low debug setting. + (error "Bogus debug function: ~A" debug-fun))) + (let* ((debug-source (di:code-location-debug-source code-location)) + (from (di:debug-source-from debug-source)) + (name (di:debug-source-name debug-source))) + (ecase from + (:file + (location-in-file name code-location debug-source)) + (:stream + (location-in-stream code-location debug-source)) + (:lisp + ;; The location comes from a form passed to `compile'. + ;; The best we can do is return the form itself for printing. + (make-location + (list :source-form (with-output-to-string (*standard-output*) + (debug::print-code-location-source-form + code-location 100 t))) + (list :position 1)))))) + +(defun location-in-file (filename code-location debug-source) + "Resolve the source location for CODE-LOCATION in FILENAME." + (let* ((code-date (di:debug-source-created debug-source)) + (root-number (di:debug-source-root-number debug-source)) + (source-code (get-source-code filename code-date))) + (with-input-from-string (s source-code) + (make-location (list :file (unix-truename filename)) + (list :position (1+ (code-location-stream-position + code-location s root-number))) + `(:snippet ,(read-snippet s)))))) + +(defun location-in-stream (code-location debug-source) + "Resolve the source location for a CODE-LOCATION from a stream. +This only succeeds if the code was compiled from an Emacs buffer." + (unless (debug-source-info-from-emacs-buffer-p debug-source) + (error "The code is compiled from a non-SLIME stream.")) + (let* ((info (c::debug-source-info debug-source)) + (string (getf info :emacs-buffer-string)) + (position (code-location-string-offset + code-location + string))) + (make-location + (list :buffer (getf info :emacs-buffer)) + (list :offset (getf info :emacs-buffer-offset) position) + (list :snippet (with-input-from-string (s string) + (file-position s position) + (read-snippet s)))))) + +;;;;; Function-name locations +;;; +(defun debug-info-function-name-location (debug-info) + "Return a function-name source-location for DEBUG-INFO. +Function-name source-locations are a fallback for when precise +positions aren't available." + (with-struct (c::debug-info- (fname name) source) debug-info + (with-struct (c::debug-source- info from name) (car source) + (ecase from + (:file + (make-location (list :file (namestring (truename name))) + (list :function-name (string fname)))) + (:stream + (assert (debug-source-info-from-emacs-buffer-p (car source))) + (make-location (list :buffer (getf info :emacs-buffer)) + (list :function-name (string fname)))) + (:lisp + (make-location (list :source-form (princ-to-string (aref name 0))) + (list :position 1))))))) + +(defun debug-source-info-from-emacs-buffer-p (debug-source) + "Does the `info' slot of DEBUG-SOURCE contain an Emacs buffer location? +This is true for functions that were compiled directly from buffers." + (info-from-emacs-buffer-p (c::debug-source-info debug-source))) + +(defun info-from-emacs-buffer-p (info) + (and info + (consp info) + (eq :emacs-buffer (car info)))) + + +;;;;; Groveling source-code for positions + +(defun code-location-stream-position (code-location stream root) + "Return the byte offset of CODE-LOCATION in STREAM. Extract the +toplevel-form-number and form-number from CODE-LOCATION and use that +to find the position of the corresponding form. + +Finish with STREAM positioned at the start of the code location." + (let* ((location (debug::maybe-block-start-location code-location)) + (tlf-offset (- (di:code-location-top-level-form-offset location) + root)) + (form-number (di:code-location-form-number location))) + (let ((pos (form-number-stream-position tlf-offset form-number stream))) + (file-position stream pos) + pos))) + +(defun form-number-stream-position (tlf-number form-number stream) + "Return the starting character position of a form in STREAM. +TLF-NUMBER is the top-level-form number. +FORM-NUMBER is an index into a source-path table for the TLF." + (multiple-value-bind (tlf position-map) (read-source-form tlf-number stream) + (let* ((path-table (di:form-number-translations tlf 0)) + (source-path + (if (<= (length path-table) form-number) ; source out of sync? + (list 0) ; should probably signal a condition + (reverse (cdr (aref path-table form-number)))))) + (source-path-source-position source-path tlf position-map)))) + +(defun code-location-string-offset (code-location string) + "Return the byte offset of CODE-LOCATION in STRING. +See CODE-LOCATION-STREAM-POSITION." + (with-input-from-string (s string) + (code-location-stream-position code-location s 0))) + + +;;;; Finding definitions + +;;; There are a great many different types of definition for us to +;;; find. We search for definitions of every kind and return them in a +;;; list. + +(defimplementation find-definitions (name) + (append (function-definitions name) + (setf-definitions name) + (variable-definitions name) + (class-definitions name) + (type-definitions name) + (compiler-macro-definitions name) + (source-transform-definitions name) + (function-info-definitions name) + (ir1-translator-definitions name) + (template-definitions name) + (primitive-definitions name) + (vm-support-routine-definitions name) + )) + +;;;;; Functions, macros, generic functions, methods +;;; +;;; We make extensive use of the compile-time debug information that +;;; CMUCL records, in particular "debug functions" and "code +;;; locations." Refer to the "Debugger Programmer's Interface" section +;;; of the CMUCL manual for more details. + +(defun function-definitions (name) + "Return definitions for NAME in the \"function namespace\", i.e., +regular functions, generic functions, methods and macros. +NAME can any valid function name (e.g, (setf car))." + (let ((macro? (and (symbolp name) (macro-function name))) + (function? (and (ext:valid-function-name-p name) + (ext:info :function :definition name) + (if (symbolp name) (fboundp name) t)))) + (cond (macro? + (list `((defmacro ,name) + ,(function-location (macro-function name))))) + (function? + (let ((function (fdefinition name))) + (if (genericp function) + (gf-definitions name function) + (list (list `(function ,name) + (function-location function))))))))) + +;;;;;; Ordinary (non-generic/macro/special) functions +;;; +;;; First we test if FUNCTION is a closure created by defstruct, and +;;; if so extract the defstruct-description (`dd') from the closure +;;; and find the constructor for the struct. Defstruct creates a +;;; defun for the default constructor and we use that as an +;;; approximation to the source location of the defstruct. +;;; +;;; For an ordinary function we return the source location of the +;;; first code-location we find. +;;; +(defun function-location (function) + "Return the source location for FUNCTION." + (cond ((struct-closure-p function) + (struct-closure-location function)) + ((c::byte-function-or-closure-p function) + (byte-function-location function)) + (t + (compiled-function-location function)))) + +(defun compiled-function-location (function) + "Return the location of a regular compiled function." + (multiple-value-bind (code-location error) + (safe-definition-finding (function-first-code-location function)) + (cond (error (list :error (princ-to-string error))) + (t (code-location-source-location code-location))))) + +(defun function-first-code-location (function) + "Return the first code-location we can find for FUNCTION." + (and (function-has-debug-function-p function) + (di:debug-function-start-location + (di:function-debug-function function)))) + +(defun function-has-debug-function-p (function) + (di:function-debug-function function)) + +(defun function-code-object= (closure function) + (and (eq (vm::find-code-object closure) + (vm::find-code-object function)) + (not (eq closure function)))) + +(defun byte-function-location (fun) + "Return the location of the byte-compiled function FUN." + (etypecase fun + ((or c::hairy-byte-function c::simple-byte-function) + (let* ((di (kernel:%code-debug-info (c::byte-function-component fun)))) + (if di + (debug-info-function-name-location di) + `(:error + ,(format nil "Byte-function without debug-info: ~a" fun))))) + (c::byte-closure + (byte-function-location (c::byte-closure-function fun))))) + +;;; Here we deal with structure accessors. Note that `dd' is a +;;; "defstruct descriptor" structure in CMUCL. A `dd' describes a +;;; `defstruct''d structure. + +(defun struct-closure-p (function) + "Is FUNCTION a closure created by defstruct?" + (or (function-code-object= function #'kernel::structure-slot-accessor) + (function-code-object= function #'kernel::structure-slot-setter) + (function-code-object= function #'kernel::%defstruct))) + +(defun struct-closure-location (function) + "Return the location of the structure that FUNCTION belongs to." + (assert (struct-closure-p function)) + (safe-definition-finding + (dd-location (struct-closure-dd function)))) + +(defun struct-closure-dd (function) + "Return the defstruct-definition (dd) of FUNCTION." + (assert (= (kernel:get-type function) vm:closure-header-type)) + (flet ((find-layout (function) + (sys:find-if-in-closure + (lambda (x) + (let ((value (if (di::indirect-value-cell-p x) + (c:value-cell-ref x) + x))) + (when (kernel::layout-p value) + (return-from find-layout value)))) + function))) + (kernel:layout-info (find-layout function)))) + +(defun dd-location (dd) + "Return the location of a `defstruct'." + (let ((ctor (struct-constructor dd))) + (cond (ctor + (function-location (coerce ctor 'function))) + (t + (let ((name (kernel:dd-name dd))) + (multiple-value-bind (location foundp) + (ext:info :source-location :defvar name) + (cond (foundp + (resolve-source-location location)) + (t + (error "No location for defstruct: ~S" name))))))))) + +(defun struct-constructor (dd) + "Return the name of the constructor from a defstruct definition." + (let* ((constructor (or (kernel:dd-default-constructor dd) + (car (kernel::dd-constructors dd))))) + (if (consp constructor) (car constructor) constructor))) + +;;;;;; Generic functions and methods + +(defun gf-definitions (name function) + "Return the definitions of a generic function and its methods." + (cons (list `(defgeneric ,name) (gf-location function)) + (gf-method-definitions function))) + +(defun gf-location (gf) + "Return the location of the generic function GF." + (definition-source-location gf (pcl::generic-function-name gf))) + +(defun gf-method-definitions (gf) + "Return the locations of all methods of the generic function GF." + (mapcar #'method-definition (pcl::generic-function-methods gf))) + +(defun method-definition (method) + (list (method-dspec method) + (method-location method))) + +(defun method-dspec (method) + "Return a human-readable \"definition specifier\" for METHOD." + (let* ((gf (pcl:method-generic-function method)) + (name (pcl:generic-function-name gf)) + (specializers (pcl:method-specializers method)) + (qualifiers (pcl:method-qualifiers method))) + `(method ,name ,@qualifiers ,(pcl::unparse-specializers specializers)))) + +(defun method-location (method) + (typecase method + (pcl::standard-accessor-method + (definition-source-location + (cond ((pcl::definition-source method) + method) + (t + (pcl::slot-definition-class + (pcl::accessor-method-slot-definition method)))) + (pcl::accessor-method-slot-name method))) + (t + (function-location (or (pcl::method-fast-function method) + (pcl:method-function method)))))) + +(defun genericp (fn) + (typep fn 'generic-function)) + +;;;;;; Types and classes + +(defun type-definitions (name) + "Return `deftype' locations for type NAME." + (maybe-make-definition (ext:info :type :expander name) 'deftype name)) + +(defun maybe-make-definition (function kind name) + "If FUNCTION is non-nil then return its definition location." + (if function + (list (list `(,kind ,name) (function-location function))))) + +(defun class-definitions (name) + "Return the definition locations for the class called NAME." + (if (symbolp name) + (let ((class (kernel::find-class name nil))) + (etypecase class + (null '()) + (kernel::structure-class + (list (list `(defstruct ,name) (dd-location (find-dd name))))) + #+(or) + (conditions::condition-class + (list (list `(define-condition ,name) + (condition-class-location class)))) + (kernel::standard-class + (list (list `(defclass ,name) + (pcl-class-location (find-class name))))) + ((or kernel::built-in-class + conditions::condition-class + kernel:funcallable-structure-class) + (list (list `(class ,name) (class-location class)))))))) + +(defun pcl-class-location (class) + "Return the `defclass' location for CLASS." + (definition-source-location class (pcl:class-name class))) + +;; FIXME: eval used for backward compatibility. +(defun class-location (class) + (declare (type kernel::class class)) + (let ((name (kernel:%class-name class))) + (multiple-value-bind (loc found?) + (let ((x (ignore-errors + (multiple-value-list + (eval `(ext:info :source-location :class ',name)))))) + (values-list x)) + (cond (found? (resolve-source-location loc)) + (`(:error + ,(format nil "No location recorded for class: ~S" name))))))) + +(defun find-dd (name) + "Find the defstruct-definition by the name of its structure-class." + (let ((layout (ext:info :type :compiler-layout name))) + (if layout + (kernel:layout-info layout)))) + +(defun condition-class-location (class) + (let ((slots (conditions::condition-class-slots class)) + (name (conditions::condition-class-name class))) + (cond ((null slots) + `(:error ,(format nil "No location info for condition: ~A" name))) + (t + ;; Find the class via one of its slot-reader methods. + (let* ((slot (first slots)) + (gf (fdefinition + (first (conditions::condition-slot-readers slot))))) + (method-location + (first + (pcl:compute-applicable-methods-using-classes + gf (list (find-class name)))))))))) + +(defun make-name-in-file-location (file string) + (multiple-value-bind (filename c) + (ignore-errors + (unix-truename (merge-pathnames (make-pathname :type "lisp") + file))) + (cond (filename (make-location `(:file ,filename) + `(:function-name ,(string string)))) + (t (list :error (princ-to-string c)))))) + +(defun source-location-form-numbers (location) + (c::decode-form-numbers (c::form-numbers-form-numbers location))) + +(defun source-location-tlf-number (location) + (nth-value 0 (source-location-form-numbers location))) + +(defun source-location-form-number (location) + (nth-value 1 (source-location-form-numbers location))) + +(defun resolve-file-source-location (location) + (let ((filename (c::file-source-location-pathname location)) + (tlf-number (source-location-tlf-number location)) + (form-number (source-location-form-number location))) + (with-open-file (s filename) + (let ((pos (form-number-stream-position tlf-number form-number s))) + (make-location `(:file ,(unix-truename filename)) + `(:position ,(1+ pos))))))) + +(defun resolve-stream-source-location (location) + (let ((info (c::stream-source-location-user-info location)) + (tlf-number (source-location-tlf-number location)) + (form-number (source-location-form-number location))) + ;; XXX duplication in frame-source-location + (assert (info-from-emacs-buffer-p info)) + (destructuring-bind (&key emacs-buffer emacs-buffer-string + emacs-buffer-offset) info + (with-input-from-string (s emacs-buffer-string) + (let ((pos (form-number-stream-position tlf-number form-number s))) + (make-location `(:buffer ,emacs-buffer) + `(:offset ,emacs-buffer-offset ,pos))))))) + +;; XXX predicates for 18e backward compatibilty. Remove them when +;; we're 19a only. +(defun file-source-location-p (object) + (when (fboundp 'c::file-source-location-p) + (c::file-source-location-p object))) + +(defun stream-source-location-p (object) + (when (fboundp 'c::stream-source-location-p) + (c::stream-source-location-p object))) + +(defun source-location-p (object) + (or (file-source-location-p object) + (stream-source-location-p object))) + +(defun resolve-source-location (location) + (etypecase location + ((satisfies file-source-location-p) + (resolve-file-source-location location)) + ((satisfies stream-source-location-p) + (resolve-stream-source-location location)))) + +(defun definition-source-location (object name) + (let ((source (pcl::definition-source object))) + (etypecase source + (null + `(:error ,(format nil "No source info for: ~A" object))) + ((satisfies source-location-p) + (resolve-source-location source)) + (pathname + (make-name-in-file-location source name)) + (cons + (destructuring-bind ((dg name) pathname) source + (declare (ignore dg)) + (etypecase pathname + (pathname (make-name-in-file-location pathname (string name))) + (null `(:error ,(format nil "Cannot resolve: ~S" source))))))))) + +(defun setf-definitions (name) + (let ((f (or (ext:info :setf :inverse name) + (ext:info :setf :expander name) + (and (symbolp name) + (fboundp `(setf ,name)) + (fdefinition `(setf ,name)))))) + (if f + `(((setf ,name) ,(function-location (cond ((functionp f) f) + ((macro-function f)) + ((fdefinition f))))))))) + +(defun variable-location (symbol) + (multiple-value-bind (location foundp) + ;; XXX for 18e compatibilty. rewrite this when we drop 18e + ;; support. + (ignore-errors (eval `(ext:info :source-location :defvar ',symbol))) + (if (and foundp location) + (resolve-source-location location) + `(:error ,(format nil "No source info for variable ~S" symbol))))) + +(defun variable-definitions (name) + (if (symbolp name) + (multiple-value-bind (kind recorded-p) (ext:info :variable :kind name) + (if recorded-p + (list (list `(variable ,kind ,name) + (variable-location name))))))) + +(defun compiler-macro-definitions (symbol) + (maybe-make-definition (compiler-macro-function symbol) + 'define-compiler-macro + symbol)) + +(defun source-transform-definitions (name) + (maybe-make-definition (ext:info :function :source-transform name) + 'c:def-source-transform + name)) + +(defun function-info-definitions (name) + (let ((info (ext:info :function :info name))) + (if info + (append (loop for transform in (c::function-info-transforms info) + collect (list `(c:deftransform ,name + ,(c::type-specifier + (c::transform-type transform))) + (function-location (c::transform-function + transform)))) + (maybe-make-definition (c::function-info-derive-type info) + 'c::derive-type name) + (maybe-make-definition (c::function-info-optimizer info) + 'c::optimizer name) + (maybe-make-definition (c::function-info-ltn-annotate info) + 'c::ltn-annotate name) + (maybe-make-definition (c::function-info-ir2-convert info) + 'c::ir2-convert name) + (loop for template in (c::function-info-templates info) + collect (list `(,(type-of template) + ,(c::template-name template)) + (function-location + (c::vop-info-generator-function + template)))))))) + +(defun ir1-translator-definitions (name) + (maybe-make-definition (ext:info :function :ir1-convert name) + 'c:def-ir1-translator name)) + +(defun template-definitions (name) + (let* ((templates (c::backend-template-names c::*backend*)) + (template (gethash name templates))) + (etypecase template + (null) + (c::vop-info + (maybe-make-definition (c::vop-info-generator-function template) + (type-of template) name))))) + +;; for cases like: (%primitive NAME ...) +(defun primitive-definitions (name) + (let ((csym (find-symbol (string name) 'c))) + (and csym + (not (eq csym name)) + (template-definitions csym)))) + +(defun vm-support-routine-definitions (name) + (let ((sr (c::backend-support-routines c::*backend*)) + (name (find-symbol (string name) 'c))) + (and name + (slot-exists-p sr name) + (maybe-make-definition (slot-value sr name) + (find-symbol (string 'vm-support-routine) 'c) + name)))) + + +;;;; Documentation. + +(defimplementation describe-symbol-for-emacs (symbol) + (let ((result '())) + (flet ((doc (kind) + (or (documentation symbol kind) :not-documented)) + (maybe-push (property value) + (when value + (setf result (list* property value result))))) + (maybe-push + :variable (multiple-value-bind (kind recorded-p) + (ext:info variable kind symbol) + (declare (ignore kind)) + (if (or (boundp symbol) recorded-p) + (doc 'variable)))) + (when (fboundp symbol) + (maybe-push + (cond ((macro-function symbol) :macro) + ((special-operator-p symbol) :special-operator) + ((genericp (fdefinition symbol)) :generic-function) + (t :function)) + (doc 'function))) + (maybe-push + :setf (if (or (ext:info setf inverse symbol) + (ext:info setf expander symbol)) + (doc 'setf))) + (maybe-push + :type (if (ext:info type kind symbol) + (doc 'type))) + (maybe-push + :class (if (find-class symbol nil) + (doc 'class))) + (maybe-push + :alien-type (if (not (eq (ext:info alien-type kind symbol) :unknown)) + (doc 'alien-type))) + (maybe-push + :alien-struct (if (ext:info alien-type struct symbol) + (doc nil))) + (maybe-push + :alien-union (if (ext:info alien-type union symbol) + (doc nil))) + (maybe-push + :alien-enum (if (ext:info alien-type enum symbol) + (doc nil))) + result))) + +(defimplementation describe-definition (symbol namespace) + (describe (ecase namespace + (:variable + symbol) + ((:function :generic-function) + (symbol-function symbol)) + (:setf + (or (ext:info setf inverse symbol) + (ext:info setf expander symbol))) + (:type + (kernel:values-specifier-type symbol)) + (:class + (find-class symbol)) + (:alien-struct + (ext:info :alien-type :struct symbol)) + (:alien-union + (ext:info :alien-type :union symbol)) + (:alien-enum + (ext:info :alien-type :enum symbol)) + (:alien-type + (ecase (ext:info :alien-type :kind symbol) + (:primitive + (let ((alien::*values-type-okay* t)) + (funcall (ext:info :alien-type :translator symbol) + (list symbol)))) + ((:defined) + (ext:info :alien-type :definition symbol)) + (:unknown :unkown)))))) + +;;;;; Argument lists + +(defimplementation arglist (fun) + (etypecase fun + (function (function-arglist fun)) + (symbol (function-arglist (or (macro-function fun) + (symbol-function fun)))))) + +(defun function-arglist (fun) + (let ((arglist + (cond ((eval:interpreted-function-p fun) + (eval:interpreted-function-arglist fun)) + ((pcl::generic-function-p fun) + (pcl:generic-function-lambda-list fun)) + ((c::byte-function-or-closure-p fun) + (byte-code-function-arglist fun)) + ((kernel:%function-arglist (kernel:%function-self fun)) + (handler-case (read-arglist fun) + (error () :not-available))) + ;; this should work both for compiled-debug-function + ;; and for interpreted-debug-function + (t + (handler-case (debug-function-arglist + (di::function-debug-function fun)) + (di:unhandled-condition () :not-available)))))) + (check-type arglist (or list (member :not-available))) + arglist)) + +(defimplementation function-name (function) + (cond ((eval:interpreted-function-p function) + (eval:interpreted-function-name function)) + ((pcl::generic-function-p function) + (pcl::generic-function-name function)) + ((c::byte-function-or-closure-p function) + (c::byte-function-name function)) + (t (kernel:%function-name (kernel:%function-self function))))) + +;;; A simple case: the arglist is available as a string that we can +;;; `read'. + +(defun read-arglist (fn) + "Parse the arglist-string of the function object FN." + (let ((string (kernel:%function-arglist + (kernel:%function-self fn))) + (package (find-package + (c::compiled-debug-info-package + (kernel:%code-debug-info + (vm::find-code-object fn)))))) + (with-standard-io-syntax + (let ((*package* (or package *package*))) + (read-from-string string))))) + +;;; A harder case: an approximate arglist is derived from available +;;; debugging information. + +(defun debug-function-arglist (debug-function) + "Derive the argument list of DEBUG-FUNCTION from debug info." + (let ((args (di::debug-function-lambda-list debug-function)) + (required '()) + (optional '()) + (rest '()) + (key '())) + ;; collect the names of debug-vars + (dolist (arg args) + (etypecase arg + (di::debug-variable + (push (di::debug-variable-symbol arg) required)) + ((member :deleted) + (push ':deleted required)) + (cons + (ecase (car arg) + (:keyword + (push (second arg) key)) + (:optional + (push (debug-variable-symbol-or-deleted (second arg)) optional)) + (:rest + (push (debug-variable-symbol-or-deleted (second arg)) rest)))))) + ;; intersperse lambda keywords as needed + (append (nreverse required) + (if optional (cons '&optional (nreverse optional))) + (if rest (cons '&rest (nreverse rest))) + (if key (cons '&key (nreverse key)))))) + +(defun debug-variable-symbol-or-deleted (var) + (etypecase var + (di:debug-variable + (di::debug-variable-symbol var)) + ((member :deleted) + '#:deleted))) + +(defun symbol-debug-function-arglist (fname) + "Return FNAME's debug-function-arglist and %function-arglist. +A utility for debugging DEBUG-FUNCTION-ARGLIST." + (let ((fn (fdefinition fname))) + (values (debug-function-arglist (di::function-debug-function fn)) + (kernel:%function-arglist (kernel:%function-self fn))))) + +;;; Deriving arglists for byte-compiled functions: +;;; +(defun byte-code-function-arglist (fn) + ;; There doesn't seem to be much arglist information around for + ;; byte-code functions. Use the arg-count and return something like + ;; (arg0 arg1 ...) + (etypecase fn + (c::simple-byte-function + (loop for i from 0 below (c::simple-byte-function-num-args fn) + collect (make-arg-symbol i))) + (c::hairy-byte-function + (hairy-byte-function-arglist fn)) + (c::byte-closure + (byte-code-function-arglist (c::byte-closure-function fn))))) + +(defun make-arg-symbol (i) + (make-symbol (format nil "~A~D" (string 'arg) i))) + +;;; A "hairy" byte-function is one that takes a variable number of +;;; arguments. `hairy-byte-function' is a type from the bytecode +;;; interpreter. +;;; +(defun hairy-byte-function-arglist (fn) + (let ((counter -1)) + (flet ((next-arg () (make-arg-symbol (incf counter)))) + (with-struct (c::hairy-byte-function- min-args max-args rest-arg-p + keywords-p keywords) fn + (let ((arglist '()) + (optional (- max-args min-args))) + ;; XXX isn't there a better way to write this? + ;; (Looks fine to me. -luke) + (dotimes (i min-args) + (push (next-arg) arglist)) + (when (plusp optional) + (push '&optional arglist) + (dotimes (i optional) + (push (next-arg) arglist))) + (when rest-arg-p + (push '&rest arglist) + (push (next-arg) arglist)) + (when keywords-p + (push '&key arglist) + (loop for (key _ __) in keywords + do (push key arglist)) + (when (eq keywords-p :allow-others) + (push '&allow-other-keys arglist))) + (nreverse arglist)))))) + + +;;;; Miscellaneous. + +(defimplementation macroexpand-all (form &optional env) + (walker:macroexpand-all form env)) + +(defimplementation compiler-macroexpand-1 (form &optional env) + (ext:compiler-macroexpand-1 form env)) + +(defimplementation compiler-macroexpand (form &optional env) + (ext:compiler-macroexpand form env)) + +(defimplementation set-default-directory (directory) + (setf (ext:default-directory) (namestring directory)) + ;; Setting *default-pathname-defaults* to an absolute directory + ;; makes the behavior of MERGE-PATHNAMES a bit more intuitive. + (setf *default-pathname-defaults* (pathname (ext:default-directory))) + (default-directory)) + +(defimplementation default-directory () + (namestring (ext:default-directory))) + +(defimplementation getpid () + (unix:unix-getpid)) + +(defimplementation lisp-implementation-type-name () + "cmucl") + +(defimplementation quit-lisp () + (ext::quit)) + +;;; source-path-{stream,file,string,etc}-position moved into +;;; source-path-parser + + +;;;; Debugging + +(defvar *sldb-stack-top*) + +(defimplementation call-with-debugging-environment (debugger-loop-fn) + (unix:unix-sigsetmask 0) + (let* ((*sldb-stack-top* (or debug:*stack-top-hint* (di:top-frame))) + (debug:*stack-top-hint* nil) + (kernel:*current-level* 0)) + (handler-bind ((di::unhandled-condition + (lambda (condition) + (error 'sldb-condition + :original-condition condition)))) + (unwind-protect + (progn + #+(or)(sys:scrub-control-stack) + (funcall debugger-loop-fn)) + #+(or)(sys:scrub-control-stack) + )))) + +(defun frame-down (frame) + (handler-case (di:frame-down frame) + (di:no-debug-info () nil))) + +(defun nth-frame (index) + (do ((frame *sldb-stack-top* (frame-down frame)) + (i index (1- i))) + ((zerop i) frame))) + +(defimplementation compute-backtrace (start end) + (let ((end (or end most-positive-fixnum))) + (loop for f = (nth-frame start) then (frame-down f) + for i from start below end + while f collect f))) + +(defimplementation print-frame (frame stream) + (let ((*standard-output* stream)) + (handler-case + (debug::print-frame-call frame :verbosity 1 :number nil) + (error (e) + (ignore-errors (princ e stream)))))) + +(defimplementation frame-source-location (index) + (let ((frame (nth-frame index))) + (cond ((foreign-frame-p frame) (foreign-frame-source-location frame)) + ((code-location-source-location (di:frame-code-location frame)))))) + +(defimplementation eval-in-frame (form index) + (di:eval-in-frame (nth-frame index) form)) + +(defun frame-debug-vars (frame) + "Return a vector of debug-variables in frame." + (let ((loc (di:frame-code-location frame))) + (remove-if + (lambda (v) + (not (eq (di:debug-variable-validity v loc) :valid))) + (di::debug-function-debug-variables (di:frame-debug-function frame))))) + +(defun debug-var-value (var frame) + (let* ((loc (di:frame-code-location frame)) + (validity (di:debug-variable-validity var loc))) + (ecase validity + (:valid (di:debug-variable-value var frame)) + ((:invalid :unknown) (make-symbol (string validity)))))) + +(defimplementation frame-locals (index) + (let ((frame (nth-frame index))) + (loop for v across (frame-debug-vars frame) + collect (list :name (di:debug-variable-symbol v) + :id (di:debug-variable-id v) + :value (debug-var-value v frame))))) + +(defimplementation frame-var-value (frame var) + (let* ((frame (nth-frame frame)) + (dvar (aref (frame-debug-vars frame) var))) + (debug-var-value dvar frame))) + +(defimplementation frame-catch-tags (index) + (mapcar #'car (di:frame-catches (nth-frame index)))) + +(defimplementation frame-package (frame-number) + (let* ((frame (nth-frame frame-number)) + (dbg-fun (di:frame-debug-function frame))) + (typecase dbg-fun + (di::compiled-debug-function + (let* ((comp (di::compiled-debug-function-component dbg-fun)) + (dbg-info (kernel:%code-debug-info comp))) + (typecase dbg-info + (c::compiled-debug-info + (find-package (c::compiled-debug-info-package dbg-info))))))))) + +(defimplementation return-from-frame (index form) + (let ((sym (find-symbol (string 'find-debug-tag-for-frame) + :debug-internals))) + (if sym + (let* ((frame (nth-frame index)) + (probe (funcall sym frame))) + (cond (probe (throw (car probe) (eval-in-frame form index))) + (t (format nil "Cannot return from frame: ~S" frame)))) + "return-from-frame is not implemented in this version of CMUCL."))) + +(defimplementation activate-stepping (frame) + (set-step-breakpoints (nth-frame frame))) + +(defimplementation sldb-break-on-return (frame) + (break-on-return (nth-frame frame))) + +;;; We set the breakpoint in the caller which might be a bit confusing. +;;; +(defun break-on-return (frame) + (let* ((caller (di:frame-down frame)) + (cl (di:frame-code-location caller))) + (flet ((hook (frame bp) + (when (frame-pointer= frame caller) + (di:delete-breakpoint bp) + (signal-breakpoint bp frame)))) + (let* ((info (ecase (di:code-location-kind cl) + ((:single-value-return :unknown-return) nil) + (:known-return (debug-function-returns + (di:frame-debug-function frame))))) + (bp (di:make-breakpoint #'hook cl :kind :code-location + :info info))) + (di:activate-breakpoint bp) + `(:ok ,(format nil "Set breakpoint in ~A" caller)))))) + +(defun frame-pointer= (frame1 frame2) + "Return true if the frame pointers of FRAME1 and FRAME2 are the same." + (sys:sap= (di::frame-pointer frame1) (di::frame-pointer frame2))) + +;;; The PC in escaped frames at a single-return-value point is +;;; actually vm:single-value-return-byte-offset bytes after the +;;; position given in the debug info. Here we try to recognize such +;;; cases. +;;; +(defun next-code-locations (frame code-location) + "Like `debug::next-code-locations' but be careful in escaped frames." + (let ((next (debug::next-code-locations code-location))) + (flet ((adjust-pc () + (let ((cl (di::copy-compiled-code-location code-location))) + (incf (di::compiled-code-location-pc cl) + vm:single-value-return-byte-offset) + cl))) + (cond ((and (di::compiled-frame-escaped frame) + (eq (di:code-location-kind code-location) + :single-value-return) + (= (length next) 1) + (di:code-location= (car next) (adjust-pc))) + (debug::next-code-locations (car next))) + (t + next))))) + +(defun set-step-breakpoints (frame) + (let ((cl (di:frame-code-location frame))) + (when (di:debug-block-elsewhere-p (di:code-location-debug-block cl)) + (error "Cannot step in elsewhere code")) + (let* ((debug::*bad-code-location-types* + (remove :call-site debug::*bad-code-location-types*)) + (next (next-code-locations frame cl))) + (cond (next + (let ((steppoints '())) + (flet ((hook (bp-frame bp) + (signal-breakpoint bp bp-frame) + (mapc #'di:delete-breakpoint steppoints))) + (dolist (code-location next) + (let ((bp (di:make-breakpoint #'hook code-location + :kind :code-location))) + (di:activate-breakpoint bp) + (push bp steppoints)))))) + (t + (break-on-return frame)))))) + + +;; XXX the return values at return breakpoints should be passed to the +;; user hooks. debug-int.lisp should be changed to do this cleanly. + +;;; The sigcontext and the PC for a breakpoint invocation are not +;;; passed to user hook functions, but we need them to extract return +;;; values. So we advice di::handle-breakpoint and bind the values to +;;; special variables. +;;; +(defvar *breakpoint-sigcontext*) +(defvar *breakpoint-pc*) + +(define-fwrapper bind-breakpoint-sigcontext (offset c sigcontext) + (let ((*breakpoint-sigcontext* sigcontext) + (*breakpoint-pc* offset)) + (call-next-function))) +(set-fwrappers 'di::handle-breakpoint '()) +(fwrap 'di::handle-breakpoint #'bind-breakpoint-sigcontext) + +(defun sigcontext-object (sc index) + "Extract the lisp object in sigcontext SC at offset INDEX." + (kernel:make-lisp-obj (vm:sigcontext-register sc index))) + +(defun known-return-point-values (sigcontext sc-offsets) + (let ((fp (system:int-sap (vm:sigcontext-register sigcontext + vm::cfp-offset)))) + (system:without-gcing + (loop for sc-offset across sc-offsets + collect (di::sub-access-debug-var-slot fp sc-offset sigcontext))))) + +;;; CMUCL returns the first few values in registers and the rest on +;;; the stack. In the multiple value case, the number of values is +;;; stored in a dedicated register. The values of the registers can be +;;; accessed in the sigcontext for the breakpoint. There are 3 kinds +;;; of return conventions: :single-value-return, :unknown-return, and +;;; :known-return. +;;; +;;; The :single-value-return convention returns the value in a +;;; register without setting the nargs registers. +;;; +;;; The :unknown-return variant is used for multiple values. A +;;; :unknown-return point consists actually of 2 breakpoints: one for +;;; the single value case and one for the general case. The single +;;; value breakpoint comes vm:single-value-return-byte-offset after +;;; the multiple value breakpoint. +;;; +;;; The :known-return convention is used by local functions. +;;; :known-return is currently not supported because we don't know +;;; where the values are passed. +;;; +(defun breakpoint-values (breakpoint) + "Return the list of return values for a return point." + (flet ((1st (sc) (sigcontext-object sc (car vm::register-arg-offsets)))) + (let ((sc (locally (declare (optimize (speed 0))) + (alien:sap-alien *breakpoint-sigcontext* (* unix:sigcontext)))) + (cl (di:breakpoint-what breakpoint))) + (ecase (di:code-location-kind cl) + (:single-value-return + (list (1st sc))) + (:known-return + (let ((info (di:breakpoint-info breakpoint))) + (if (vectorp info) + (known-return-point-values sc info) + (progn + ;;(break) + (list "<>" info))))) + (:unknown-return + (let ((mv-return-pc (di::compiled-code-location-pc cl))) + (if (= mv-return-pc *breakpoint-pc*) + (mv-function-end-breakpoint-values sc) + (list (1st sc))))))))) + +;; XXX: di::get-function-end-breakpoint-values takes 2 arguments in +;; newer versions of CMUCL (after ~March 2005). +(defun mv-function-end-breakpoint-values (sigcontext) + (let ((sym (find-symbol "FUNCTION-END-BREAKPOINT-VALUES/STANDARD" :di))) + (cond (sym (funcall sym sigcontext)) + (t (funcall 'di::get-function-end-breakpoint-values sigcontext))))) + +(defun debug-function-returns (debug-fun) + "Return the return style of DEBUG-FUN." + (let* ((cdfun (di::compiled-debug-function-compiler-debug-fun debug-fun))) + (c::compiled-debug-function-returns cdfun))) + +(define-condition breakpoint (simple-condition) + ((message :initarg :message :reader breakpoint.message) + (values :initarg :values :reader breakpoint.values)) + (:report (lambda (c stream) (princ (breakpoint.message c) stream)))) + +(defimplementation condition-extras (condition) + (typecase condition + (breakpoint + ;; pop up the source buffer + `((:show-frame-source 0))) + (t '()))) + +(defun signal-breakpoint (breakpoint frame) + "Signal a breakpoint condition for BREAKPOINT in FRAME. +Try to create a informative message." + (flet ((brk (values fstring &rest args) + (let ((msg (apply #'format nil fstring args)) + (debug:*stack-top-hint* frame)) + (break 'breakpoint :message msg :values values)))) + (with-struct (di::breakpoint- kind what) breakpoint + (case kind + (:code-location + (case (di:code-location-kind what) + ((:single-value-return :known-return :unknown-return) + (let ((values (breakpoint-values breakpoint))) + (brk values "Return value: ~{~S ~}" values))) + (t + #+(or) + (when (eq (di:code-location-kind what) :call-site) + (call-site-function breakpoint frame)) + (brk nil "Breakpoint: ~S ~S" + (di:code-location-kind what) + (di::compiled-code-location-pc what))))) + (:function-start + (brk nil "Function start breakpoint")) + (t (brk nil "Breakpoint: ~A in ~A" breakpoint frame)))))) + +(defimplementation sldb-break-at-start (fname) + (let ((debug-fun (di:function-debug-function (coerce fname 'function)))) + (cond ((not debug-fun) + `(:error ,(format nil "~S has no debug-function" fname))) + (t + (flet ((hook (frame bp &optional args cookie) + (declare (ignore args cookie)) + (signal-breakpoint bp frame))) + (let ((bp (di:make-breakpoint #'hook debug-fun + :kind :function-start))) + (di:activate-breakpoint bp) + `(:ok ,(format nil "Set breakpoint in ~S" fname)))))))) + +(defun frame-cfp (frame) + "Return the Control-Stack-Frame-Pointer for FRAME." + (etypecase frame + (di::compiled-frame (di::frame-pointer frame)) + ((or di::interpreted-frame null) -1))) + +(defun frame-ip (frame) + "Return the (absolute) instruction pointer and the relative pc of FRAME." + (if (not frame) + -1 + (let ((debug-fun (di::frame-debug-function frame))) + (etypecase debug-fun + (di::compiled-debug-function + (let* ((code-loc (di:frame-code-location frame)) + (component (di::compiled-debug-function-component debug-fun)) + (pc (di::compiled-code-location-pc code-loc)) + (ip (sys:without-gcing + (sys:sap-int + (sys:sap+ (kernel:code-instructions component) pc))))) + (values ip pc))) + (di::interpreted-debug-function -1) + (di::bogus-debug-function + #-x86 + (let* ((real (di::frame-real-frame (di::frame-up frame))) + (fp (di::frame-pointer real))) + ;;#+(or) + (progn + (format *debug-io* "Frame-real-frame = ~S~%" real) + (format *debug-io* "fp = ~S~%" fp) + (format *debug-io* "lra = ~S~%" + (kernel:stack-ref fp vm::lra-save-offset))) + (values + (sys:int-sap + (- (kernel:get-lisp-obj-address + (kernel:stack-ref fp vm::lra-save-offset)) + (- (ash vm:function-code-offset vm:word-shift) + vm:function-pointer-type))) + 0)) + #+x86 + (let ((fp (di::frame-pointer (di:frame-up frame)))) + (multiple-value-bind (ra ofp) (di::x86-call-context fp) + (declare (ignore ofp)) + (values ra 0)))))))) + +(defun frame-registers (frame) + "Return the lisp registers CSP, CFP, IP, OCFP, LRA for FRAME-NUMBER." + (let* ((cfp (frame-cfp frame)) + (csp (frame-cfp (di::frame-up frame))) + (ip (frame-ip frame)) + (ocfp (frame-cfp (di::frame-down frame))) + (lra (frame-ip (di::frame-down frame)))) + (values csp cfp ip ocfp lra))) + +(defun print-frame-registers (frame-number) + (let ((frame (di::frame-real-frame (nth-frame frame-number)))) + (flet ((fixnum (p) (etypecase p + (integer p) + (sys:system-area-pointer (sys:sap-int p))))) + (apply #'format t "~ +~8X Stack Pointer +~8X Frame Pointer +~8X Instruction Pointer +~8X Saved Frame Pointer +~8X Saved Instruction Pointer~%" (mapcar #'fixnum + (multiple-value-list (frame-registers frame))))))) + +(defvar *gdb-program-name* + (ext:enumerate-search-list (p "path:gdb") + (when (probe-file p) + (return p)))) + +(defimplementation disassemble-frame (frame-number) + (print-frame-registers frame-number) + (terpri) + (let* ((frame (di::frame-real-frame (nth-frame frame-number))) + (debug-fun (di::frame-debug-function frame))) + (etypecase debug-fun + (di::compiled-debug-function + (let* ((component (di::compiled-debug-function-component debug-fun)) + (fun (di:debug-function-function debug-fun))) + (if fun + (disassemble fun) + (disassem:disassemble-code-component component)))) + (di::bogus-debug-function + (cond ((probe-file *gdb-program-name*) + (let ((ip (sys:sap-int (frame-ip frame)))) + (princ (gdb-command "disas 0x~x" ip)))) + (t + (format t "~%[Disassembling bogus frames not implemented]"))))))) + +(defmacro with-temporary-file ((stream filename) &body body) + `(call/temporary-file (lambda (,stream ,filename) . ,body))) + +(defun call/temporary-file (fun) + (let ((name (system::pick-temporary-file-name))) + (unwind-protect + (with-open-file (stream name :direction :output :if-exists :supersede) + (funcall fun stream name)) + (delete-file name)))) + +(defun gdb-command (format-string &rest args) + (let ((str (gdb-exec (format nil + "interpreter-exec mi2 \"attach ~d\"~%~ + interpreter-exec console ~s~%detach" + (getpid) + (apply #'format nil format-string args)))) + (prompt (format nil + #-(and darwin x86) "~%^done~%(gdb) ~%" + #+(and darwin x86) +"~%^done,thread-id=\"1\"~%(gdb) ~%"))) + (subseq str (+ (or (search prompt str) 0) (length prompt))))) + +(defun gdb-exec (cmd) + (with-temporary-file (file filename) + (write-string cmd file) + (force-output file) + (let* ((output (make-string-output-stream)) + ;; gdb on sparc needs to know the executable to find the + ;; symbols. Without this, gdb can't disassemble anything. + ;; NOTE: We assume that the first entry in + ;; lisp::*cmucl-lib* is the bin directory where lisp is + ;; located. If this is not true, we'll have to do + ;; something better to find the lisp executable. + (lisp-path + #+sparc + (list + (namestring + (probe-file + (merge-pathnames "lisp" (car (lisp::parse-unix-search-path + lisp::*cmucl-lib*)))))) + #-sparc + nil) + (proc (ext:run-program *gdb-program-name* + `(,@lisp-path "-batch" "-x" ,filename) + :wait t + :output output))) + (assert (eq (ext:process-status proc) :exited)) + (assert (eq (ext:process-exit-code proc) 0)) + (get-output-stream-string output)))) + +(defun foreign-frame-p (frame) + #-x86 + (let ((ip (frame-ip frame))) + (and (sys:system-area-pointer-p ip) + (typep (di::frame-debug-function frame) 'di::bogus-debug-function))) + #+x86 + (let ((ip (frame-ip frame))) + (and (sys:system-area-pointer-p ip) + (multiple-value-bind (pc code) + (di::compute-lra-data-from-pc ip) + (declare (ignore pc)) + (not code))))) + +(defun foreign-frame-source-location (frame) + (let ((ip (sys:sap-int (frame-ip frame)))) + (cond ((probe-file *gdb-program-name*) + (parse-gdb-line-info (gdb-command "info line *0x~x" ip))) + (t `(:error "no srcloc available for ~a" frame))))) + +;; The output of gdb looks like: +;; Line 215 of "../../src/lisp/x86-assem.S" +;; starts at address 0x805318c +;; and ends at 0x805318e . +;; The ../../ are fixed up with the "target:" search list which might +;; be wrong sometimes. +(defun parse-gdb-line-info (string) + (with-input-from-string (*standard-input* string) + (let ((w1 (read-word))) + (cond ((equal w1 "Line") + (let ((line (read-word))) + (assert (equal (read-word) "of")) + (let* ((file (read-from-string (read-word))) + (pathname + (or (probe-file file) + (probe-file (format nil "target:lisp/~a" file)) + file))) + (make-location (list :file (unix-truename pathname)) + (list :line (parse-integer line)))))) + (t + `(:error ,string)))))) + +(defun read-word (&optional (stream *standard-input*)) + (peek-char t stream) + (concatenate 'string (loop until (whitespacep (peek-char nil stream)) + collect (read-char stream)))) + +(defun whitespacep (char) + (member char '(#\space #\newline))) + + +;;;; Inspecting + +(defconstant +lowtag-symbols+ + '(vm:even-fixnum-type + vm:function-pointer-type + vm:other-immediate-0-type + vm:list-pointer-type + vm:odd-fixnum-type + vm:instance-pointer-type + vm:other-immediate-1-type + vm:other-pointer-type) + "Names of the constants that specify type tags. +The `symbol-value' of each element is a type tag.") + +(defconstant +header-type-symbols+ + (labels ((suffixp (suffix string) + (and (>= (length string) (length suffix)) + (string= string suffix :start1 (- (length string) + (length suffix))))) + (header-type-symbol-p (x) + (and (suffixp "-TYPE" (symbol-name x)) + (not (member x +lowtag-symbols+)) + (boundp x) + (typep (symbol-value x) 'fixnum)))) + (remove-if-not #'header-type-symbol-p + (append (apropos-list "-TYPE" "VM") + (apropos-list "-TYPE" "BIGNUM")))) + "A list of names of the type codes in boxed objects.") + +(defimplementation describe-primitive-type (object) + (with-output-to-string (*standard-output*) + (let* ((lowtag (kernel:get-lowtag object)) + (lowtag-symbol (find lowtag +lowtag-symbols+ :key #'symbol-value))) + (format t "lowtag: ~A" lowtag-symbol) + (when (member lowtag (list vm:other-pointer-type + vm:function-pointer-type + vm:other-immediate-0-type + vm:other-immediate-1-type + )) + (let* ((type (kernel:get-type object)) + (type-symbol (find type +header-type-symbols+ + :key #'symbol-value))) + (format t ", type: ~A" type-symbol)))))) + +(defmethod emacs-inspect ((o t)) + (cond ((di::indirect-value-cell-p o) + `("Value: " (:value ,(c:value-cell-ref o)))) + ((alien::alien-value-p o) + (inspect-alien-value o)) + (t + (cmucl-inspect o)))) + +(defun cmucl-inspect (o) + (destructuring-bind (text labeledp . parts) (inspect::describe-parts o) + (list* (format nil "~A~%" text) + (if labeledp + (loop for (label . value) in parts + append (label-value-line label value)) + (loop for value in parts for i from 0 + append (label-value-line i value)))))) + +(defmethod emacs-inspect ((o function)) + (let ((header (kernel:get-type o))) + (cond ((= header vm:function-header-type) + (append (label-value-line* + ("Self" (kernel:%function-self o)) + ("Next" (kernel:%function-next o)) + ("Name" (kernel:%function-name o)) + ("Arglist" (kernel:%function-arglist o)) + ("Type" (kernel:%function-type o)) + ("Code" (kernel:function-code-header o))) + (list + (with-output-to-string (s) + (disassem:disassemble-function o :stream s))))) + ((= header vm:closure-header-type) + (list* (format nil "~A is a closure.~%" o) + (append + (label-value-line "Function" (kernel:%closure-function o)) + `("Environment:" (:newline)) + (loop for i from 0 below (1- (kernel:get-closure-length o)) + append (label-value-line + i (kernel:%closure-index-ref o i)))))) + ((eval::interpreted-function-p o) + (cmucl-inspect o)) + (t + (call-next-method))))) + +(defmethod emacs-inspect ((o kernel:funcallable-instance)) + (append (label-value-line* + (:function (kernel:%funcallable-instance-function o)) + (:lexenv (kernel:%funcallable-instance-lexenv o)) + (:layout (kernel:%funcallable-instance-layout o))) + (cmucl-inspect o))) + +(defmethod emacs-inspect ((o kernel:code-component)) + (append + (label-value-line* + ("code-size" (kernel:%code-code-size o)) + ("entry-points" (kernel:%code-entry-points o)) + ("debug-info" (kernel:%code-debug-info o)) + ("trace-table-offset" (kernel:code-header-ref + o vm:code-trace-table-offset-slot))) + `("Constants:" (:newline)) + (loop for i from vm:code-constants-offset + below (kernel:get-header-data o) + append (label-value-line i (kernel:code-header-ref o i))) + `("Code:" + (:newline) + , (with-output-to-string (*standard-output*) + (cond ((c::compiled-debug-info-p (kernel:%code-debug-info o)) + (disassem:disassemble-code-component o)) + ((or + (c::debug-info-p (kernel:%code-debug-info o)) + (consp (kernel:code-header-ref + o vm:code-trace-table-offset-slot))) + (c:disassem-byte-component o)) + (t + (disassem:disassemble-memory + (disassem::align + (+ (logandc2 (kernel:get-lisp-obj-address o) + vm:lowtag-mask) + (* vm:code-constants-offset vm:word-bytes)) + (ash 1 vm:lowtag-bits)) + (ash (kernel:%code-code-size o) vm:word-shift)))))))) + +(defmethod emacs-inspect ((o kernel:fdefn)) + (label-value-line* + ("name" (kernel:fdefn-name o)) + ("function" (kernel:fdefn-function o)) + ("raw-addr" (sys:sap-ref-32 + (sys:int-sap (kernel:get-lisp-obj-address o)) + (* vm:fdefn-raw-addr-slot vm:word-bytes))))) + +#+(or) +(defmethod emacs-inspect ((o array)) + (if (typep o 'simple-array) + (call-next-method) + (label-value-line* + (:header (describe-primitive-type o)) + (:rank (array-rank o)) + (:fill-pointer (kernel:%array-fill-pointer o)) + (:fill-pointer-p (kernel:%array-fill-pointer-p o)) + (:elements (kernel:%array-available-elements o)) + (:data (kernel:%array-data-vector o)) + (:displacement (kernel:%array-displacement o)) + (:displaced-p (kernel:%array-displaced-p o)) + (:dimensions (array-dimensions o))))) + +(defmethod emacs-inspect ((o simple-vector)) + (append + (label-value-line* + (:header (describe-primitive-type o)) + (:length (c::vector-length o))) + (loop for i below (length o) + append (label-value-line i (aref o i))))) + +(defun inspect-alien-record (alien) + (with-struct (alien::alien-value- sap type) alien + (with-struct (alien::alien-record-type- kind name fields) type + (append + (label-value-line* + (:sap sap) + (:kind kind) + (:name name)) + (loop for field in fields + append (let ((slot (alien::alien-record-field-name field))) + (declare (optimize (speed 0))) + (label-value-line slot (alien:slot alien slot)))))))) + +(defun inspect-alien-pointer (alien) + (with-struct (alien::alien-value- sap type) alien + (label-value-line* + (:sap sap) + (:type type) + (:to (alien::deref alien))))) + +(defun inspect-alien-value (alien) + (typecase (alien::alien-value-type alien) + (alien::alien-record-type (inspect-alien-record alien)) + (alien::alien-pointer-type (inspect-alien-pointer alien)) + (t (cmucl-inspect alien)))) + +(defimplementation eval-context (obj) + (cond ((typep (class-of obj) 'structure-class) + (let* ((dd (kernel:layout-info (kernel:layout-of obj))) + (slots (kernel:dd-slots dd))) + (list* (cons '*package* + (symbol-package (if slots + (kernel:dsd-name (car slots)) + (kernel:dd-name dd)))) + (loop for slot in slots collect + (cons (kernel:dsd-name slot) + (funcall (kernel:dsd-accessor slot) obj)))))))) + + +;;;; Profiling +(defimplementation profile (fname) + (eval `(profile:profile ,fname))) + +(defimplementation unprofile (fname) + (eval `(profile:unprofile ,fname))) + +(defimplementation unprofile-all () + (eval `(profile:unprofile)) + "All functions unprofiled.") + +(defimplementation profile-report () + (eval `(profile:report-time))) + +(defimplementation profile-reset () + (eval `(profile:reset-time)) + "Reset profiling counters.") + +(defimplementation profiled-functions () + profile:*timed-functions*) + +(defimplementation profile-package (package callers methods) + (profile:profile-all :package package + :callers-p callers + :methods methods)) + + +;;;; Multiprocessing + +#+mp +(progn + (defimplementation initialize-multiprocessing (continuation) + (mp::init-multi-processing) + (mp:make-process continuation :name "swank") + ;; Threads magic: this never returns! But top-level becomes + ;; available again. + (unless mp::*idle-process* + (mp::startup-idle-and-top-level-loops))) + + (defimplementation spawn (fn &key name) + (mp:make-process fn :name (or name "Anonymous"))) + + (defvar *thread-id-counter* 0) + + (defimplementation thread-id (thread) + (or (getf (mp:process-property-list thread) 'id) + (setf (getf (mp:process-property-list thread) 'id) + (incf *thread-id-counter*)))) + + (defimplementation find-thread (id) + (find id (all-threads) + :key (lambda (p) (getf (mp:process-property-list p) 'id)))) + + (defimplementation thread-name (thread) + (mp:process-name thread)) + + (defimplementation thread-status (thread) + (mp:process-whostate thread)) + + (defimplementation current-thread () + mp:*current-process*) + + (defimplementation all-threads () + (copy-list mp:*all-processes*)) + + (defimplementation interrupt-thread (thread fn) + (mp:process-interrupt thread fn)) + + (defimplementation kill-thread (thread) + (mp:destroy-process thread)) + + (defvar *mailbox-lock* (mp:make-lock "mailbox lock")) + + (defstruct (mailbox (:conc-name mailbox.)) + (mutex (mp:make-lock "process mailbox")) + (queue '() :type list)) + + (defun mailbox (thread) + "Return THREAD's mailbox." + (mp:with-lock-held (*mailbox-lock*) + (or (getf (mp:process-property-list thread) 'mailbox) + (setf (getf (mp:process-property-list thread) 'mailbox) + (make-mailbox))))) + + (defimplementation send (thread message) + (check-slime-interrupts) + (let* ((mbox (mailbox thread))) + (mp:with-lock-held ((mailbox.mutex mbox)) + (setf (mailbox.queue mbox) + (nconc (mailbox.queue mbox) (list message)))))) + + (defimplementation receive-if (test &optional timeout) + (let ((mbox (mailbox mp:*current-process*))) + (assert (or (not timeout) (eq timeout t))) + (loop + (check-slime-interrupts) + (mp:with-lock-held ((mailbox.mutex mbox)) + (let* ((q (mailbox.queue mbox)) + (tail (member-if test q))) + (when tail + (setf (mailbox.queue mbox) + (nconc (ldiff q tail) (cdr tail))) + (return (car tail))))) + (when (eq timeout t) (return (values nil t))) + (mp:process-wait-with-timeout + "receive-if" 0.5 + (lambda () (some test (mailbox.queue mbox))))))) + + + ) ;; #+mp + + + +;;;; GC hooks +;;; +;;; Display GC messages in the echo area to avoid cluttering the +;;; normal output. +;;; + +;; this should probably not be here, but where else? +(defun background-message (message) + (swank::background-message message)) + +(defun print-bytes (nbytes &optional stream) + "Print the number NBYTES to STREAM in KB, MB, or GB units." + (let ((names '((0 bytes) (10 kb) (20 mb) (30 gb) (40 tb) (50 eb)))) + (multiple-value-bind (power name) + (loop for ((p1 n1) (p2 n2)) on names + while n2 do + (when (<= (expt 2 p1) nbytes (1- (expt 2 p2))) + (return (values p1 n1)))) + (cond (name + (format stream "~,1F ~A" (/ nbytes (expt 2 power)) name)) + (t + (format stream "~:D bytes" nbytes)))))) + +(defconstant gc-generations 6) + +#+gencgc +(defun generation-stats () + "Return a string describing the size distribution among the generations." + (let* ((alloc (loop for i below gc-generations + collect (lisp::gencgc-stats i))) + (sum (coerce (reduce #'+ alloc) 'float))) + (format nil "~{~3F~^/~}" + (mapcar (lambda (size) (/ size sum)) + alloc)))) + +(defvar *gc-start-time* 0) + +(defun pre-gc-hook (bytes-in-use) + (setq *gc-start-time* (get-internal-real-time)) + (let ((msg (format nil "[Commencing GC with ~A in use.]" + (print-bytes bytes-in-use)))) + (background-message msg))) + +(defun post-gc-hook (bytes-retained bytes-freed trigger) + (declare (ignore trigger)) + (let* ((seconds (/ (- (get-internal-real-time) *gc-start-time*) + internal-time-units-per-second)) + (msg (format nil "[GC done. ~A freed ~A retained ~A ~4F sec]" + (print-bytes bytes-freed) + (print-bytes bytes-retained) + #+gencgc(generation-stats) + #-gencgc"" + seconds))) + (background-message msg))) + +(defun install-gc-hooks () + (setq ext:*gc-notify-before* #'pre-gc-hook) + (setq ext:*gc-notify-after* #'post-gc-hook)) + +(defun remove-gc-hooks () + (setq ext:*gc-notify-before* #'lisp::default-gc-notify-before) + (setq ext:*gc-notify-after* #'lisp::default-gc-notify-after)) + +(defvar *install-gc-hooks* t + "If non-nil install GC hooks") + +(defimplementation emacs-connected () + (when *install-gc-hooks* + (install-gc-hooks))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;Trace implementations +;;In CMUCL, we have: +;; (trace ) +;; (trace (method ? (+))) +;; (trace :methods t ') ;;to trace all methods of the gf +;; can be a normal name or a (setf name) + +(defun tracedp (spec) + (member spec (eval '(trace)) :test #'equal)) + +(defun toggle-trace-aux (spec &rest options) + (cond ((tracedp spec) + (eval `(untrace ,spec)) + (format nil "~S is now untraced." spec)) + (t + (eval `(trace ,spec ,@options)) + (format nil "~S is now traced." spec)))) + +(defimplementation toggle-trace (spec) + (ecase (car spec) + ((setf) + (toggle-trace-aux spec)) + ((:defgeneric) + (let ((name (second spec))) + (toggle-trace-aux name :methods name))) + ((:defmethod) + (cond ((fboundp `(method ,@(cdr spec))) + (toggle-trace-aux `(method ,(cdr spec)))) + ;; Man, is this ugly + ((fboundp `(pcl::fast-method ,@(cdr spec))) + (toggle-trace-aux `(pcl::fast-method ,@(cdr spec)))) + (t + (error 'undefined-function :name (cdr spec))))) + ((:call) + (destructuring-bind (caller callee) (cdr spec) + (toggle-trace-aux (process-fspec callee) + :wherein (list (process-fspec caller))))) + ;; doesn't work properly + ;; ((:labels :flet) (toggle-trace-aux (process-fspec spec))) + )) + +(defun process-fspec (fspec) + (cond ((consp fspec) + (ecase (first fspec) + ((:defun :defgeneric) (second fspec)) + ((:defmethod) + `(method ,(second fspec) ,@(third fspec) ,(fourth fspec))) + ((:labels) `(labels ,(third fspec) ,(process-fspec (second fspec)))) + ((:flet) `(flet ,(third fspec) ,(process-fspec (second fspec)))))) + (t + fspec))) + +;;; Weak datastructures + +(defimplementation make-weak-key-hash-table (&rest args) + (apply #'make-hash-table :weak-p t args)) + + +;;; Save image + +(defimplementation save-image (filename &optional restart-function) + (multiple-value-bind (pid error) (unix:unix-fork) + (when (not pid) (error "fork: ~A" (unix:get-unix-error-msg error))) + (cond ((= pid 0) + (apply #'ext:save-lisp + filename + (if restart-function + `(:init-function ,restart-function)))) + (t + (let ((status (waitpid pid))) + (destructuring-bind (&key exited? status &allow-other-keys) status + (assert (and exited? (equal status 0)) () + "Invalid exit status: ~a" status))))))) + +(defun waitpid (pid) + (alien:with-alien ((status c-call:int)) + (let ((code (alien:alien-funcall + (alien:extern-alien + waitpid (alien:function c-call:int c-call:int + (* c-call:int) c-call:int)) + pid (alien:addr status) 0))) + (cond ((= code -1) (error "waitpid: ~A" (unix:get-unix-error-msg))) + (t (assert (= code pid)) + (decode-wait-status status)))))) + +(defun decode-wait-status (status) + (let ((output (with-output-to-string (s) + (call-program (list (process-status-program) + (format nil "~d" status)) + :output s)))) + (read-from-string output))) + +(defun call-program (args &key output) + (destructuring-bind (program &rest args) args + (let ((process (ext:run-program program args :output output))) + (when (not program) (error "fork failed")) + (unless (and (eq (ext:process-status process) :exited) + (= (ext:process-exit-code process) 0)) + (error "Non-zero exit status"))))) + +(defvar *process-status-program* nil) + +(defun process-status-program () + (or *process-status-program* + (setq *process-status-program* + (compile-process-status-program)))) + +(defun compile-process-status-program () + (let ((infile (system::pick-temporary-file-name + "/tmp/process-status~d~c.c"))) + (with-open-file (stream infile :direction :output :if-exists :supersede) + (format stream " +#include +#include +#include +#include +#include + +#define FLAG(value) (value ? \"t\" : \"nil\") + +int main (int argc, char** argv) { + assert (argc == 2); + { + char* endptr = NULL; + char* arg = argv[1]; + long int status = strtol (arg, &endptr, 10); + assert (endptr != arg && *endptr == '\\0'); + printf (\"(:exited? %s :status %d :signal? %s :signal %d :coredump? %s\" + \" :stopped? %s :stopsig %d)\\n\", + FLAG(WIFEXITED(status)), WEXITSTATUS(status), + FLAG(WIFSIGNALED(status)), WTERMSIG(status), + FLAG(WCOREDUMP(status)), + FLAG(WIFSTOPPED(status)), WSTOPSIG(status)); + fflush (NULL); + return 0; + } +} +") + (finish-output stream)) + (let* ((outfile (system::pick-temporary-file-name)) + (args (list "cc" "-o" outfile infile))) + (warn "Running cc: ~{~a ~}~%" args) + (call-program args :output t) + (delete-file infile) + outfile))) + +;; FIXME: lisp:unicode-complete introduced in version 20d. +#+#.(swank/backend:with-symbol 'unicode-complete 'lisp) +(defun match-semi-standard (prefix matchp) + ;; Handle the CMUCL's short character names. + (loop for name in lisp::char-name-alist + when (funcall matchp prefix (car name)) + collect (car name))) + +#+#.(swank/backend:with-symbol 'unicode-complete 'lisp) +(defimplementation character-completion-set (prefix matchp) + (let ((names (lisp::unicode-complete prefix))) + ;; Match prefix against semistandard names. If there's a match, + ;; add it to our list of matches. + (let ((semi-standard (match-semi-standard prefix matchp))) + (when semi-standard + (setf names (append semi-standard names)))) + (setf names (mapcar #'string-capitalize names)) + (loop for n in names + when (funcall matchp prefix n) + collect n))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/corman.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/corman.lisp new file mode 100644 index 0000000..80d9ddd --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/corman.lisp @@ -0,0 +1,583 @@ +;;; +;;; swank-corman.lisp --- Corman Lisp specific code for SLIME. +;;; +;;; Copyright (C) 2004, 2005 Espen Wiborg (espenhw@grumblesmurf.org) +;;; +;;; License +;;; ======= +;;; This software is provided 'as-is', without any express or implied +;;; warranty. In no event will the author be held liable for any damages +;;; arising from the use of this software. +;;; +;;; Permission is granted to anyone to use this software for any purpose, +;;; including commercial applications, and to alter it and redistribute +;;; it freely, subject to the following restrictions: +;;; +;;; 1. The origin of this software must not be misrepresented; you must +;;; not claim that you wrote the original software. If you use this +;;; software in a product, an acknowledgment in the product documentation +;;; would be appreciated but is not required. +;;; +;;; 2. Altered source versions must be plainly marked as such, and must +;;; not be misrepresented as being the original software. +;;; +;;; 3. This notice may not be removed or altered from any source +;;; distribution. +;;; +;;; Notes +;;; ===== +;;; You will need CCL 2.51, and you will *definitely* need to patch +;;; CCL with the patches at +;;; http://www.grumblesmurf.org/lisp/corman-patches, otherwise SLIME +;;; will blow up in your face. You should also follow the +;;; instructions on http://www.grumblesmurf.org/lisp/corman-slime. +;;; +;;; The only communication style currently supported is NIL. +;;; +;;; Starting CCL inside emacs (with M-x slime) seems to work for me +;;; with Corman Lisp 2.51, but I have seen random failures with 2.5 +;;; (sometimes it works, other times it hangs on start or hangs when +;;; initializing WinSock) - starting CCL externally and using M-x +;;; slime-connect always works fine. +;;; +;;; Sometimes CCL gets confused and starts giving you random memory +;;; access violation errors on startup; if this happens, try redumping +;;; your image. +;;; +;;; What works +;;; ========== +;;; * Basic editing and evaluation +;;; * Arglist display +;;; * Compilation +;;; * Loading files +;;; * apropos/describe +;;; * Debugger +;;; * Inspector +;;; +;;; TODO +;;; ==== +;;; * More debugger functionality (missing bits: restart-frame, +;;; return-from-frame, disassemble-frame, activate-stepping, +;;; toggle-trace) +;;; * XREF +;;; * Profiling +;;; * More sophisticated communication styles than NIL +;;; + +(in-package :swank/backend) + +;;; Pull in various needed bits +(require :composite-streams) +(require :sockets) +(require :winbase) +(require :lp) + +(use-package :gs) + +;; MOP stuff + +(defclass swank-mop:standard-slot-definition () + () + (:documentation + "Dummy class created so that swank.lisp will compile and load.")) + +(defun named-by-gensym-p (c) + (null (symbol-package (class-name c)))) + +(deftype swank-mop:eql-specializer () + '(satisfies named-by-gensym-p)) + +(defun swank-mop:eql-specializer-object (specializer) + (with-hash-table-iterator (next-entry cl::*clos-singleton-specializers*) + (loop (multiple-value-bind (more key value) + (next-entry) + (unless more (return nil)) + (when (eq specializer value) + (return key)))))) + +(defun swank-mop:class-finalized-p (class) + (declare (ignore class)) + t) + +(defun swank-mop:class-prototype (class) + (make-instance class)) + +(defun swank-mop:specializer-direct-methods (obj) + (declare (ignore obj)) + nil) + +(defun swank-mop:generic-function-argument-precedence-order (gf) + (generic-function-lambda-list gf)) + +(defun swank-mop:generic-function-method-combination (gf) + (declare (ignore gf)) + :standard) + +(defun swank-mop:generic-function-declarations (gf) + (declare (ignore gf)) + nil) + +(defun swank-mop:slot-definition-documentation (slot) + (declare (ignore slot)) + (getf slot :documentation nil)) + +(defun swank-mop:slot-definition-type (slot) + (declare (ignore slot)) + t) + +(import-swank-mop-symbols :cl '(;; classes + :standard-slot-definition + :eql-specializer + :eql-specializer-object + ;; standard class readers + :class-default-initargs + :class-direct-default-initargs + :class-finalized-p + :class-prototype + :specializer-direct-methods + ;; gf readers + :generic-function-argument-precedence-order + :generic-function-declarations + :generic-function-method-combination + ;; method readers + ;; slot readers + :slot-definition-documentation + :slot-definition-type)) + +;;;; swank implementations + +;;; Debugger + +(defvar *stack-trace* nil) +(defvar *frame-trace* nil) + +(defstruct frame + name function address debug-info variables) + +(defimplementation call-with-debugging-environment (fn) + (let* ((real-stack-trace (cl::stack-trace)) + (*stack-trace* (cdr (member 'cl:invoke-debugger real-stack-trace + :key #'car))) + (*frame-trace* + (let* ((db::*debug-level* (1+ db::*debug-level*)) + (db::*debug-frame-pointer* (db::stash-ebp + (ct:create-foreign-ptr))) + (db::*debug-max-level* (length real-stack-trace)) + (db::*debug-min-level* 1)) + (cdr (member #'cl:invoke-debugger + (cons + (make-frame :function nil) + (loop for i from db::*debug-min-level* + upto db::*debug-max-level* + until (eq (db::get-frame-function i) + cl::*top-level*) + collect + (make-frame + :function (db::get-frame-function i) + :address (db::get-frame-address i)))) + :key #'frame-function))))) + (funcall fn))) + +(defimplementation compute-backtrace (start end) + (loop for f in (subseq *stack-trace* start (min end (length *stack-trace*))) + collect f)) + +(defimplementation print-frame (frame stream) + (format stream "~S" frame)) + +(defun get-frame-debug-info (frame) + (or (frame-debug-info frame) + (setf (frame-debug-info frame) + (db::prepare-frame-debug-info (frame-function frame) + (frame-address frame))))) + +(defimplementation frame-locals (frame-number) + (let* ((frame (elt *frame-trace* frame-number)) + (info (get-frame-debug-info frame))) + (let ((var-list + (loop for i from 4 below (length info) by 2 + collect `(list :name ',(svref info i) :id 0 + :value (db::debug-filter ,(svref info i)))))) + (let ((vars (eval-in-frame `(list ,@var-list) frame-number))) + (setf (frame-variables frame) vars))))) + +(defimplementation eval-in-frame (form frame-number) + (let ((frame (elt *frame-trace* frame-number))) + (let ((cl::*compiler-environment* (get-frame-debug-info frame))) + (eval form)))) + +(defimplementation frame-var-value (frame-number var) + (let ((vars (frame-variables (elt *frame-trace* frame-number)))) + (when vars + (second (elt vars var))))) + +(defimplementation frame-source-location (frame-number) + (fspec-location (frame-function (elt *frame-trace* frame-number)))) + +(defun break (&optional (format-control "Break") &rest format-arguments) + (with-simple-restart (continue "Return from BREAK.") + (let ();(*debugger-hook* nil)) + (let ((condition + (make-condition 'simple-condition + :format-control format-control + :format-arguments format-arguments))) + ;;(format *debug-io* ";;; User break: ~A~%" condition) + (invoke-debugger condition)))) + nil) + +;;; Socket communication + +(defimplementation create-socket (host port &key backlog) + (sockets:start-sockets) + (sockets:make-server-socket :host host :port port)) + +(defimplementation local-port (socket) + (sockets:socket-port socket)) + +(defimplementation close-socket (socket) + (close socket)) + +(defimplementation accept-connection (socket + &key external-format buffering timeout) + (declare (ignore buffering timeout external-format)) + (sockets:make-socket-stream (sockets:accept-socket socket))) + +;;; Misc + +(defimplementation preferred-communication-style () + nil) + +(defimplementation getpid () + ccl:*current-process-id*) + +(defimplementation lisp-implementation-type-name () + "cormanlisp") + +(defimplementation quit-lisp () + (sockets:stop-sockets) + (win32:exitprocess 0)) + +(defimplementation set-default-directory (directory) + (setf (ccl:current-directory) directory) + (directory-namestring (setf *default-pathname-defaults* + (truename (merge-pathnames directory))))) + +(defimplementation default-directory () + (directory-namestring (ccl:current-directory))) + +(defimplementation macroexpand-all (form &optional env) + (declare (ignore env)) + (ccl:macroexpand-all form)) + +;;; Documentation + +(defun fspec-location (fspec) + (when (symbolp fspec) + (setq fspec (symbol-function fspec))) + (let ((file (ccl::function-source-file fspec))) + (if file + (handler-case + (let ((truename (truename + (merge-pathnames file + ccl:*cormanlisp-directory*)))) + (make-location (list :file (namestring truename)) + (if (ccl::function-source-line fspec) + (list :line + (1+ (ccl::function-source-line fspec))) + (list :function-name + (princ-to-string + (function-name fspec)))))) + (error (c) (list :error (princ-to-string c)))) + (list :error (format nil "No source information available for ~S" + fspec))))) + +(defimplementation find-definitions (name) + (list (list name (fspec-location name)))) + +(defimplementation arglist (name) + (handler-case + (cond ((and (symbolp name) + (macro-function name)) + (ccl::macro-lambda-list (symbol-function name))) + (t + (when (symbolp name) + (setq name (symbol-function name))) + (if (eq (class-of name) cl::the-class-standard-gf) + (generic-function-lambda-list name) + (ccl:function-lambda-list name)))) + (error () :not-available))) + +(defimplementation function-name (fn) + (handler-case (getf (cl::function-info-list fn) 'cl::function-name) + (error () nil))) + +(defimplementation describe-symbol-for-emacs (symbol) + (let ((result '())) + (flet ((doc (kind &optional (sym symbol)) + (or (documentation sym kind) :not-documented)) + (maybe-push (property value) + (when value + (setf result (list* property value result))))) + (maybe-push + :variable (when (boundp symbol) + (doc 'variable))) + (maybe-push + :function (if (fboundp symbol) + (doc 'function))) + (maybe-push + :class (if (find-class symbol nil) + (doc 'class))) + result))) + +(defimplementation describe-definition (symbol namespace) + (ecase namespace + (:variable + (describe symbol)) + ((:function :generic-function) + (describe (symbol-function symbol))) + (:class + (describe (find-class symbol))))) + +;;; Compiler + +(defvar *buffer-name* nil) +(defvar *buffer-position*) +(defvar *buffer-string*) +(defvar *compile-filename* nil) + +;; FIXME +(defimplementation call-with-compilation-hooks (FN) + (handler-bind ((error (lambda (c) + (signal 'compiler-condition + :original-condition c + :severity :warning + :message (format nil "~A" c) + :location + (cond (*buffer-name* + (make-location + (list :buffer *buffer-name*) + (list :offset *buffer-position* 0))) + (*compile-filename* + (make-location + (list :file *compile-filename*) + (list :position 1))) + (t + (list :error "No location"))))))) + (funcall fn))) + +(defimplementation swank-compile-file (input-file output-file + load-p external-format + &key policy) + (declare (ignore external-format policy)) + (with-compilation-hooks () + (let ((*buffer-name* nil) + (*compile-filename* input-file)) + (multiple-value-bind (output-file warnings? failure?) + (compile-file input-file :output-file output-file) + (values output-file warnings? + (or failure? (and load-p (load output-file)))))))) + +(defimplementation swank-compile-string (string &key buffer position filename + policy) + (declare (ignore filename policy)) + (with-compilation-hooks () + (let ((*buffer-name* buffer) + (*buffer-position* position) + (*buffer-string* string)) + (funcall (compile nil (read-from-string + (format nil "(~S () ~A)" 'lambda string)))) + t))) + +;;;; Inspecting + +;; Hack to make swank.lisp load, at least +(defclass file-stream ()) + +(defun comma-separated (list &optional (callback (lambda (v) + `(:value ,v)))) + (butlast (loop for e in list + collect (funcall callback e) + collect ", "))) + +(defmethod emacs-inspect ((class standard-class)) + `("Name: " + (:value ,(class-name class)) + (:newline) + "Super classes: " + ,@(comma-separated (swank-mop:class-direct-superclasses class)) + (:newline) + "Direct Slots: " + ,@(comma-separated + (swank-mop:class-direct-slots class) + (lambda (slot) + `(:value ,slot + ,(princ-to-string + (swank-mop:slot-definition-name slot))))) + (:newline) + "Effective Slots: " + ,@(if (swank-mop:class-finalized-p class) + (comma-separated + (swank-mop:class-slots class) + (lambda (slot) + `(:value ,slot ,(princ-to-string + (swank-mop:slot-definition-name slot))))) + '("#")) + (:newline) + ,@(when (documentation class t) + `("Documentation:" (:newline) ,(documentation class t) (:newline))) + "Sub classes: " + ,@(comma-separated (swank-mop:class-direct-subclasses class) + (lambda (sub) + `(:value ,sub ,(princ-to-string (class-name sub))))) + (:newline) + "Precedence List: " + ,@(if (swank-mop:class-finalized-p class) + (comma-separated + (swank-mop:class-precedence-list class) + (lambda (class) + `(:value ,class + ,(princ-to-string (class-name class))))) + '("#")) + (:newline))) + +(defmethod emacs-inspect ((slot cons)) + ;; Inspects slot definitions + (if (eq (car slot) :name) + `("Name: " (:value ,(swank-mop:slot-definition-name slot)) + (:newline) + ,@(when (swank-mop:slot-definition-documentation slot) + `("Documentation:" + (:newline) + (:value + ,(swank-mop:slot-definition-documentation slot)) + (:newline))) + "Init args: " (:value + ,(swank-mop:slot-definition-initargs slot)) + (:newline) + "Init form: " + ,(if (swank-mop:slot-definition-initfunction slot) + `(:value ,(swank-mop:slot-definition-initform slot)) + "#") (:newline) + "Init function: " + (:value ,(swank-mop:slot-definition-initfunction slot)) + (:newline)) + (call-next-method))) + +(defmethod emacs-inspect ((pathname pathnames::pathname-internal)) + (list* (if (wild-pathname-p pathname) + "A wild pathname." + "A pathname.") + '(:newline) + (append (label-value-line* + ("Namestring" (namestring pathname)) + ("Host" (pathname-host pathname)) + ("Device" (pathname-device pathname)) + ("Directory" (pathname-directory pathname)) + ("Name" (pathname-name pathname)) + ("Type" (pathname-type pathname)) + ("Version" (pathname-version pathname))) + (unless (or (wild-pathname-p pathname) + (not (probe-file pathname))) + (label-value-line "Truename" (truename pathname)))))) + +(defmethod emacs-inspect ((o t)) + (cond ((cl::structurep o) (inspect-structure o)) + (t (call-next-method)))) + +(defun inspect-structure (o) + (let* ((template (cl::uref o 1)) + (num-slots (cl::struct-template-num-slots template))) + (cond ((symbolp template) + (loop for i below num-slots + append (label-value-line i (cl::uref o (+ 2 i))))) + (t + (loop for i below num-slots + append (label-value-line (elt template (+ 6 (* i 5))) + (cl::uref o (+ 2 i)))))))) + + +;;; Threads + +(require 'threads) + +(defstruct (mailbox (:conc-name mailbox.)) + thread + (lock (make-instance 'threads:critical-section)) + (queue '() :type list)) + +(defvar *mailbox-lock* (make-instance 'threads:critical-section)) +(defvar *mailboxes* (list)) + +(defmacro with-lock (lock &body body) + `(threads:with-synchronization (threads:cs ,lock) + ,@body)) + +(defimplementation spawn (fun &key name) + (declare (ignore name)) + (th:create-thread + (lambda () + (handler-bind ((serious-condition #'invoke-debugger)) + (unwind-protect (funcall fun) + (with-lock *mailbox-lock* + (setq *mailboxes* (remove cormanlisp:*current-thread-id* + *mailboxes* :key #'mailbox.thread)))))))) + +(defimplementation thread-id (thread) + thread) + +(defimplementation find-thread (thread) + (if (thread-alive-p thread) + thread)) + +(defimplementation thread-alive-p (thread) + (if (threads:thread-handle thread) t nil)) + +(defimplementation current-thread () + cormanlisp:*current-thread-id*) + +;; XXX implement it +(defimplementation all-threads () + '()) + +;; XXX something here is broken +(defimplementation kill-thread (thread) + (threads:terminate-thread thread 'killed)) + +(defun mailbox (thread) + (with-lock *mailbox-lock* + (or (find thread *mailboxes* :key #'mailbox.thread) + (let ((mb (make-mailbox :thread thread))) + (push mb *mailboxes*) + mb)))) + +(defimplementation send (thread message) + (let ((mbox (mailbox thread))) + (with-lock (mailbox.lock mbox) + (setf (mailbox.queue mbox) + (nconc (mailbox.queue mbox) (list message)))))) + +(defimplementation receive () + (let ((mbox (mailbox cormanlisp:*current-thread-id*))) + (loop + (with-lock (mailbox.lock mbox) + (when (mailbox.queue mbox) + (return (pop (mailbox.queue mbox))))) + (sleep 0.1)))) + + +;;; This is probably not good, but it WFM +(in-package :common-lisp) + +(defvar *old-documentation* #'documentation) +(defun documentation (thing &optional (type 'function)) + (if (symbolp thing) + (funcall *old-documentation* thing type) + (values))) + +(defmethod print-object ((restart restart) stream) + (if (or *print-escape* + *print-readably*) + (print-unreadable-object (restart stream :type t :identity t) + (princ (restart-name restart) stream)) + (when (functionp (restart-report-function restart)) + (funcall (restart-report-function restart) stream)))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/ecl.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/ecl.lisp new file mode 100644 index 0000000..743aa6e --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/ecl.lisp @@ -0,0 +1,1098 @@ +;;;; -*- indent-tabs-mode: nil -*- +;;; +;;; swank-ecl.lisp --- SLIME backend for ECL. +;;; +;;; This code has been placed in the Public Domain. All warranties +;;; are disclaimed. +;;; + +;;; Administrivia + +(defpackage swank/ecl + (:use cl swank/backend)) + +(in-package swank/ecl) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defun ecl-version () + (let ((version (find-symbol "+ECL-VERSION-NUMBER+" :EXT))) + (if version + (symbol-value version) + 0))) + (when (< (ecl-version) 100301) + (error "~&IMPORTANT:~% ~ + The version of ECL you're using (~A) is too old.~% ~ + Please upgrade to at least 10.3.1.~% ~ + Sorry for the inconvenience.~%~%" + (lisp-implementation-version)))) + +;; Hard dependencies. +(eval-when (:compile-toplevel :load-toplevel :execute) + (require 'sockets)) + +;; Soft dependencies. +(eval-when (:compile-toplevel :load-toplevel :execute) + (when (probe-file "sys:profile.fas") + (require :profile) + (pushnew :profile *features*)) + (when (probe-file "sys:serve-event.fas") + (require :serve-event) + (pushnew :serve-event *features*))) + +(declaim (optimize (debug 3))) + +;;; Swank-mop + +(eval-when (:compile-toplevel :load-toplevel :execute) + (import-swank-mop-symbols + :clos + (and (< (ecl-version) 121201) + `(:eql-specializer + :eql-specializer-object + :generic-function-declarations + :specializer-direct-methods + ,@(unless (fboundp 'clos:compute-applicable-methods-using-classes) + '(:compute-applicable-methods-using-classes)))))) + +(defimplementation gray-package-name () + "GRAY") + + +;;;; UTF8 + +;;; Convert the string STRING to a (simple-array (unsigned-byte 8)). +;;; +;;; string-to-utf8 (string) + +;;; Convert the (simple-array (unsigned-byte 8)) OCTETS to a string. +;;; +;;; utf8-to-string (octets) + + +;;;; TCP Server + +(defun resolve-hostname (name) + (car (sb-bsd-sockets:host-ent-addresses + (sb-bsd-sockets:get-host-by-name name)))) + +(defimplementation create-socket (host port &key backlog) + (let ((socket (make-instance 'sb-bsd-sockets:inet-socket + :type :stream + :protocol :tcp))) + (setf (sb-bsd-sockets:sockopt-reuse-address socket) t) + (sb-bsd-sockets:socket-bind socket (resolve-hostname host) port) + (sb-bsd-sockets:socket-listen socket (or backlog 5)) + socket)) + +(defimplementation local-port (socket) + (nth-value 1 (sb-bsd-sockets:socket-name socket))) + +(defimplementation close-socket (socket) + (sb-bsd-sockets:socket-close socket)) + +(defun accept (socket) + "Like socket-accept, but retry on EAGAIN." + (loop (handler-case + (return (sb-bsd-sockets:socket-accept socket)) + (sb-bsd-sockets:interrupted-error ())))) + +(defimplementation accept-connection (socket + &key external-format + buffering timeout) + (declare (ignore timeout)) + (sb-bsd-sockets:socket-make-stream (accept socket) + :output t + :input t + :buffering (ecase buffering + ((t) :full) + ((nil) :none) + (:line :line)) + :element-type (if external-format + 'character + '(unsigned-byte 8)) + :external-format external-format)) + +;;; Call FN whenever SOCKET is readable. +;;; +;;; add-sigio-handler (socket fn) + +;;; Remove all sigio handlers for SOCKET. +;;; +;;; remove-sigio-handlers (socket) + +;;; Call FN when Lisp is waiting for input and SOCKET is readable. +;;; +;;; add-fd-handler (socket fn) + +;;; Remove all fd-handlers for SOCKET. +;;; +;;; remove-fd-handlers (socket) + +(defimplementation preferred-communication-style () + (cond + ((member :threads *features*) :spawn) + ((member :windows *features*) nil) + (t #|:fd-handler|# nil))) + +;;; Set the 'stream 'timeout. The timeout is either the real number +;;; specifying the timeout in seconds or 'nil for no timeout. +;;; +;;; set-stream-timeout (stream timeout) + + +;;; Hook called when the first connection from Emacs is established. +;;; Called from the INIT-FN of the socket server that accepts the +;;; connection. +;;; +;;; This is intended for setting up extra context, e.g. to discover +;;; that the calling thread is the one that interacts with Emacs. +;;; +;;; emacs-connected () + + +;;;; Unix Integration + +(defimplementation getpid () + (si:getpid)) + +;;; Call FUNCTION on SIGINT (instead of invoking the debugger). +;;; Return old signal handler. +;;; +;;; install-sigint-handler (function) + +;;; XXX! +;;; If ECL is built with thread support, it'll spawn a helper thread +;;; executing the SIGINT handler. We do not want to BREAK into that +;;; helper but into the main thread, though. This is coupled with the +;;; current choice of NIL as communication-style in so far as ECL's +;;; main-thread is also the Slime's REPL thread. + +(defun make-interrupt-handler (real-handler) + #+threads + (let ((main-thread (find 'si:top-level (mp:all-processes) + :key #'mp:process-name))) + #'(lambda (&rest args) + (declare (ignore args)) + (mp:interrupt-process main-thread real-handler))) + #-threads + #'(lambda (&rest args) + (declare (ignore args)) + (funcall real-handler))) + +(defimplementation call-with-user-break-handler (real-handler function) + (let ((old-handler #'si:terminal-interrupt)) + (setf (symbol-function 'si:terminal-interrupt) + (make-interrupt-handler real-handler)) + (unwind-protect (funcall function) + (setf (symbol-function 'si:terminal-interrupt) old-handler)))) + +(defimplementation quit-lisp () + (ext:quit)) + +;;; Default implementation is fine. +;;; +;;; lisp-implementation-type-name +;;; lisp-implementation-program + +(defimplementation socket-fd (socket) + (etypecase socket + (fixnum socket) + (two-way-stream (socket-fd (two-way-stream-input-stream socket))) + (sb-bsd-sockets:socket (sb-bsd-sockets:socket-file-descriptor socket)) + (file-stream (si:file-stream-fd socket)))) + +;;; Create a character stream for the file descriptor FD. This +;;; interface implementation requires either `ffi:c-inline' or has to +;;; wait for the exported interface. +;;; +;;; make-fd-stream (socket-stream) + +;;; Duplicate a file descriptor. If the syscall fails, signal a +;;; condition. See dup(2). This interface requiers `ffi:c-inline' or +;;; has to wait for the exported interface. +;;; +;;; dup (fd) + +;;; Does not apply to ECL which doesn't dump images. +;;; +;;; exec-image (image-file args) + +(defimplementation command-line-args () + (ext:command-args)) + + +;;;; pathnames + +;;; Return a pathname for FILENAME. +;;; A filename in Emacs may for example contain asterisks which should not +;;; be translated to wildcards. +;;; +;;; filename-to-pathname (filename) + +;;; Return the filename for PATHNAME. +;;; +;;; pathname-to-filename (pathname) + +(defimplementation default-directory () + (namestring (ext:getcwd))) + +(defimplementation set-default-directory (directory) + (ext:chdir (namestring directory)) ; adapts *DEFAULT-PATHNAME-DEFAULTS*. + (default-directory)) + + +;;; Call FN with hooks to handle special syntax. Can we use it for +;;; `ffi:c-inline' to be handled as C/C++ code? +;;; +;;; call-with-syntax-hooks + +;;; Return a suitable initial value for SWANK:*READTABLE-ALIST*. +;;; +;;; default-readtable-alist + + +;;;; Packages + +#+package-local-nicknames +(defimplementation package-local-nicknames (package) + (ext:package-local-nicknames package)) + + +;;;; Compilation + +(defvar *buffer-name* nil) +(defvar *buffer-start-position*) + +(defun signal-compiler-condition (&rest args) + (apply #'signal 'compiler-condition args)) + +#-ecl-bytecmp +(defun handle-compiler-message (condition) + ;; ECL emits lots of noise in compiler-notes, like "Invoking + ;; external command". + (unless (typep condition 'c::compiler-note) + (signal-compiler-condition + :original-condition condition + :message (princ-to-string condition) + :severity (etypecase condition + (c:compiler-fatal-error :error) + (c:compiler-error :error) + (error :error) + (style-warning :style-warning) + (warning :warning)) + :location (condition-location condition)))) + +#-ecl-bytecmp +(defun condition-location (condition) + (let ((file (c:compiler-message-file condition)) + (position (c:compiler-message-file-position condition))) + (if (and position (not (minusp position))) + (if *buffer-name* + (make-buffer-location *buffer-name* + *buffer-start-position* + position) + (make-file-location file position)) + (make-error-location "No location found.")))) + +(defimplementation call-with-compilation-hooks (function) + #+ecl-bytecmp + (funcall function) + #-ecl-bytecmp + (handler-bind ((c:compiler-message #'handle-compiler-message)) + (funcall function))) + +(defvar *tmpfile-map* (make-hash-table :test #'equal)) + +(defun note-buffer-tmpfile (tmp-file buffer-name) + ;; EXT:COMPILED-FUNCTION-FILE below will return a namestring. + (let ((tmp-namestring (namestring (truename tmp-file)))) + (setf (gethash tmp-namestring *tmpfile-map*) buffer-name) + tmp-namestring)) + +(defun tmpfile-to-buffer (tmp-file) + (gethash tmp-file *tmpfile-map*)) + +(defimplementation swank-compile-string + (string &key buffer position filename policy) + (declare (ignore policy)) + (with-compilation-hooks () + (let ((*buffer-name* buffer) ; for compilation hooks + (*buffer-start-position* position)) + (let ((tmp-file (si:mkstemp "TMP:ecl-swank-tmpfile-")) + (fasl-file) + (warnings-p) + (failure-p)) + (unwind-protect + (with-open-file (tmp-stream tmp-file :direction :output + :if-exists :supersede) + (write-string string tmp-stream) + (finish-output tmp-stream) + (multiple-value-setq (fasl-file warnings-p failure-p) + (compile-file tmp-file + :load t + :source-truename (or filename + (note-buffer-tmpfile tmp-file buffer)) + :source-offset (1- position)))) + (when (probe-file tmp-file) + (delete-file tmp-file)) + (when fasl-file + (delete-file fasl-file))) + (not failure-p))))) + +(defimplementation swank-compile-file (input-file output-file + load-p external-format + &key policy) + (declare (ignore policy)) + (with-compilation-hooks () + (compile-file input-file :output-file output-file + :load load-p + :external-format external-format))) + +(defvar *external-format-to-coding-system* + '((:latin-1 + "latin-1" "latin-1-unix" "iso-latin-1-unix" + "iso-8859-1" "iso-8859-1-unix") + (:utf-8 "utf-8" "utf-8-unix"))) + +(defun external-format (coding-system) + (or (car (rassoc-if (lambda (x) (member coding-system x :test #'equal)) + *external-format-to-coding-system*)) + (find coding-system (ext:all-encodings) :test #'string-equal))) + +(defimplementation find-external-format (coding-system) + #+unicode (external-format coding-system) + ;; Without unicode support, ECL uses the one-byte encoding of the + ;; underlying OS, and will barf on anything except :DEFAULT. We + ;; return NIL here for known multibyte encodings, so + ;; SWANK:CREATE-SERVER will barf. + #-unicode (let ((xf (external-format coding-system))) + (if (member xf '(:utf-8)) + nil + :default))) + + +;;; Default implementation is fine +;;; +;;; guess-external-format + + +;;;; Streams + +;;; Implemented in `gray' +;;; +;;; make-output-stream +;;; make-input-stream + + +;;;; Documentation + +(defimplementation arglist (name) + (multiple-value-bind (arglist foundp) + (ext:function-lambda-list name) + (if foundp arglist :not-available))) + +(defimplementation type-specifier-p (symbol) + (or (subtypep nil symbol) + (not (eq (type-specifier-arglist symbol) :not-available)))) + +(defimplementation function-name (f) + (typecase f + (generic-function (clos:generic-function-name f)) + (function (si:compiled-function-name f)))) + +;;; Default implementation is fine (CL). +;;; +;;; valid-function-name-p (form) + +#+walker +(defimplementation macroexpand-all (form &optional env) + (walker:macroexpand-all form env)) + +;;; Default implementation is fine. +;;; +;;; compiler-macroexpand-1 +;;; compiler-macroexpand + +(defimplementation collect-macro-forms (form &optional env) + ;; Currently detects only normal macros, not compiler macros. + (declare (ignore env)) + (with-collected-macro-forms (macro-forms) + (handler-bind ((warning #'muffle-warning)) + (ignore-errors + (compile nil `(lambda () ,form)))) + (values macro-forms nil))) + +;;; Expand the format string CONTROL-STRING. +;;; Default implementation is fine. +;;; +;;; format-string-expand + +(defimplementation describe-symbol-for-emacs (symbol) + (let ((result '())) + (flet ((frob (type boundp) + (when (funcall boundp symbol) + (let ((doc (describe-definition symbol type))) + (setf result (list* type doc result)))))) + (frob :VARIABLE #'boundp) + (frob :FUNCTION #'fboundp) + (frob :CLASS (lambda (x) (find-class x nil)))) + result)) + +(defimplementation describe-definition (name type) + (case type + (:variable (documentation name 'variable)) + (:function (documentation name 'function)) + (:class (documentation name 'class)) + (t nil))) + + +;;;; Debugging + +(eval-when (:compile-toplevel :load-toplevel :execute) + (import + '(si::*break-env* + si::*ihs-top* + si::*ihs-current* + si::*ihs-base* + si::*frs-base* + si::*frs-top* + si::*tpl-commands* + si::*tpl-level* + si::frs-top + si::ihs-top + si::ihs-fun + si::ihs-env + si::sch-frs-base + si::set-break-env + si::set-current-ihs + si::tpl-commands))) + +(defun make-invoke-debugger-hook (hook) + (when hook + #'(lambda (condition old-hook) + ;; Regard *debugger-hook* if set by user. + (if *debugger-hook* + nil ; decline, *DEBUGGER-HOOK* will be tried next. + (funcall hook condition old-hook))))) + +(defimplementation install-debugger-globally (function) + (setq *debugger-hook* function) + (setq ext:*invoke-debugger-hook* (make-invoke-debugger-hook function))) + +(defimplementation call-with-debugger-hook (hook fun) + (let ((*debugger-hook* hook) + (ext:*invoke-debugger-hook* (make-invoke-debugger-hook hook))) + (funcall fun))) + +(defvar *backtrace* '()) + +(defun in-swank-package-p (x) + (and + (symbolp x) + (member (symbol-package x) + (list #.(find-package :swank) + #.(find-package :swank/backend) + #.(ignore-errors (find-package :swank-mop)) + #.(ignore-errors (find-package :swank-loader)))) + t)) + +(defun is-swank-source-p (name) + (setf name (pathname name)) + (pathname-match-p + name + (make-pathname :defaults swank-loader::*source-directory* + :name (pathname-name name) + :type (pathname-type name) + :version (pathname-version name)))) + +(defun is-ignorable-fun-p (x) + (or + (in-swank-package-p (frame-name x)) + (multiple-value-bind (file position) + (ignore-errors (si::bc-file (car x))) + (declare (ignore position)) + (if file (is-swank-source-p file))))) + +(defimplementation call-with-debugging-environment (debugger-loop-fn) + (declare (type function debugger-loop-fn)) + (let* ((*ihs-top* (ihs-top)) + (*ihs-current* *ihs-top*) + (*frs-base* (or (sch-frs-base *frs-top* *ihs-base*) (1+ (frs-top)))) + (*frs-top* (frs-top)) + (*tpl-level* (1+ *tpl-level*)) + (*backtrace* (loop for ihs from 0 below *ihs-top* + collect (list (si::ihs-fun ihs) + (si::ihs-env ihs) + nil)))) + (declare (special *ihs-current*)) + (loop for f from *frs-base* until *frs-top* + do (let ((i (- (si::frs-ihs f) *ihs-base* 1))) + (when (plusp i) + (let* ((x (elt *backtrace* i)) + (name (si::frs-tag f))) + (unless (si::fixnump name) + (push name (third x))))))) + (setf *backtrace* (remove-if #'is-ignorable-fun-p (nreverse *backtrace*))) + (set-break-env) + (set-current-ihs) + (let ((*ihs-base* *ihs-top*)) + (funcall debugger-loop-fn)))) + +(defimplementation compute-backtrace (start end) + (subseq *backtrace* start + (and (numberp end) + (min end (length *backtrace*))))) + +(defun frame-name (frame) + (let ((x (first frame))) + (if (symbolp x) + x + (function-name x)))) + +(defun function-position (fun) + (multiple-value-bind (file position) + (si::bc-file fun) + (when file + (make-file-location file position)))) + +(defun frame-function (frame) + (let* ((x (first frame)) + fun position) + (etypecase x + (symbol (and (fboundp x) + (setf fun (fdefinition x) + position (function-position fun)))) + (function (setf fun x position (function-position x)))) + (values fun position))) + +(defun frame-decode-env (frame) + (let ((functions '()) + (blocks '()) + (variables '())) + (setf frame (si::decode-ihs-env (second frame))) + (dolist (record (remove-if-not #'consp frame)) + (let* ((record0 (car record)) + (record1 (cdr record))) + (cond ((or (symbolp record0) (stringp record0)) + (setq variables (acons record0 record1 variables))) + ((not (si::fixnump record0)) + (push record1 functions)) + ((symbolp record1) + (push record1 blocks)) + (t + )))) + (values functions blocks variables))) + +(defimplementation print-frame (frame stream) + (format stream "~A" (first frame))) + +;;; Is the frame FRAME restartable?. +;;; Return T if `restart-frame' can safely be called on the frame. +;;; +;;; frame-restartable-p (frame) + +(defimplementation frame-source-location (frame-number) + (let ((frame (elt *backtrace* frame-number))) + (or (nth-value 1 (frame-function frame)) + (make-error-location "Unknown source location for ~A." (car frame))))) + +(defimplementation frame-catch-tags (frame-number) + (third (elt *backtrace* frame-number))) + +(defimplementation frame-locals (frame-number) + (loop for (name . value) in (nth-value 2 (frame-decode-env + (elt *backtrace* frame-number))) + collect (list :name name :id 0 :value value))) + +(defimplementation frame-var-value (frame-number var-number) + (destructuring-bind (name . value) + (elt + (nth-value 2 (frame-decode-env (elt *backtrace* frame-number))) + var-number) + (declare (ignore name)) + value)) + +(defimplementation disassemble-frame (frame-number) + (let ((fun (frame-function (elt *backtrace* frame-number)))) + (disassemble fun))) + +(defimplementation eval-in-frame (form frame-number) + (let ((env (second (elt *backtrace* frame-number)))) + (si:eval-with-env form env))) + +;;; frame-package +;;; frame-call +;;; return-from-frame +;;; restart-frame +;;; print-condition +;;; condition-extras + +(defimplementation gdb-initial-commands () + ;; These signals are used by the GC. + #+linux '("handle SIGPWR noprint nostop" + "handle SIGXCPU noprint nostop")) + +;;; active-stepping +;;; sldb-break-on-return +;;; sldb-break-at-start +;;; sldb-stepper-condition-p +;;; sldb-setp-into +;;; sldb-step-next +;;; sldb-step-out + + +;;;; Definition finding + +(defvar +TAGS+ (namestring + (merge-pathnames "TAGS" (translate-logical-pathname "SYS:")))) + +(defun make-file-location (file file-position) + ;; File positions in CL start at 0, but Emacs' buffer positions + ;; start at 1. We specify (:ALIGN T) because the positions comming + ;; from ECL point at right after the toplevel form appearing before + ;; the actual target toplevel form; (:ALIGN T) will DTRT in that case. + (make-location `(:file ,(namestring (translate-logical-pathname file))) + `(:position ,(1+ file-position)) + `(:align t))) + +(defun make-buffer-location (buffer-name start-position &optional (offset 0)) + (make-location `(:buffer ,buffer-name) + `(:offset ,start-position ,offset) + `(:align t))) + +(defun make-TAGS-location (&rest tags) + (make-location `(:etags-file ,+TAGS+) + `(:tag ,@tags))) + +(defimplementation find-definitions (name) + (let ((annotations (ext:get-annotation name 'si::location :all))) + (cond (annotations + (loop for annotation in annotations + collect (destructuring-bind (dspec file . pos) annotation + `(,dspec ,(make-file-location file pos))))) + (t + (mapcan #'(lambda (type) (find-definitions-by-type name type)) + (classify-definition-name name)))))) + +(defun classify-definition-name (name) + (let ((types '())) + (when (fboundp name) + (cond ((special-operator-p name) + (push :special-operator types)) + ((macro-function name) + (push :macro types)) + ((typep (fdefinition name) 'generic-function) + (push :generic-function types)) + ((si:mangle-name name t) + (push :c-function types)) + (t + (push :lisp-function types)))) + (when (boundp name) + (cond ((constantp name) + (push :constant types)) + (t + (push :global-variable types)))) + types)) + +(defun find-definitions-by-type (name type) + (ecase type + (:lisp-function + (when-let (loc (source-location (fdefinition name))) + (list `((defun ,name) ,loc)))) + (:c-function + (when-let (loc (source-location (fdefinition name))) + (list `((c-source ,name) ,loc)))) + (:generic-function + (loop for method in (clos:generic-function-methods (fdefinition name)) + for specs = (clos:method-specializers method) + for loc = (source-location method) + when loc + collect `((defmethod ,name ,specs) ,loc))) + (:macro + (when-let (loc (source-location (macro-function name))) + (list `((defmacro ,name) ,loc)))) + (:constant + (when-let (loc (source-location name)) + (list `((defconstant ,name) ,loc)))) + (:global-variable + (when-let (loc (source-location name)) + (list `((defvar ,name) ,loc)))) + (:special-operator))) + +;;; FIXME: There ought to be a better way. +(eval-when (:compile-toplevel :load-toplevel :execute) + (defun c-function-name-p (name) + (and (symbolp name) (si:mangle-name name t) t)) + (defun c-function-p (object) + (and (functionp object) + (let ((fn-name (function-name object))) + (and fn-name (c-function-name-p fn-name)))))) + +(deftype c-function () + `(satisfies c-function-p)) + +(defun assert-source-directory () + (unless (probe-file #P"SRC:") + (error "ECL's source directory ~A does not exist. ~ + You can specify a different location via the environment ~ + variable `ECLSRCDIR'." + (namestring (translate-logical-pathname #P"SYS:"))))) + +(defun assert-TAGS-file () + (unless (probe-file +TAGS+) + (error "No TAGS file ~A found. It should have been installed with ECL." + +TAGS+))) + +(defun package-names (package) + (cons (package-name package) (package-nicknames package))) + +(defun source-location (object) + (converting-errors-to-error-location + (typecase object + (c-function + (assert-source-directory) + (assert-TAGS-file) + (let ((lisp-name (function-name object))) + (assert lisp-name) + (multiple-value-bind (flag c-name) (si:mangle-name lisp-name t) + (assert flag) + ;; In ECL's code base sometimes the mangled name is used + ;; directly, sometimes ECL's DPP magic of @SI::SYMBOL or + ;; @EXT::SYMBOL is used. We cannot predict here, so we just + ;; provide several candidates. + (apply #'make-TAGS-location + c-name + (loop with s = (symbol-name lisp-name) + for p in (package-names (symbol-package lisp-name)) + collect (format nil "~A::~A" p s) + collect (format nil "~(~A::~A~)" p s)))))) + (function + (multiple-value-bind (file pos) (ext:compiled-function-file object) + (cond ((not file) + (return-from source-location nil)) + ((tmpfile-to-buffer file) + (make-buffer-location (tmpfile-to-buffer file) pos)) + (t + (assert (probe-file file)) + (assert (not (minusp pos))) + (make-file-location file pos))))) + (method + ;; FIXME: This will always return NIL at the moment; ECL does not + ;; store debug information for methods yet. + (source-location (clos:method-function object))) + ((member nil t) + (multiple-value-bind (flag c-name) (si:mangle-name object) + (assert flag) + (make-TAGS-location c-name)))))) + +(defimplementation find-source-location (object) + (or (source-location object) + (make-error-location "Source definition of ~S not found." object))) + +;;; buffer-first-change + + +;;;; XREF + +;;; who-calls +;;; calls-who +;;; who-references +;;; who-binds +;;; who-sets +;;; who-macroexpands +;;; who-specializes +;;; list-callers +;;; list-callees + + +;;;; Profiling + +;;; XXX: use monitor.lisp (ccl,clisp) + +#+profile +(progn + +(defimplementation profile (fname) + (when fname (eval `(profile:profile ,fname)))) + +(defimplementation unprofile (fname) + (when fname (eval `(profile:unprofile ,fname)))) + +(defimplementation unprofile-all () + (profile:unprofile-all) + "All functions unprofiled.") + +(defimplementation profile-report () + (profile:report)) + +(defimplementation profile-reset () + (profile:reset) + "Reset profiling counters.") + +(defimplementation profiled-functions () + (profile:profile)) + +(defimplementation profile-package (package callers methods) + (declare (ignore callers methods)) + (eval `(profile:profile ,(package-name (find-package package))))) +) ; #+profile (progn ... + + +;;;; Trace + +;;; Toggle tracing of the function(s) given with SPEC. +;;; SPEC can be: +;;; (setf NAME) ; a setf function +;;; (:defmethod NAME QUALIFIER... (SPECIALIZER...)) ; a specific method +;;; (:defgeneric NAME) ; a generic function with all methods +;;; (:call CALLER CALLEE) ; trace calls from CALLER to CALLEE. +;;; (:labels TOPLEVEL LOCAL) +;;; (:flet TOPLEVEL LOCAL) +;;; +;;; toggle-trace (spec) + + +;;;; Inspector + +;;; FIXME: Would be nice if it was possible to inspect objects +;;; implemented in C. + +;;; Return a list of bindings corresponding to OBJECT's slots. +;;; eval-context (object) + +;;; Return a string describing the primitive type of object. +;;; describe-primitive-type (object) + + +;;;; Multithreading + +;;; Not needed in ECL +;;; +;;; initialize-multiprocessing + +#+threads +(progn + (defvar *thread-id-counter* 0) + + (defparameter *thread-id-map* (make-hash-table)) + + (defvar *thread-id-map-lock* + (mp:make-lock :name "thread id map lock")) + + (defimplementation spawn (fn &key name) + (mp:process-run-function name fn)) + + (defimplementation thread-id (target-thread) + (block thread-id + (mp:with-lock (*thread-id-map-lock*) + ;; Does TARGET-THREAD have an id already? + (maphash (lambda (id thread-pointer) + (let ((thread (si:weak-pointer-value thread-pointer))) + (cond ((not thread) + (remhash id *thread-id-map*)) + ((eq thread target-thread) + (return-from thread-id id))))) + *thread-id-map*) + ;; TARGET-THREAD not found in *THREAD-ID-MAP* + (let ((id (incf *thread-id-counter*)) + (thread-pointer (si:make-weak-pointer target-thread))) + (setf (gethash id *thread-id-map*) thread-pointer) + id)))) + + (defimplementation find-thread (id) + (mp:with-lock (*thread-id-map-lock*) + (let* ((thread-ptr (gethash id *thread-id-map*)) + (thread (and thread-ptr (si:weak-pointer-value thread-ptr)))) + (unless thread + (remhash id *thread-id-map*)) + thread))) + + (defimplementation thread-name (thread) + (mp:process-name thread)) + + (defimplementation thread-status (thread) + (if (mp:process-active-p thread) + "RUNNING" + "STOPPED")) + + ;; thread-attributes + + (defimplementation current-thread () + mp:*current-process*) + + (defimplementation all-threads () + (mp:all-processes)) + + (defimplementation thread-alive-p (thread) + (mp:process-active-p thread)) + + (defimplementation interrupt-thread (thread fn) + (mp:interrupt-process thread fn)) + + (defimplementation kill-thread (thread) + (mp:process-kill thread)) + + (defvar *mailbox-lock* (mp:make-lock :name "mailbox lock")) + (defvar *mailboxes* (list)) + (declaim (type list *mailboxes*)) + + (defstruct (mailbox (:conc-name mailbox.)) + thread + (mutex (mp:make-lock)) + (cvar (mp:make-condition-variable)) + (queue '() :type list)) + + (defun mailbox (thread) + "Return THREAD's mailbox." + (mp:with-lock (*mailbox-lock*) + (or (find thread *mailboxes* :key #'mailbox.thread) + (let ((mb (make-mailbox :thread thread))) + (push mb *mailboxes*) + mb)))) + + (defimplementation send (thread message) + (let* ((mbox (mailbox thread)) + (mutex (mailbox.mutex mbox))) + (mp:with-lock (mutex) + (setf (mailbox.queue mbox) + (nconc (mailbox.queue mbox) (list message))) + (mp:condition-variable-broadcast (mailbox.cvar mbox))))) + + ;; receive + + (defimplementation receive-if (test &optional timeout) + (let* ((mbox (mailbox (current-thread))) + (mutex (mailbox.mutex mbox))) + (assert (or (not timeout) (eq timeout t))) + (loop + (check-slime-interrupts) + (mp:with-lock (mutex) + (let* ((q (mailbox.queue mbox)) + (tail (member-if test q))) + (when tail + (setf (mailbox.queue mbox) (nconc (ldiff q tail) (cdr tail))) + (return (car tail)))) + (when (eq timeout t) (return (values nil t))) + (mp:condition-variable-wait (mailbox.cvar mbox) mutex))))) + + ;; Trigger a call to CHECK-SLIME-INTERRUPTS in THREAD without using + ;; asynchronous interrupts. + ;; + ;; Doesn't have to implement this if RECEIVE-IF periodically calls + ;; CHECK-SLIME-INTERRUPTS, but that's energy inefficient. + ;; + ;; wake-thread (thread) + + ;; Copied from sbcl.lisp and adjusted to ECL. + (let ((alist '()) + (mutex (mp:make-lock :name "register-thread"))) + + (defimplementation register-thread (name thread) + (declare (type symbol name)) + (mp:with-lock (mutex) + (etypecase thread + (null + (setf alist (delete name alist :key #'car))) + (mp:process + (let ((probe (assoc name alist))) + (cond (probe (setf (cdr probe) thread)) + (t (setf alist (acons name thread alist)))))))) + nil) + + (defimplementation find-registered (name) + (mp:with-lock (mutex) + (cdr (assoc name alist))))) + + ;; Not needed in ECL (?). + ;; + ;; set-default-initial-binding (var form) + + ) ; #+threads + +;;; Instead of busy waiting with communication-style NIL, use select() +;;; on the sockets' streams. +#+serve-event +(defimplementation wait-for-input (streams &optional timeout) + (assert (member timeout '(nil t))) + (flet ((poll-streams (streams timeout) + (let* ((serve-event::*descriptor-handlers* + (copy-list serve-event::*descriptor-handlers*)) + (active-fds '()) + (fd-stream-alist + (loop for s in streams + for fd = (socket-fd s) + collect (cons fd s) + do (serve-event:add-fd-handler fd :input + #'(lambda (fd) + (push fd active-fds)))))) + (serve-event:serve-event timeout) + (loop for fd in active-fds collect (cdr (assoc fd fd-stream-alist)))))) + (loop + (cond ((check-slime-interrupts) (return :interrupt)) + (timeout (return (poll-streams streams 0))) + (t + (when-let (ready (poll-streams streams 0.2)) + (return ready))))))) + +#-serve-event +(defimplementation wait-for-input (streams &optional timeout) + (assert (member timeout '(nil t))) + (loop + (cond ((check-slime-interrupts) (return :interrupt)) + (timeout (return (remove-if-not #'listen streams))) + (t + (let ((ready (remove-if-not #'listen streams))) + (if ready (return ready)) + (sleep 0.1)))))) + + +;;;; Locks + +#+threads +(defimplementation make-lock (&key name) + (mp:make-lock :name name :recursive t)) + +(defimplementation call-with-lock-held (lock function) + (declare (type function function)) + (mp:with-lock (lock) (funcall function))) + + +;;;; Weak datastructures + +;;; XXX: this should work but causes SLIME REPL hang at some point of time. May +;;; be ECL or SLIME bug - disabling for now. +#+(and ecl-weak-hash (or)) +(progn + (defimplementation make-weak-key-hash-table (&rest args) + (apply #'make-hash-table :weakness :key args)) + + (defimplementation make-weak-value-hash-table (&rest args) + (apply #'make-hash-table :weakness :value args)) + + (defimplementation hash-table-weakness (hashtable) + (ext:hash-table-weakness hashtable))) + + +;;;; Character names + +;;; Default implementation is fine. +;;; +;;; character-completion-set (prefix matchp) + + +;;;; Heap dumps + +;;; Doesn't apply to ECL. +;;; +;;; save-image (filename &optional restart-function) +;;; background-save-image (filename &key restart-function completion-function) + + +;;;; Wrapping + +;;; Intercept future calls to SPEC and surround them in callbacks. +;;; Very much similar to so-called advices for normal functions. +;;; +;;; wrap (spec indicator &key before after replace) +;;; unwrap (spec indicator) +;;; wrapped-p (spec indicator) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/gray.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/gray.lisp new file mode 100644 index 0000000..3c6c697 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/gray.lisp @@ -0,0 +1,207 @@ +;;;; -*- Mode: lisp; indent-tabs-mode: nil -*- +;;; +;;; swank-gray.lisp --- Gray stream based IO redirection. +;;; +;;; Created 2003 +;;; +;;; This code has been placed in the Public Domain. All warranties +;;; are disclaimed. +;;; + +(in-package swank/backend) + +#.(progn + (defvar *gray-stream-symbols* + '(fundamental-character-output-stream + stream-write-char + stream-write-string + stream-fresh-line + stream-force-output + stream-finish-output + + fundamental-character-input-stream + stream-read-char + stream-peek-char + stream-read-line + stream-listen + stream-unread-char + stream-clear-input + stream-line-column + stream-read-char-no-hang)) + nil) + +(defpackage swank/gray + (:use cl swank/backend) + (:import-from #.(gray-package-name) . #.*gray-stream-symbols*) + (:export . #.*gray-stream-symbols*)) + +(in-package swank/gray) + +(defclass slime-output-stream (fundamental-character-output-stream) + ((output-fn :initarg :output-fn) + (buffer :initform (make-string 8000)) + (fill-pointer :initform 0) + (column :initform 0) + (lock :initform (make-lock :name "buffer write lock")) + (flush-thread :initarg :flush-thread + :initform nil + :accessor flush-thread) + (flush-scheduled :initarg :flush-scheduled + :initform nil + :accessor flush-scheduled))) + +(defun maybe-schedule-flush (stream) + (when (and (flush-thread stream) + (not (flush-scheduled stream))) + (setf (flush-scheduled stream) t) + (send (flush-thread stream) t))) + +(defmacro with-slime-output-stream (stream &body body) + `(with-slots (lock output-fn buffer fill-pointer column) ,stream + (call-with-lock-held lock (lambda () ,@body)))) + +(defmethod stream-write-char ((stream slime-output-stream) char) + (with-slime-output-stream stream + (setf (schar buffer fill-pointer) char) + (incf fill-pointer) + (incf column) + (when (char= #\newline char) + (setf column 0)) + (if (= fill-pointer (length buffer)) + (finish-output stream) + (maybe-schedule-flush stream))) + char) + +(defmethod stream-write-string ((stream slime-output-stream) string + &optional start end) + (with-slime-output-stream stream + (let* ((start (or start 0)) + (end (or end (length string))) + (len (length buffer)) + (count (- end start)) + (free (- len fill-pointer))) + (when (>= count free) + (stream-finish-output stream)) + (cond ((< count len) + (replace buffer string :start1 fill-pointer + :start2 start :end2 end) + (incf fill-pointer count) + (maybe-schedule-flush stream)) + (t + (funcall output-fn (subseq string start end)))) + (let ((last-newline (position #\newline string :from-end t + :start start :end end))) + (setf column (if last-newline + (- end last-newline 1) + (+ column count)))))) + string) + +(defmethod stream-line-column ((stream slime-output-stream)) + (with-slime-output-stream stream column)) + +(defmethod stream-finish-output ((stream slime-output-stream)) + (with-slime-output-stream stream + (unless (zerop fill-pointer) + (funcall output-fn (subseq buffer 0 fill-pointer)) + (setf fill-pointer 0)) + (setf (flush-scheduled stream) nil)) + nil) + +#+(and sbcl sb-thread) +(defmethod stream-force-output :around ((stream slime-output-stream)) + ;; Workaround for deadlocks between the world-lock and auto-flush-thread + ;; buffer write lock. + ;; + ;; Another alternative would be to grab the world-lock here, but that's less + ;; future-proof, and could introduce other lock-ordering issues in the + ;; future. + (handler-case + (sb-sys:with-deadline (:seconds 0.1) + (call-next-method)) + (sb-sys:deadline-timeout () + nil))) + +(defmethod stream-force-output ((stream slime-output-stream)) + (stream-finish-output stream)) + +(defmethod stream-fresh-line ((stream slime-output-stream)) + (with-slime-output-stream stream + (cond ((zerop column) nil) + (t (terpri stream) t)))) + +(defclass slime-input-stream (fundamental-character-input-stream) + ((input-fn :initarg :input-fn) + (buffer :initform "") (index :initform 0) + (lock :initform (make-lock :name "buffer read lock")))) + +(defmethod stream-read-char ((s slime-input-stream)) + (call-with-lock-held + (slot-value s 'lock) + (lambda () + (with-slots (buffer index input-fn) s + (when (= index (length buffer)) + (let ((string (funcall input-fn))) + (cond ((zerop (length string)) + (return-from stream-read-char :eof)) + (t + (setf buffer string) + (setf index 0))))) + (assert (plusp (length buffer))) + (prog1 (aref buffer index) (incf index)))))) + +(defmethod stream-listen ((s slime-input-stream)) + (call-with-lock-held + (slot-value s 'lock) + (lambda () + (with-slots (buffer index) s + (< index (length buffer)))))) + +(defmethod stream-unread-char ((s slime-input-stream) char) + (call-with-lock-held + (slot-value s 'lock) + (lambda () + (with-slots (buffer index) s + (decf index) + (cond ((eql (aref buffer index) char) + (setf (aref buffer index) char)) + (t + (warn "stream-unread-char: ignoring ~S (expected ~S)" + char (aref buffer index))))))) + nil) + +(defmethod stream-clear-input ((s slime-input-stream)) + (call-with-lock-held + (slot-value s 'lock) + (lambda () + (with-slots (buffer index) s + (setf buffer "" + index 0)))) + nil) + +(defmethod stream-line-column ((s slime-input-stream)) + nil) + +(defmethod stream-read-char-no-hang ((s slime-input-stream)) + (call-with-lock-held + (slot-value s 'lock) + (lambda () + (with-slots (buffer index) s + (when (< index (length buffer)) + (prog1 (aref buffer index) (incf index))))))) + + +;;; + +(defimplementation make-auto-flush-thread (stream) + (if (typep stream 'slime-output-stream) + (setf (flush-thread stream) + (spawn (lambda () (auto-flush-loop stream 0.08 t)) + :name "auto-flush-thread")) + (spawn (lambda () (auto-flush-loop stream *auto-flush-interval*)) + :name "auto-flush-thread"))) + +(defimplementation make-output-stream (write-string) + (make-instance 'slime-output-stream :output-fn write-string)) + +(defimplementation make-input-stream (read-string) + (make-instance 'slime-input-stream :input-fn read-string)) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/lispworks.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/lispworks.lisp new file mode 100644 index 0000000..8b2d2ed --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/lispworks.lisp @@ -0,0 +1,1020 @@ +;;; -*- indent-tabs-mode: nil -*- +;;; +;;; swank-lispworks.lisp --- LispWorks specific code for SLIME. +;;; +;;; Created 2003, Helmut Eller +;;; +;;; This code has been placed in the Public Domain. All warranties +;;; are disclaimed. +;;; + +(defpackage swank/lispworks + (:use cl swank/backend)) + +(in-package swank/lispworks) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (require "comm")) + +(defimplementation gray-package-name () + "STREAM") + +(import-swank-mop-symbols :clos '(:slot-definition-documentation + :slot-boundp-using-class + :slot-value-using-class + :slot-makunbound-using-class + :eql-specializer + :eql-specializer-object + :compute-applicable-methods-using-classes)) + +(defun swank-mop:slot-definition-documentation (slot) + (documentation slot t)) + +(defun swank-mop:slot-boundp-using-class (class object slotd) + (clos:slot-boundp-using-class class object + (clos:slot-definition-name slotd))) + +(defun swank-mop:slot-value-using-class (class object slotd) + (clos:slot-value-using-class class object + (clos:slot-definition-name slotd))) + +(defun (setf swank-mop:slot-value-using-class) (value class object slotd) + (setf (clos:slot-value-using-class class object + (clos:slot-definition-name slotd)) + value)) + +(defun swank-mop:slot-makunbound-using-class (class object slotd) + (clos:slot-makunbound-using-class class object + (clos:slot-definition-name slotd))) + +(defun swank-mop:compute-applicable-methods-using-classes (gf classes) + (clos::compute-applicable-methods-from-classes gf classes)) + +;; lispworks doesn't have the eql-specializer class, it represents +;; them as a list of `(EQL ,OBJECT) +(deftype swank-mop:eql-specializer () 'cons) + +(defun swank-mop:eql-specializer-object (eql-spec) + (second eql-spec)) + +(eval-when (:compile-toplevel :execute :load-toplevel) + (defvar *original-defimplementation* (macro-function 'defimplementation)) + (defmacro defimplementation (&whole whole name args &body body + &environment env) + (declare (ignore args body)) + `(progn + (dspec:record-definition '(defun ,name) (dspec:location) + :check-redefinition-p nil) + ,(funcall *original-defimplementation* whole env)))) + +;;; UTF8 + +(defimplementation string-to-utf8 (string) + (ef:encode-lisp-string string '(:utf-8 :eol-style :lf))) + +(defimplementation utf8-to-string (octets) + (ef:decode-external-string octets '(:utf-8 :eol-style :lf))) + +;;; TCP server + +(defimplementation preferred-communication-style () + :spawn) + +(defun socket-fd (socket) + (etypecase socket + (fixnum socket) + (comm:socket-stream (comm:socket-stream-socket socket)))) + +(defimplementation create-socket (host port &key backlog) + (multiple-value-bind (socket where errno) + #-(or lispworks4.1 (and macosx lispworks4.3)) + (comm::create-tcp-socket-for-service port :address host + :backlog (or backlog 5)) + #+(or lispworks4.1 (and macosx lispworks4.3)) + (comm::create-tcp-socket-for-service port) + (cond (socket socket) + (t (error 'network-error + :format-control "~A failed: ~A (~D)" + :format-arguments (list where + (list #+unix (lw:get-unix-error errno)) + errno)))))) + +(defimplementation local-port (socket) + (nth-value 1 (comm:get-socket-address (socket-fd socket)))) + +(defimplementation close-socket (socket) + (comm::close-socket (socket-fd socket))) + +(defimplementation accept-connection (socket + &key external-format buffering timeout) + (declare (ignore buffering)) + (let* ((fd (comm::get-fd-from-socket socket))) + (assert (/= fd -1)) + (cond ((not external-format) + (make-instance 'comm:socket-stream + :socket fd + :direction :io + :read-timeout timeout + :element-type '(unsigned-byte 8))) + (t + (assert (valid-external-format-p external-format)) + (ecase (first external-format) + ((:latin-1 :ascii) + (make-instance 'comm:socket-stream + :socket fd + :direction :io + :read-timeout timeout + :element-type 'base-char)) + (:utf-8 + (make-flexi-stream + (make-instance 'comm:socket-stream + :socket fd + :direction :io + :read-timeout timeout + :element-type '(unsigned-byte 8)) + external-format))))))) + +(defun make-flexi-stream (stream external-format) + (unless (member :flexi-streams *features*) + (error "Cannot use external format ~A~ + without having installed flexi-streams in the inferior-lisp." + external-format)) + (funcall (read-from-string "FLEXI-STREAMS:MAKE-FLEXI-STREAM") + stream + :external-format + (apply (read-from-string "FLEXI-STREAMS:MAKE-EXTERNAL-FORMAT") + external-format))) + +;;; Coding Systems + +(defun valid-external-format-p (external-format) + (member external-format *external-format-to-coding-system* + :test #'equal :key #'car)) + +(defvar *external-format-to-coding-system* + '(((:latin-1 :eol-style :lf) + "latin-1-unix" "iso-latin-1-unix" "iso-8859-1-unix") + ;;((:latin-1) "latin-1" "iso-latin-1" "iso-8859-1") + ;;((:utf-8) "utf-8") + ((:utf-8 :eol-style :lf) "utf-8-unix") + ;;((:euc-jp) "euc-jp") + ((:euc-jp :eol-style :lf) "euc-jp-unix") + ;;((:ascii) "us-ascii") + ((:ascii :eol-style :lf) "us-ascii-unix"))) + +(defimplementation find-external-format (coding-system) + (car (rassoc-if (lambda (x) (member coding-system x :test #'equal)) + *external-format-to-coding-system*))) + +;;; Unix signals + +(defun sigint-handler () + (with-simple-restart (continue "Continue from SIGINT handler.") + (invoke-debugger "SIGINT"))) + +(defun make-sigint-handler (process) + (lambda (&rest args) + (declare (ignore args)) + (mp:process-interrupt process #'sigint-handler))) + +(defun set-sigint-handler () + ;; Set SIGINT handler on Swank request handler thread. + #-win32 + (sys::set-signal-handler +sigint+ + (make-sigint-handler mp:*current-process*))) + +#-win32 +(defimplementation install-sigint-handler (handler) + (sys::set-signal-handler +sigint+ + (let ((self mp:*current-process*)) + (lambda (&rest args) + (declare (ignore args)) + (mp:process-interrupt self handler))))) + +(defimplementation getpid () + #+win32 (win32:get-current-process-id) + #-win32 (system::getpid)) + +(defimplementation lisp-implementation-type-name () + "lispworks") + +(defimplementation set-default-directory (directory) + (namestring (hcl:change-directory directory))) + +;;;; Documentation + +(defun map-list (function list) + "Map over proper and not proper lists." + (loop for (car . cdr) on list + collect (funcall function car) into result + when (null cdr) return result + when (atom cdr) return (nconc result (funcall function cdr)))) + +(defun replace-strings-with-symbols (tree) + (map-list + (lambda (x) + (typecase x + (list + (replace-strings-with-symbols x)) + (symbol + x) + (string + (intern x)) + (t + (intern (write-to-string x))))) + tree)) + +(defimplementation arglist (symbol-or-function) + (let ((arglist (lw:function-lambda-list symbol-or-function))) + (etypecase arglist + ((member :dont-know) + :not-available) + (list + (replace-strings-with-symbols arglist))))) + +(defimplementation function-name (function) + (nth-value 2 (function-lambda-expression function))) + +(defimplementation macroexpand-all (form &optional env) + (declare (ignore env)) + (walker:walk-form form)) + +(defun generic-function-p (object) + (typep object 'generic-function)) + +(defimplementation describe-symbol-for-emacs (symbol) + "Return a plist describing SYMBOL. +Return NIL if the symbol is unbound." + (let ((result '())) + (labels ((first-line (string) + (let ((pos (position #\newline string))) + (if (null pos) string (subseq string 0 pos)))) + (doc (kind &optional (sym symbol)) + (let ((string (or (documentation sym kind)))) + (if string + (first-line string) + :not-documented))) + (maybe-push (property value) + (when value + (setf result (list* property value result))))) + (maybe-push + :variable (when (boundp symbol) + (doc 'variable))) + (maybe-push + :generic-function (if (and (fboundp symbol) + (generic-function-p (fdefinition symbol))) + (doc 'function))) + (maybe-push + :function (if (and (fboundp symbol) + (not (generic-function-p (fdefinition symbol)))) + (doc 'function))) + (maybe-push + :setf (let ((setf-name (sys:underlying-setf-name `(setf ,symbol)))) + (if (fboundp setf-name) + (doc 'setf)))) + (maybe-push + :class (if (find-class symbol nil) + (doc 'class))) + result))) + +(defimplementation describe-definition (symbol type) + (ecase type + (:variable (describe-symbol symbol)) + (:class (describe (find-class symbol))) + ((:function :generic-function) (describe-function symbol)) + (:setf (describe-function (sys:underlying-setf-name `(setf ,symbol)))))) + +(defun describe-function (symbol) + (cond ((fboundp symbol) + (format t "(~A ~/pprint-fill/)~%~%~:[(not documented)~;~:*~A~]~%" + symbol + (lispworks:function-lambda-list symbol) + (documentation symbol 'function)) + (describe (fdefinition symbol))) + (t (format t "~S is not fbound" symbol)))) + +(defun describe-symbol (sym) + (format t "~A is a symbol in package ~A." sym (symbol-package sym)) + (when (boundp sym) + (format t "~%~%Value: ~A" (symbol-value sym))) + (let ((doc (documentation sym 'variable))) + (when doc + (format t "~%~%Variable documentation:~%~A" doc))) + (when (fboundp sym) + (describe-function sym))) + +(defimplementation type-specifier-p (symbol) + (or (ignore-errors + (subtypep nil symbol)) + (not (eq (type-specifier-arglist symbol) :not-available)))) + +;;; Debugging + +(defclass slime-env (env:environment) + ((debugger-hook :initarg :debugger-hoook))) + +(defun slime-env (hook io-bindings) + (make-instance 'slime-env :name "SLIME Environment" + :io-bindings io-bindings + :debugger-hoook hook)) + +(defmethod env-internals:environment-display-notifier + ((env slime-env) &key restarts condition) + (declare (ignore restarts condition)) + (swank:swank-debugger-hook condition *debugger-hook*)) + +(defmethod env-internals:environment-display-debugger ((env slime-env)) + *debug-io*) + +(defmethod env-internals:confirm-p ((e slime-env) &optional msg &rest args) + (apply #'swank:y-or-n-p-in-emacs msg args)) + +(defimplementation call-with-debugger-hook (hook fun) + (let ((*debugger-hook* hook)) + (env:with-environment ((slime-env hook '())) + (funcall fun)))) + +(defimplementation install-debugger-globally (function) + (setq *debugger-hook* function) + (setf (env:environment) (slime-env function '()))) + +(defvar *sldb-top-frame*) + +(defun interesting-frame-p (frame) + (cond ((or (dbg::call-frame-p frame) + (dbg::derived-call-frame-p frame) + (dbg::foreign-frame-p frame) + (dbg::interpreted-call-frame-p frame)) + t) + ((dbg::catch-frame-p frame) dbg:*print-catch-frames*) + ((dbg::binding-frame-p frame) dbg:*print-binding-frames*) + ((dbg::handler-frame-p frame) dbg:*print-handler-frames*) + ((dbg::restart-frame-p frame) dbg:*print-restart-frames*) + (t nil))) + +(defun nth-next-frame (frame n) + "Unwind FRAME N times." + (do ((frame frame (dbg::frame-next frame)) + (i n (if (interesting-frame-p frame) (1- i) i))) + ((or (not frame) + (and (interesting-frame-p frame) (zerop i))) + frame))) + +(defun nth-frame (index) + (nth-next-frame *sldb-top-frame* index)) + +(defun find-top-frame () + "Return the most suitable top-frame for the debugger." + (flet ((find-named-frame (name) + (do ((frame (dbg::debugger-stack-current-frame + dbg::*debugger-stack*) + (nth-next-frame frame 1))) + ((or (null frame) ; no frame found! + (and (dbg::call-frame-p frame) + (eq (dbg::call-frame-function-name frame) + name))) + (nth-next-frame frame 1))))) + (or (find-named-frame 'invoke-debugger) + (find-named-frame 'swank::safe-backtrace) + ;; if we can't find a likely top frame, take any old frame + ;; at the top + (dbg::debugger-stack-current-frame dbg::*debugger-stack*)))) + +(defimplementation call-with-debugging-environment (fn) + (dbg::with-debugger-stack () + (let ((*sldb-top-frame* (find-top-frame))) + (funcall fn)))) + +(defimplementation compute-backtrace (start end) + (let ((end (or end most-positive-fixnum)) + (backtrace '())) + (do ((frame (nth-frame start) (dbg::frame-next frame)) + (i start)) + ((or (not frame) (= i end)) (nreverse backtrace)) + (when (interesting-frame-p frame) + (incf i) + (push frame backtrace))))) + +(defun frame-actual-args (frame) + (let ((*break-on-signals* nil) + (kind nil)) + (loop for arg in (dbg::call-frame-arglist frame) + if (eq kind '&rest) + nconc (handler-case + (dbg::dbg-eval arg frame) + (error (e) (list (format nil "<~A>" arg)))) + and do (loop-finish) + else + if (member arg '(&rest &optional &key)) + do (setq kind arg) + else + nconc + (handler-case + (nconc (and (eq kind '&key) + (list (cond ((symbolp arg) + (intern (symbol-name arg) :keyword)) + ((and (consp arg) (symbolp (car arg))) + (intern (symbol-name (car arg)) + :keyword)) + (t (caar arg))))) + (list (dbg::dbg-eval + (cond ((symbolp arg) arg) + ((and (consp arg) (symbolp (car arg))) + (car arg)) + (t (cadar arg))) + frame))) + (error (e) (list (format nil "<~A>" arg))))))) + +(defimplementation print-frame (frame stream) + (cond ((dbg::call-frame-p frame) + (prin1 (cons (dbg::call-frame-function-name frame) + (frame-actual-args frame)) + stream)) + (t (princ frame stream)))) + +(defun frame-vars (frame) + (first (dbg::frame-locals-format-list frame #'list 75 0))) + +(defimplementation frame-locals (n) + (let ((frame (nth-frame n))) + (if (dbg::call-frame-p frame) + (mapcar (lambda (var) + (destructuring-bind (name value symbol location) var + (declare (ignore name location)) + (list :name symbol :id 0 + :value value))) + (frame-vars frame))))) + +(defimplementation frame-var-value (frame var) + (let ((frame (nth-frame frame))) + (destructuring-bind (_n value _s _l) (nth var (frame-vars frame)) + (declare (ignore _n _s _l)) + value))) + +(defimplementation frame-source-location (frame) + (let ((frame (nth-frame frame)) + (callee (if (plusp frame) (nth-frame (1- frame))))) + (if (dbg::call-frame-p frame) + (let ((dspec (dbg::call-frame-function-name frame)) + (cname (and (dbg::call-frame-p callee) + (dbg::call-frame-function-name callee))) + (path (and (dbg::call-frame-p frame) + (dbg::call-frame-edit-path frame)))) + (if dspec + (frame-location dspec cname path)))))) + +(defimplementation eval-in-frame (form frame-number) + (let ((frame (nth-frame frame-number))) + (dbg::dbg-eval form frame))) + +(defun function-name-package (name) + (typecase name + (null nil) + (symbol (symbol-package name)) + ((cons (eql hcl:subfunction)) + (destructuring-bind (name parent) (cdr name) + (declare (ignore name)) + (function-name-package parent))) + ((cons (eql lw:top-level-form)) nil) + (t nil))) + +(defimplementation frame-package (frame-number) + (let ((frame (nth-frame frame-number))) + (if (dbg::call-frame-p frame) + (function-name-package (dbg::call-frame-function-name frame))))) + +(defimplementation return-from-frame (frame-number form) + (let* ((frame (nth-frame frame-number)) + (return-frame (dbg::find-frame-for-return frame))) + (dbg::dbg-return-from-call-frame frame form return-frame + dbg::*debugger-stack*))) + +(defimplementation restart-frame (frame-number) + (let ((frame (nth-frame frame-number))) + (dbg::restart-frame frame :same-args t))) + +(defimplementation disassemble-frame (frame-number) + (let* ((frame (nth-frame frame-number))) + (when (dbg::call-frame-p frame) + (let ((function (dbg::get-call-frame-function frame))) + (disassemble function))))) + +;;; Definition finding + +(defun frame-location (dspec callee-name edit-path) + (let ((infos (dspec:find-dspec-locations dspec))) + (cond (infos + (destructuring-bind ((rdspec location) &rest _) infos + (declare (ignore _)) + (let ((name (and callee-name (symbolp callee-name) + (string callee-name))) + (path (edit-path-to-cmucl-source-path edit-path))) + (make-dspec-location rdspec location + `(:call-site ,name :edit-path ,path))))) + (t + (list :error (format nil "Source location not available for: ~S" + dspec)))))) + +;; dbg::call-frame-edit-path is not documented but lets assume the +;; binary representation of the integer EDIT-PATH should be +;; interpreted as a sequence of CAR or CDR. #b1111010 is roughly the +;; same as cadadddr. Something is odd with the highest bit. +(defun edit-path-to-cmucl-source-path (edit-path) + (and edit-path + (cons 0 + (let ((n -1)) + (loop for i from (1- (integer-length edit-path)) downto 0 + if (logbitp i edit-path) do (incf n) + else collect (prog1 n (setq n 0))))))) + +;; (edit-path-to-cmucl-source-path #b1111010) => (0 3 1) + +(defimplementation find-definitions (name) + (let ((locations (dspec:find-name-locations dspec:*dspec-classes* name))) + (loop for (dspec location) in locations + collect (list dspec (make-dspec-location dspec location))))) + + +;;; Compilation + +(defmacro with-swank-compilation-unit ((location &rest options) &body body) + (lw:rebinding (location) + `(let ((compiler::*error-database* '())) + (with-compilation-unit ,options + (multiple-value-prog1 (progn ,@body) + (signal-error-data-base compiler::*error-database* + ,location) + (signal-undefined-functions compiler::*unknown-functions* + ,location)))))) + +(defimplementation swank-compile-file (input-file output-file + load-p external-format + &key policy) + (declare (ignore policy)) + (with-swank-compilation-unit (input-file) + (compile-file input-file + :output-file output-file + :load load-p + :external-format external-format))) + +(defvar *within-call-with-compilation-hooks* nil + "Whether COMPILE-FILE was called from within CALL-WITH-COMPILATION-HOOKS.") + +(defvar *undefined-functions-hash* nil + "Hash table to map info about undefined functions to pathnames.") + +(lw:defadvice (compile-file compile-file-and-collect-notes :around) + (pathname &rest rest) + (multiple-value-prog1 (apply #'lw:call-next-advice pathname rest) + (when *within-call-with-compilation-hooks* + (maphash (lambda (unfun dspecs) + (dolist (dspec dspecs) + (let ((unfun-info (list unfun dspec))) + (unless (gethash unfun-info *undefined-functions-hash*) + (setf (gethash unfun-info *undefined-functions-hash*) + pathname))))) + compiler::*unknown-functions*)))) + +(defimplementation call-with-compilation-hooks (function) + (let ((compiler::*error-database* '()) + (*undefined-functions-hash* (make-hash-table :test 'equal)) + (*within-call-with-compilation-hooks* t)) + (with-compilation-unit () + (prog1 (funcall function) + (signal-error-data-base compiler::*error-database*) + (signal-undefined-functions compiler::*unknown-functions*))))) + +(defun map-error-database (database fn) + (loop for (filename . defs) in database do + (loop for (dspec . conditions) in defs do + (dolist (c conditions) + (multiple-value-bind (condition path) + (if (consp c) (values (car c) (cdr c)) (values c nil)) + (funcall fn filename dspec condition path)))))) + +(defun lispworks-severity (condition) + (cond ((not condition) :warning) + (t (etypecase condition + #-(or lispworks4 lispworks5) + (conditions:compiler-note :note) + (error :error) + (style-warning :warning) + (warning :warning))))) + +(defun signal-compiler-condition (message location condition) + (check-type message string) + (signal + (make-instance 'compiler-condition :message message + :severity (lispworks-severity condition) + :location location + :original-condition condition))) + +(defvar *temp-file-format* '(:utf-8 :eol-style :lf)) + +(defun compile-from-temp-file (string filename) + (unwind-protect + (progn + (with-open-file (s filename :direction :output + :if-exists :supersede + :external-format *temp-file-format*) + + (write-string string s) + (finish-output s)) + (multiple-value-bind (binary-filename warnings? failure?) + (compile-file filename :load t + :external-format *temp-file-format*) + (declare (ignore warnings?)) + (when binary-filename + (delete-file binary-filename)) + (not failure?))) + (delete-file filename))) + +(defun dspec-function-name-position (dspec fallback) + (etypecase dspec + (cons (let ((name (dspec:dspec-primary-name dspec))) + (typecase name + ((or symbol string) + (list :function-name (string name))) + (t fallback)))) + (null fallback) + (symbol (list :function-name (string dspec))))) + +(defmacro with-fairly-standard-io-syntax (&body body) + "Like WITH-STANDARD-IO-SYNTAX but preserve *PACKAGE* and *READTABLE*." + (let ((package (gensym)) + (readtable (gensym))) + `(let ((,package *package*) + (,readtable *readtable*)) + (with-standard-io-syntax + (let ((*package* ,package) + (*readtable* ,readtable)) + ,@body))))) + +(defun skip-comments (stream) + (let ((pos0 (file-position stream))) + (cond ((equal (ignore-errors (list (read-delimited-list #\( stream))) + '(())) + (file-position stream (1- (file-position stream)))) + (t (file-position stream pos0))))) + +#-(or lispworks4.1 lispworks4.2) ; no dspec:parse-form-dspec prior to 4.3 +(defun dspec-stream-position (stream dspec) + (with-fairly-standard-io-syntax + (loop (let* ((pos (progn (skip-comments stream) (file-position stream))) + (form (read stream nil '#1=#:eof))) + (when (eq form '#1#) + (return nil)) + (labels ((check-dspec (form) + (when (consp form) + (let ((operator (car form))) + (case operator + ((progn) + (mapcar #'check-dspec + (cdr form))) + ((eval-when locally macrolet symbol-macrolet) + (mapcar #'check-dspec + (cddr form))) + ((in-package) + (let ((package (find-package (second form)))) + (when package + (setq *package* package)))) + (otherwise + (let ((form-dspec (dspec:parse-form-dspec form))) + (when (dspec:dspec-equal dspec form-dspec) + (return pos))))))))) + (check-dspec form)))))) + +(defun dspec-file-position (file dspec) + (let* ((*compile-file-pathname* (pathname file)) + (*compile-file-truename* (truename *compile-file-pathname*)) + (*load-pathname* *compile-file-pathname*) + (*load-truename* *compile-file-truename*)) + (with-open-file (stream file) + (let ((pos + #-(or lispworks4.1 lispworks4.2) + (ignore-errors (dspec-stream-position stream dspec)))) + (if pos + (list :position (1+ pos)) + (dspec-function-name-position dspec `(:position 1))))))) + +(defun emacs-buffer-location-p (location) + (and (consp location) + (eq (car location) :emacs-buffer))) + +(defun make-dspec-location (dspec location &optional hints) + (etypecase location + ((or pathname string) + (multiple-value-bind (file err) + (ignore-errors (namestring (truename location))) + (if err + (list :error (princ-to-string err)) + (make-location `(:file ,file) + (dspec-file-position file dspec) + hints)))) + (symbol + `(:error ,(format nil "Cannot resolve location: ~S" location))) + ((satisfies emacs-buffer-location-p) + (destructuring-bind (_ buffer offset) location + (declare (ignore _)) + (make-location `(:buffer ,buffer) + (dspec-function-name-position dspec `(:offset ,offset 0)) + hints))))) + +(defun make-dspec-progenitor-location (dspec location edit-path) + (let ((canon-dspec (dspec:canonicalize-dspec dspec))) + (make-dspec-location + (if canon-dspec + (if (dspec:local-dspec-p canon-dspec) + (dspec:dspec-progenitor canon-dspec) + canon-dspec) + nil) + location + (if edit-path + (list :edit-path (edit-path-to-cmucl-source-path edit-path)))))) + +(defun signal-error-data-base (database &optional location) + (map-error-database + database + (lambda (filename dspec condition edit-path) + (signal-compiler-condition + (format nil "~A" condition) + (make-dspec-progenitor-location dspec (or location filename) edit-path) + condition)))) + +(defun unmangle-unfun (symbol) + "Converts symbols like 'SETF::|\"CL-USER\" \"GET\"| to +function names like \(SETF GET)." + (cond ((sys::setf-symbol-p symbol) + (sys::setf-pair-from-underlying-name symbol)) + (t symbol))) + +(defun signal-undefined-functions (htab &optional filename) + (maphash (lambda (unfun dspecs) + (dolist (dspec dspecs) + (signal-compiler-condition + (format nil "Undefined function ~A" (unmangle-unfun unfun)) + (make-dspec-progenitor-location + dspec + (or filename + (gethash (list unfun dspec) *undefined-functions-hash*)) + nil) + nil))) + htab)) + +(defimplementation swank-compile-string (string &key buffer position filename + policy) + (declare (ignore filename policy)) + (assert buffer) + (assert position) + (let* ((location (list :emacs-buffer buffer position)) + (tmpname (hcl:make-temp-file nil "lisp"))) + (with-swank-compilation-unit (location) + (compile-from-temp-file + (with-output-to-string (s) + (let ((*print-radix* t)) + (print `(eval-when (:compile-toplevel) + (setq dspec::*location* (list ,@location))) + s)) + (write-string string s)) + tmpname)))) + +;;; xref + +(defmacro defxref (name function) + `(defimplementation ,name (name) + (xref-results (,function name)))) + +(defxref who-calls hcl:who-calls) +(defxref who-macroexpands hcl:who-calls) ; macros are in the calls table too +(defxref calls-who hcl:calls-who) +(defxref list-callers list-callers-internal) +(defxref list-callees list-callees-internal) + +(defun list-callers-internal (name) + (let ((callers (make-array 100 + :fill-pointer 0 + :adjustable t))) + (hcl:sweep-all-objects + #'(lambda (object) + (when (and #+Harlequin-PC-Lisp (low:compiled-code-p object) + #+Harlequin-Unix-Lisp (sys:callablep object) + #-(or Harlequin-PC-Lisp Harlequin-Unix-Lisp) + (sys:compiled-code-p object) + (system::find-constant$funcallable name object)) + (vector-push-extend object callers)))) + ;; Delay dspec:object-dspec until after sweep-all-objects + ;; to reduce allocation problems. + (loop for object across callers + collect (if (symbolp object) + (list 'function object) + (or (dspec:object-dspec object) object))))) + +(defun list-callees-internal (name) + (let ((callees '())) + (system::find-constant$funcallable + 'junk name + :test #'(lambda (junk constant) + (declare (ignore junk)) + (when (and (symbolp constant) + (fboundp constant)) + (pushnew (list 'function constant) callees :test 'equal)) + ;; Return nil so we iterate over all constants. + nil)) + callees)) + +;; only for lispworks 4.2 and above +#-lispworks4.1 +(progn + (defxref who-references hcl:who-references) + (defxref who-binds hcl:who-binds) + (defxref who-sets hcl:who-sets)) + +(defimplementation who-specializes (classname) + (let ((class (find-class classname nil))) + (when class + (let ((methods (clos:class-direct-methods class))) + (xref-results (mapcar #'dspec:object-dspec methods)))))) + +(defun xref-results (dspecs) + (flet ((frob-locs (dspec locs) + (cond (locs + (loop for (name loc) in locs + collect (list name (make-dspec-location name loc)))) + (t `((,dspec (:error "Source location not available"))))))) + (loop for dspec in dspecs + append (frob-locs dspec (dspec:dspec-definition-locations dspec))))) + +;;; Inspector + +(defmethod emacs-inspect ((o t)) + (lispworks-inspect o)) + +(defmethod emacs-inspect ((o function)) + (lispworks-inspect o)) + +;; FIXME: slot-boundp-using-class in LW works with names so we can't +;; use our method in swank.lisp. +(defmethod emacs-inspect ((o standard-object)) + (lispworks-inspect o)) + +(defun lispworks-inspect (o) + (multiple-value-bind (names values _getter _setter type) + (lw:get-inspector-values o nil) + (declare (ignore _getter _setter)) + (append + (label-value-line "Type" type) + (loop for name in names + for value in values + append (label-value-line name value))))) + +;;; Miscellaneous + +(defimplementation quit-lisp () + (lispworks:quit)) + +;;; Tracing + +(defun parse-fspec (fspec) + "Return a dspec for FSPEC." + (ecase (car fspec) + ((:defmethod) `(method ,(cdr fspec))))) + +(defun tracedp (dspec) + (member dspec (eval '(trace)) :test #'equal)) + +(defun toggle-trace-aux (dspec) + (cond ((tracedp dspec) + (eval `(untrace ,dspec)) + (format nil "~S is now untraced." dspec)) + (t + (eval `(trace (,dspec))) + (format nil "~S is now traced." dspec)))) + +(defimplementation toggle-trace (fspec) + (toggle-trace-aux (parse-fspec fspec))) + +;;; Multithreading + +(defimplementation initialize-multiprocessing (continuation) + (cond ((not mp::*multiprocessing*) + (push (list "Initialize SLIME" '() continuation) + mp:*initial-processes*) + (mp:initialize-multiprocessing)) + (t (funcall continuation)))) + +(defimplementation spawn (fn &key name) + (mp:process-run-function name () fn)) + +(defvar *id-lock* (mp:make-lock)) +(defvar *thread-id-counter* 0) + +(defimplementation thread-id (thread) + (mp:with-lock (*id-lock*) + (or (getf (mp:process-plist thread) 'id) + (setf (getf (mp:process-plist thread) 'id) + (incf *thread-id-counter*))))) + +(defimplementation find-thread (id) + (find id (mp:list-all-processes) + :key (lambda (p) (getf (mp:process-plist p) 'id)))) + +(defimplementation thread-name (thread) + (mp:process-name thread)) + +(defimplementation thread-status (thread) + (format nil "~A ~D" + (mp:process-whostate thread) + (mp:process-priority thread))) + +(defimplementation make-lock (&key name) + (mp:make-lock :name name)) + +(defimplementation call-with-lock-held (lock function) + (mp:with-lock (lock) (funcall function))) + +(defimplementation current-thread () + mp:*current-process*) + +(defimplementation all-threads () + (mp:list-all-processes)) + +(defimplementation interrupt-thread (thread fn) + (mp:process-interrupt thread fn)) + +(defimplementation kill-thread (thread) + (mp:process-kill thread)) + +(defimplementation thread-alive-p (thread) + (mp:process-alive-p thread)) + +(defstruct (mailbox (:conc-name mailbox.)) + (mutex (mp:make-lock :name "thread mailbox")) + (queue '() :type list)) + +(defvar *mailbox-lock* (mp:make-lock)) + +(defun mailbox (thread) + (mp:with-lock (*mailbox-lock*) + (or (getf (mp:process-plist thread) 'mailbox) + (setf (getf (mp:process-plist thread) 'mailbox) + (make-mailbox))))) + +(defimplementation receive-if (test &optional timeout) + (let* ((mbox (mailbox mp:*current-process*)) + (lock (mailbox.mutex mbox))) + (assert (or (not timeout) (eq timeout t))) + (loop + (check-slime-interrupts) + (mp:with-lock (lock "receive-if/try") + (let* ((q (mailbox.queue mbox)) + (tail (member-if test q))) + (when tail + (setf (mailbox.queue mbox) (nconc (ldiff q tail) (cdr tail))) + (return (car tail))))) + (when (eq timeout t) (return (values nil t))) + (mp:process-wait-with-timeout + "receive-if" 0.3 (lambda () (some test (mailbox.queue mbox))))))) + +(defimplementation send (thread message) + (let ((mbox (mailbox thread))) + (mp:with-lock ((mailbox.mutex mbox)) + (setf (mailbox.queue mbox) + (nconc (mailbox.queue mbox) (list message)))))) + +(let ((alist '()) + (lock (mp:make-lock :name "register-thread"))) + + (defimplementation register-thread (name thread) + (declare (type symbol name)) + (mp:with-lock (lock) + (etypecase thread + (null + (setf alist (delete name alist :key #'car))) + (mp:process + (let ((probe (assoc name alist))) + (cond (probe (setf (cdr probe) thread)) + (t (setf alist (acons name thread alist)))))))) + nil) + + (defimplementation find-registered (name) + (mp:with-lock (lock) + (cdr (assoc name alist))))) + + +(defimplementation set-default-initial-binding (var form) + (setq mp:*process-initial-bindings* + (acons var `(eval (quote ,form)) + mp:*process-initial-bindings* ))) + +(defimplementation thread-attributes (thread) + (list :priority (mp:process-priority thread) + :idle (mp:process-idle-time thread))) + + +;;;; Weak hashtables + +(defimplementation make-weak-key-hash-table (&rest args) + (apply #'make-hash-table :weak-kind :key args)) + +(defimplementation make-weak-value-hash-table (&rest args) + (apply #'make-hash-table :weak-kind :value args)) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/match.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/match.lisp new file mode 100644 index 0000000..d6200db --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/match.lisp @@ -0,0 +1,242 @@ +;; +;; SELECT-MATCH macro (and IN macro) +;; +;; Copyright 1990 Stephen Adams +;; +;; You are free to copy, distribute and make derivative works of this +;; source provided that this copyright notice is displayed near the +;; beginning of the file. No liability is accepted for the +;; correctness or performance of the code. If you modify the code +;; please indicate this fact both at the place of modification and in +;; this copyright message. +;; +;; Stephen Adams +;; Department of Electronics and Computer Science +;; University of Southampton +;; SO9 5NH, UK +;; +;; sra@ecs.soton.ac.uk +;; + +;; +;; Synopsis: +;; +;; (select-match expression +;; (pattern action+)*) +;; +;; --- or --- +;; +;; (select-match expression +;; pattern => expression +;; pattern => expression +;; ...) +;; +;; pattern -> constant ;egs 1, #\x, #c(1.0 1.1) +;; | symbol ;matches anything +;; | 'anything ;must be EQUAL +;; | (pattern = pattern) ;both patterns must match +;; | (#'function pattern) ;predicate test +;; | (pattern . pattern) ;cons cell +;; + +;; Example +;; +;; (select-match item +;; (('if e1 e2 e3) 'if-then-else) ;(1) +;; ((#'oddp k) 'an-odd-integer) ;(2) +;; (((#'treep tree) = (hd . tl)) 'something-else) ;(3) +;; (other 'anything-else)) ;(4) +;; +;; Notes +;; +;; . Each pattern is tested in turn. The first match is taken. +;; +;; . If no pattern matches, an error is signalled. +;; +;; . Constant patterns (things X for which (CONSTANTP X) is true, i.e. +;; numbers, strings, characters, etc.) match things which are EQUAL. +;; +;; . Quoted patterns (which are CONSTANTP) are constants. +;; +;; . Symbols match anything. The symbol is bound to the matched item +;; for the execution of the actions. +;; For example, (SELECT-MATCH '(1 2 3) +;; (1 . X) => X) +;; returns (2 3) because X is bound to the cdr of the candidate. +;; +;; . The two pattern match (p1 = p2) can be used to name parts +;; of the matched structure. For example, (ALL = (HD . TL)) +;; matches a cons cell. ALL is bound to the cons cell, HD to its car +;; and TL to its tail. +;; +;; . A predicate test applies the predicate to the item being matched. +;; If the predicate returns NIL then the match fails. +;; If it returns truth, then the nested pattern is matched. This is +;; often just a symbol like K in the example. +;; +;; . Care should be taken with the domain values for predicate matches. +;; If, in the above eg, item is not an integer, an error would occur +;; during the test. A safer pattern would be +;; (#'integerp (#'oddp k)) +;; This would only test for oddness of the item was an integer. +;; +;; . A single symbol will match anything so it can be used as a default +;; case, like OTHER above. +;; + +(in-package swank/match) + +(defmacro match (expression &body patterns) + `(select-match ,expression ,@patterns)) + +(defmacro select-match (expression &rest patterns) + (let* ((do-let (not (atom expression))) + (key (if do-let (gensym) expression)) + (cbody (expand-select-patterns key patterns)) + (cform `(cond . ,cbody))) + (if do-let + `(let ((,key ,expression)) ,cform) + cform))) + +(defun expand-select-patterns (key patterns) + (if (eq (second patterns) '=>) + (expand-select-patterns-style-2 key patterns) + (expand-select-patterns-style-1 key patterns))) + +(defun expand-select-patterns-style-1 (key patterns) + (if (null patterns) + `((t (error "Case select pattern match failure on ~S" ,key))) + (let* ((pattern (caar patterns)) + (actions (cdar patterns)) + (rest (cdr patterns)) + (test (compile-select-test key pattern)) + (bindings (compile-select-bindings key pattern actions))) + `(,(if bindings `(,test (let ,bindings . ,actions)) + `(,test . ,actions)) + . ,(unless (eq test t) + (expand-select-patterns-style-1 key rest)))))) + +(defun expand-select-patterns-style-2 (key patterns) + (cond ((null patterns) + `((t (error "Case select pattern match failure on ~S" ,key)))) + (t (when (or (< (length patterns) 3) + (not (eq (second patterns) '=>))) + (error "Illegal patterns: ~S" patterns)) + (let* ((pattern (first patterns)) + (actions (list (third patterns))) + (rest (cdddr patterns)) + (test (compile-select-test key pattern)) + (bindings (compile-select-bindings key pattern actions))) + `(,(if bindings `(,test (let ,bindings . ,actions)) + `(,test . ,actions)) + . ,(unless (eq test t) + (expand-select-patterns-style-2 key rest))))))) + +(defun compile-select-test (key pattern) + (let ((tests (remove t (compile-select-tests key pattern)))) + (cond + ;; note AND does this anyway, but this allows us to tell if + ;; the pattern will always match. + ((null tests) t) + ((= (length tests) 1) (car tests)) + (t `(and . ,tests))))) + +(defun compile-select-tests (key pattern) + (cond ((constantp pattern) `((,(cond ((numberp pattern) 'eql) + ((symbolp pattern) 'eq) + (t 'equal)) + ,key ,pattern))) + ((symbolp pattern) '(t)) + ((select-double-match? pattern) + (append + (compile-select-tests key (first pattern)) + (compile-select-tests key (third pattern)))) + ((select-predicate? pattern) + (append + `((,(second (first pattern)) ,key)) + (compile-select-tests key (second pattern)))) + ((consp pattern) + (append + `((consp ,key)) + (compile-select-tests (cs-car key) (car + pattern)) + (compile-select-tests (cs-cdr key) (cdr + pattern)))) + (t (error "Illegal select pattern: ~S" pattern)))) + + +(defun compile-select-bindings (key pattern action) + (cond ((constantp pattern) '()) + ((symbolp pattern) + (if (select-in-tree pattern action) + `((,pattern ,key)) + '())) + ((select-double-match? pattern) + (append + (compile-select-bindings key (first pattern) action) + (compile-select-bindings key (third pattern) action))) + ((select-predicate? pattern) + (compile-select-bindings key (second pattern) action)) + ((consp pattern) + (append + (compile-select-bindings (cs-car key) (car pattern) + action) + (compile-select-bindings (cs-cdr key) (cdr pattern) + action))))) + +(defun select-in-tree (atom tree) + (or (eq atom tree) + (if (consp tree) + (or (select-in-tree atom (car tree)) + (select-in-tree atom (cdr tree)))))) + +(defun select-double-match? (pattern) + ;; ( = ) + (and (consp pattern) (consp (cdr pattern)) (consp (cddr pattern)) + (null (cdddr pattern)) + (eq (second pattern) '=))) + +(defun select-predicate? (pattern) + ;; ((function ) ) + (and (consp pattern) + (consp (cdr pattern)) + (null (cddr pattern)) + (consp (first pattern)) + (consp (cdr (first pattern))) + (null (cddr (first pattern))) + (eq (caar pattern) 'function))) + +(defun cs-car (exp) + (cs-car/cdr 'car exp + '((car . caar) (cdr . cadr) (caar . caaar) (cadr . caadr) + (cdar . cadar) (cddr . caddr) + (caaar . caaaar) (caadr . caaadr) (cadar . caadar) + (caddr . caaddr) (cdaar . cadaar) (cdadr . cadadr) + (cddar . caddar) (cdddr . cadddr)))) + +(defun cs-cdr (exp) + (cs-car/cdr 'cdr exp + '((car . cdar) (cdr . cddr) (caar . cdaar) (cadr . cdadr) + (cdar . cddar) (cddr . cdddr) + (caaar . cdaaar) (caadr . cdaadr) (cadar . cdadar) + (caddr . cdaddr) (cdaar . cddaar) (cdadr . cddadr) + (cddar . cdddar) (cdddr . cddddr)))) + +(defun cs-car/cdr (op exp table) + (if (and (consp exp) (= (length exp) 2)) + (let ((replacement (assoc (car exp) table))) + (if replacement + `(,(cdr replacement) ,(second exp)) + `(,op ,exp))) + `(,op ,exp))) + +;; (setf c1 '(select-match x (a 1) (b 2 3 4))) +;; (setf c2 '(select-match (car y) +;; (1 (print 100) 101) (2 200) ("hello" 5) (:x 20) (else (1+ +;; else)))) +;; (setf c3 '(select-match (caddr y) +;; ((all = (x y)) (list x y all)) +;; ((a '= b) (list 'assign a b)) +;; ((#'oddp k) (1+ k))))) + + diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/mezzano.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/mezzano.lisp new file mode 100644 index 0000000..b4d8feb --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/mezzano.lisp @@ -0,0 +1,730 @@ +;;;;; -*- indent-tabs-mode: nil -*- +;;; +;;; swank-mezzano.lisp --- SLIME backend for Mezzano +;;; +;;; This code has been placed in the Public Domain. All warranties are +;;; disclaimed. +;;; + +;;; Administrivia + +(defpackage swank/mezzano + (:use cl swank/backend)) + +(in-package swank/mezzano) + +;;; swank-mop + +(import-swank-mop-symbols :mezzano.clos '(:class-default-initargs + :class-direct-default-initargs + :specializer-direct-methods + :generic-function-declarations)) + +(defun swank-mop:specializer-direct-methods (obj) + (declare (ignore obj)) + '()) + +(defun swank-mop:generic-function-declarations (gf) + (declare (ignore gf)) + '()) + +(defimplementation gray-package-name () + "MEZZANO.GRAY") + +;;;; TCP server + +(defclass listen-socket () + ((%host :initarg :host) + (%port :initarg :port) + (%connection-fifo :initarg :connections) + (%callback :initarg :callback))) + +(defimplementation create-socket (host port &key backlog) + (let* ((connections (mezzano.supervisor:make-fifo (or backlog 10))) + (sock (make-instance 'listen-socket + :host host + :port port + :connections connections + :callback (lambda (conn) + (do-connection conn connections)))) + (listen-fn (slot-value sock '%callback))) + (when (find port mezzano.network.tcp::*server-alist* + :key #'first) + (error "Server already listening on port ~D" port)) + (push (list port listen-fn) mezzano.network.tcp::*server-alist*) + sock)) + +(defun do-connection (conn connections) + (when (not (mezzano.supervisor:fifo-push + (make-instance 'mezzano.network.tcp::tcp-stream :connection conn) + connections + nil)) + ;; Drop connections when they can't be handled. + (close conn))) + +(defimplementation local-port (socket) + (slot-value socket '%port)) + +(defimplementation close-socket (socket) + (setf mezzano.network.tcp::*server-alist* + (remove (slot-value socket '%callback) + mezzano.network.tcp::*server-alist* + :key #'second)) + (let ((fifo (slot-value socket '%connection-fifo))) + (loop + (let ((conn (mezzano.supervisor:fifo-pop fifo nil))) + (when (not conn) + (return)) + (close conn)))) + (setf (slot-value socket '%connection-fifo) nil)) + +(defimplementation accept-connection (socket &key external-format + buffering timeout) + (declare (ignore external-format buffering timeout)) + (loop + (let ((value (mezzano.supervisor:fifo-pop + (slot-value socket '%connection-fifo) + nil))) + (when value + (return value))) + ;; Poke standard-input every now and then to keep the console alive. + (listen) + (sleep 0.05))) + +(defimplementation preferred-communication-style () + :spawn) + +;;;; Unix signals +;;;; ???? + +(defimplementation getpid () + 0) + +;;;; Compilation + +(defun signal-compiler-condition (condition severity) + (signal 'compiler-condition + :original-condition condition + :severity severity + :message (format nil "~A" condition) + :location nil)) + +(defimplementation call-with-compilation-hooks (func) + (handler-bind + ((error + (lambda (c) + (signal-compiler-condition c :error))) + (warning + (lambda (c) + (signal-compiler-condition c :warning))) + (style-warning + (lambda (c) + (signal-compiler-condition c :style-warning)))) + (funcall func))) + +(defimplementation swank-compile-string (string &key buffer position filename + policy) + (declare (ignore buffer policy)) + (let* ((*load-pathname* (ignore-errors (pathname filename))) + (*load-truename* (when *load-pathname* + (ignore-errors (truename *load-pathname*)))) + (sys.int::*top-level-form-number* `(:position ,position))) + (with-compilation-hooks () + (eval (read-from-string (concatenate 'string "(progn " string " )"))))) + t) + +(defimplementation swank-compile-file (input-file output-file load-p + external-format + &key policy) + (with-compilation-hooks () + (multiple-value-prog1 + (compile-file input-file + :output-file output-file + :external-format external-format) + (when load-p + (load output-file))))) + +(defimplementation find-external-format (coding-system) + (if (or (equal coding-system "utf-8") + (equal coding-system "utf-8-unix")) + :default + nil)) + +;;;; Debugging + +;; Definitely don't allow this. +(defimplementation install-debugger-globally (function) + (declare (ignore function)) + nil) + +(defvar *current-backtrace*) + +(defimplementation call-with-debugging-environment (debugger-loop-fn) + (let ((*current-backtrace* '())) + (let ((prev-fp nil)) + (sys.int::map-backtrace + (lambda (i fp) + (push (list (1- i) fp prev-fp) *current-backtrace*) + (setf prev-fp fp)))) + (setf *current-backtrace* (reverse *current-backtrace*)) + ;; Drop the topmost frame, which is finished call to MAP-BACKTRACE. + (pop *current-backtrace*) + ;; And the next one for good measure. + (pop *current-backtrace*) + (funcall debugger-loop-fn))) + +(defimplementation compute-backtrace (start end) + (subseq *current-backtrace* start end)) + +(defimplementation print-frame (frame stream) + (format stream "~S" (sys.int::function-from-frame frame))) + +(defimplementation frame-source-location (frame-number) + (let* ((frame (nth frame-number *current-backtrace*)) + (fn (sys.int::function-from-frame frame))) + (function-location fn))) + +(defimplementation frame-locals (frame-number) + (loop + with frame = (nth frame-number *current-backtrace*) + for (name id location repr) in (sys.int::frame-locals frame) + collect (list :name name + :id id + :value (sys.int::read-frame-slot frame location repr)))) + +(defimplementation frame-var-value (frame-number var-id) + (let* ((frame (nth frame-number *current-backtrace*)) + (locals (sys.int::frame-locals frame)) + (info (nth var-id locals))) + (if info + (destructuring-bind (name id location repr) + info + (declare (ignore id)) + (values (sys.int::read-frame-slot frame location repr) name)) + (error "Invalid variable id ~D for frame number ~D." + var-id frame-number)))) + +;;;; Definition finding + +(defun top-level-form-position (pathname tlf) + (ignore-errors + (with-open-file (s pathname) + (loop + repeat tlf + do (with-standard-io-syntax + (let ((*read-suppress* t) + (*read-eval* nil)) + (read s nil)))) + (let ((default (make-pathname :host (pathname-host s)))) + (make-location `(:file ,(enough-namestring s default)) + `(:position ,(1+ (file-position s)))))))) + +(defun function-location (function) + "Return a location object for FUNCTION." + (let* ((info (sys.int::function-debug-info function)) + (pathname (sys.int::debug-info-source-pathname info)) + (tlf (sys.int::debug-info-source-top-level-form-number info))) + (cond ((and (consp tlf) + (eql (first tlf) :position)) + (let ((default (make-pathname :host (pathname-host pathname)))) + (make-location `(:file ,(enough-namestring pathname default)) + `(:position ,(second tlf))))) + (t + (top-level-form-position pathname tlf))))) + +(defun method-definition-name (name method) + `(defmethod ,name + ,@(mezzano.clos:method-qualifiers method) + ,(mapcar (lambda (x) + (typecase x + (mezzano.clos:class + (mezzano.clos:class-name x)) + (mezzano.clos:eql-specializer + `(eql ,(mezzano.clos:eql-specializer-object x))) + (t x))) + (mezzano.clos:method-specializers method)))) + +(defimplementation find-definitions (name) + (let ((result '())) + (labels + ((frob-fn (dspec fn) + (let ((loc (function-location fn))) + (when loc + (push (list dspec loc) result)))) + (try-fn (name) + (when (valid-function-name-p name) + (when (and (fboundp name) + (not (and (symbolp name) + (or (special-operator-p name) + (macro-function name))))) + (let ((fn (fdefinition name))) + (cond ((typep fn 'mezzano.clos:standard-generic-function) + (dolist (m (mezzano.clos:generic-function-methods fn)) + (frob-fn (method-definition-name name m) + (mezzano.clos:method-function m)))) + (t + (frob-fn `(defun ,name) fn))))) + (when (compiler-macro-function name) + (frob-fn `(define-compiler-macro ,name) + (compiler-macro-function name)))))) + (try-fn name) + (try-fn `(setf name)) + (try-fn `(sys.int::cas name)) + (when (and (symbolp name) + (get name 'sys.int::setf-expander)) + (frob-fn `(define-setf-expander ,name) + (get name 'sys.int::setf-expander))) + (when (and (symbolp name) + (macro-function name)) + (frob-fn `(defmacro ,name) + (macro-function name)))) + result)) + +;;;; XREF +;;; Simpler variants. + +(defun find-all-frefs () + (let ((frefs (make-array 500 :adjustable t :fill-pointer 0)) + (keep-going t)) + (loop + (when (not keep-going) + (return)) + (adjust-array frefs (* (array-dimension frefs 0) 2)) + (setf keep-going nil + (fill-pointer frefs) 0) + ;; Walk the wired area looking for FREFs. + (sys.int::walk-area + :wired + (lambda (object address size) + (when (sys.int::function-reference-p object) + (when (not (vector-push object frefs)) + (setf keep-going t)))))) + (remove-duplicates (coerce frefs 'list)))) + +(defimplementation list-callers (function-name) + (let ((fref-for-fn (sys.int::function-reference function-name)) + (callers '())) + (loop + for fref in (find-all-frefs) + for fn = (sys.int::function-reference-function fref) + for name = (sys.int::function-reference-name fref) + when fn + do + (cond ((typep fn 'standard-generic-function) + (dolist (m (mezzano.clos:generic-function-methods fn)) + (let* ((mf (mezzano.clos:method-function m)) + (mf-frefs (get-all-frefs-in-function mf))) + (when (member fref-for-fn mf-frefs) + (push `((defmethod ,name + ,@(mezzano.clos:method-qualifiers m) + ,(mapcar #'specializer-name + (mezzano.clos:method-specializers m))) + ,(function-location mf)) + callers))))) + ((member fref-for-fn + (get-all-frefs-in-function fn)) + (push `((defun ,name) ,(function-location fn)) callers)))) + callers)) + +(defun specializer-name (specializer) + (if (typep specializer 'standard-class) + (mezzano.clos:class-name specializer) + specializer)) + +(defun get-all-frefs-in-function (function) + (when (sys.int::funcallable-std-instance-p function) + (setf function (sys.int::funcallable-std-instance-function function))) + (when (sys.int::closure-p function) + (setf function (sys.int::%closure-function function))) + (loop + for i below (sys.int::function-pool-size function) + for entry = (sys.int::function-pool-object function i) + when (sys.int::function-reference-p entry) + collect entry + when (compiled-function-p entry) ; closures + append (get-all-frefs-in-function entry))) + +(defimplementation list-callees (function-name) + (let* ((fn (fdefinition function-name)) + ;; Grovel around in the function's constant pool looking for + ;; function-references. These may be for #', but they're + ;; probably going to be for normal calls. + ;; TODO: This doesn't work well on interpreted functions or + ;; funcallable instances. + (callees (remove-duplicates (get-all-frefs-in-function fn)))) + (loop + for fref in callees + for name = (sys.int::function-reference-name fref) + for fn = (sys.int::function-reference-function fref) + when fn + collect `((defun ,name) ,(function-location fn))))) + +;;;; Documentation + +(defimplementation arglist (name) + (let ((macro (when (symbolp name) + (macro-function name))) + (fn (if (functionp name) + name + (ignore-errors (fdefinition name))))) + (cond + (macro + (get name 'sys.int::macro-lambda-list)) + (fn + (cond + ((typep fn 'mezzano.clos:standard-generic-function) + (mezzano.clos:generic-function-lambda-list fn)) + (t + (function-lambda-list fn)))) + (t :not-available)))) + +(defun function-lambda-list (function) + (sys.int::debug-info-lambda-list + (sys.int::function-debug-info function))) + +(defimplementation type-specifier-p (symbol) + (cond + ((or (get symbol 'sys.int::type-expander) + (get symbol 'sys.int::compound-type) + (get symbol 'sys.int::type-symbol)) + t) + (t :not-available))) + +(defimplementation function-name (function) + (sys.int::function-name function)) + +(defimplementation valid-function-name-p (form) + "Is FORM syntactically valid to name a function? + If true, FBOUNDP should not signal a type-error for FORM." + (flet ((length=2 (list) + (and (not (null (cdr list))) (null (cddr list))))) + (or (symbolp form) + (and (consp form) (length=2 form) + (or (eq (first form) 'setf) + (eq (first form) 'sys.int::cas)) + (symbolp (second form)))))) + +(defimplementation describe-symbol-for-emacs (symbol) + (let ((result '())) + (when (boundp symbol) + (setf (getf result :variable) nil)) + (when (and (fboundp symbol) + (not (macro-function symbol))) + (setf (getf result :function) + (function-docstring symbol))) + (when (fboundp `(setf ,symbol)) + (setf (getf result :setf) + (function-docstring `(setf ,symbol)))) + (when (get symbol 'sys.int::setf-expander) + (setf (getf result :setf) nil)) + (when (special-operator-p symbol) + (setf (getf result :special-operator) nil)) + (when (macro-function symbol) + (setf (getf result :macro) nil)) + (when (compiler-macro-function symbol) + (setf (getf result :compiler-macro) nil)) + (when (type-specifier-p symbol) + (setf (getf result :type) nil)) + (when (find-class symbol nil) + (setf (getf result :class) nil)) + result)) + +(defun function-docstring (function-name) + (let* ((definition (fdefinition function-name)) + (debug-info (sys.int::function-debug-info definition))) + (sys.int::debug-info-docstring debug-info))) + +;;;; Multithreading + +;; FIXME: This should be a weak table. +(defvar *thread-ids-for-emacs* (make-hash-table)) +(defvar *next-thread-id-for-emacs* 0) +(defvar *thread-id-for-emacs-lock* (mezzano.supervisor:make-mutex + "SWANK thread ID table")) + +(defimplementation spawn (fn &key name) + (mezzano.supervisor:make-thread fn :name name)) + +(defimplementation thread-id (thread) + (mezzano.supervisor:with-mutex (*thread-id-for-emacs-lock*) + (let ((id (gethash thread *thread-ids-for-emacs*))) + (when (null id) + (setf id (incf *next-thread-id-for-emacs*) + (gethash thread *thread-ids-for-emacs*) id + (gethash id *thread-ids-for-emacs*) thread)) + id))) + +(defimplementation find-thread (id) + (mezzano.supervisor:with-mutex (*thread-id-for-emacs-lock*) + (gethash id *thread-ids-for-emacs*))) + +(defimplementation thread-name (thread) + (mezzano.supervisor:thread-name thread)) + +(defimplementation thread-status (thread) + (format nil "~:(~A~)" (mezzano.supervisor:thread-state thread))) + +(defimplementation current-thread () + (mezzano.supervisor:current-thread)) + +(defimplementation all-threads () + (mezzano.supervisor:all-threads)) + +(defimplementation thread-alive-p (thread) + (not (eql (mezzano.supervisor:thread-state thread) :dead))) + +(defimplementation interrupt-thread (thread fn) + (mezzano.supervisor:establish-thread-foothold thread fn)) + +(defimplementation kill-thread (thread) + ;; Documentation says not to execute unwind-protected sections, but there's + ;; no way to do that. + ;; And killing threads at arbitrary points without unwinding them is a good + ;; way to hose the system. + (mezzano.supervisor:terminate-thread thread)) + +(defvar *mailbox-lock* (mezzano.supervisor:make-mutex "mailbox lock")) +(defvar *mailboxes* (list)) + +(defstruct (mailbox (:conc-name mailbox.)) + thread + (mutex (mezzano.supervisor:make-mutex)) + (queue '() :type list)) + +(defun mailbox (thread) + "Return THREAD's mailbox." + ;; Use weak pointers to avoid holding on to dead threads forever. + (mezzano.supervisor:with-mutex (*mailbox-lock*) + ;; Flush forgotten threads. + (setf *mailboxes* + (remove-if-not #'sys.int::weak-pointer-value *mailboxes*)) + (loop + for entry in *mailboxes* + do + (multiple-value-bind (key value livep) + (sys.int::weak-pointer-pair entry) + (when (eql key thread) + (return value))) + finally + (let ((mb (make-mailbox :thread thread))) + (push (sys.int::make-weak-pointer thread mb) *mailboxes*) + (return mb))))) + +(defimplementation send (thread message) + (let* ((mbox (mailbox thread)) + (mutex (mailbox.mutex mbox))) + (mezzano.supervisor:with-mutex (mutex) + (setf (mailbox.queue mbox) + (nconc (mailbox.queue mbox) (list message)))))) + +(defvar *receive-if-sleep-time* 0.02) + +(defimplementation receive-if (test &optional timeout) + (let* ((mbox (mailbox (current-thread))) + (mutex (mailbox.mutex mbox))) + (assert (or (not timeout) (eq timeout t))) + (loop + (check-slime-interrupts) + (mezzano.supervisor:with-mutex (mutex) + (let* ((q (mailbox.queue mbox)) + (tail (member-if test q))) + (when tail + (setf (mailbox.queue mbox) (nconc (ldiff q tail) (cdr tail))) + (return (car tail)))) + (when (eq timeout t) (return (values nil t)))) + (sleep *receive-if-sleep-time*)))) + +(defvar *registered-threads* (make-hash-table)) +(defvar *registered-threads-lock* + (mezzano.supervisor:make-mutex "registered threads lock")) + +(defimplementation register-thread (name thread) + (declare (type symbol name)) + (mezzano.supervisor:with-mutex (*registered-threads-lock*) + (etypecase thread + (null + (remhash name *registered-threads*)) + (mezzano.supervisor:thread + (setf (gethash name *registered-threads*) thread)))) + nil) + +(defimplementation find-registered (name) + (mezzano.supervisor:with-mutex (*registered-threads-lock*) + (values (gethash name *registered-threads*)))) + +(defimplementation wait-for-input (streams &optional timeout) + (loop + (let ((ready '())) + (dolist (s streams) + (when (or (listen s) + (and (typep s 'mezzano.network.tcp::tcp-stream) + (mezzano.network.tcp::tcp-connection-closed-p s))) + (push s ready))) + (when ready + (return ready)) + (when (check-slime-interrupts) + (return :interrupt)) + (when timeout + (return '())) + (sleep 1) + (when (numberp timeout) + (decf timeout 1) + (when (not (plusp timeout)) + (return '())))))) + +;;;; Locks + +(defstruct recursive-lock + mutex + (depth 0)) + +(defimplementation make-lock (&key name) + (make-recursive-lock + :mutex (mezzano.supervisor:make-mutex name))) + +(defimplementation call-with-lock-held (lock function) + (cond ((mezzano.supervisor:mutex-held-p + (recursive-lock-mutex lock)) + (unwind-protect + (progn (incf (recursive-lock-depth lock)) + (funcall function)) + (decf (recursive-lock-depth lock)))) + (t + (mezzano.supervisor:with-mutex ((recursive-lock-mutex lock)) + (multiple-value-prog1 + (funcall function) + (assert (eql (recursive-lock-depth lock) 0))))))) + +;;;; Character names + +(defimplementation character-completion-set (prefix matchp) + ;; TODO: Unicode characters too. + (loop + for names in sys.int::*char-name-alist* + append + (loop + for name in (rest names) + when (funcall matchp prefix name) + collect name))) + +;;;; Inspector + +(defmethod emacs-inspect ((o function)) + (case (sys.int::%object-tag o) + (#.sys.int::+object-tag-function+ + (label-value-line* + (:name (sys.int::function-name o)) + (:arglist (arglist o)) + (:debug-info (sys.int::function-debug-info o)))) + (#.sys.int::+object-tag-closure+ + (append + (label-value-line :function (sys.int::%closure-function o)) + `("Closed over values:" (:newline)) + (loop + for i below (sys.int::%closure-length o) + append (label-value-line i (sys.int::%closure-value o i))))) + (t + (call-next-method)))) + +(defmethod emacs-inspect ((o sys.int::weak-pointer)) + (label-value-line* + (:key (sys.int::weak-pointer-key o)) + (:value (sys.int::weak-pointer-value o)))) + +(defmethod emacs-inspect ((o sys.int::function-reference)) + (label-value-line* + (:name (sys.int::function-reference-name o)) + (:function (sys.int::function-reference-function o)))) + +(defmethod emacs-inspect ((object structure-object)) + (let ((class (class-of object))) + `("Class: " (:value ,class) (:newline) + ,@(swank::all-slots-for-inspector object)))) + +(in-package :swank) + +(defmethod all-slots-for-inspector ((object structure-object)) + (let* ((class (class-of object)) + (direct-slots (swank-mop:class-direct-slots class)) + (effective-slots (swank-mop:class-slots class)) + (longest-slot-name-length + (loop for slot :in effective-slots + maximize (length (symbol-name + (swank-mop:slot-definition-name slot))))) + (checklist + (reinitialize-checklist + (ensure-istate-metadata object :checklist + (make-checklist (length effective-slots))))) + (grouping-kind + ;; We box the value so we can re-set it. + (ensure-istate-metadata object :grouping-kind + (box *inspector-slots-default-grouping*))) + (sort-order + (ensure-istate-metadata object :sort-order + (box *inspector-slots-default-order*))) + (sort-predicate (ecase (ref sort-order) + (:alphabetically #'string<) + (:unsorted (constantly nil)))) + (sorted-slots (sort (copy-seq effective-slots) + sort-predicate + :key #'swank-mop:slot-definition-name)) + (effective-slots + (ecase (ref grouping-kind) + (:all sorted-slots) + (:inheritance (stable-sort-by-inheritance sorted-slots + class sort-predicate))))) + `("--------------------" + (:newline) + " Group slots by inheritance " + (:action ,(ecase (ref grouping-kind) + (:all "[ ]") + (:inheritance "[X]")) + ,(lambda () + ;; We have to do this as the order of slots will + ;; be sorted differently. + (fill (checklist.buttons checklist) nil) + (setf (ref grouping-kind) + (ecase (ref grouping-kind) + (:all :inheritance) + (:inheritance :all)))) + :refreshp t) + (:newline) + " Sort slots alphabetically " + (:action ,(ecase (ref sort-order) + (:unsorted "[ ]") + (:alphabetically "[X]")) + ,(lambda () + (fill (checklist.buttons checklist) nil) + (setf (ref sort-order) + (ecase (ref sort-order) + (:unsorted :alphabetically) + (:alphabetically :unsorted)))) + :refreshp t) + (:newline) + ,@ (case (ref grouping-kind) + (:all + `((:newline) + "All Slots:" + (:newline) + ,@(make-slot-listing checklist object class + effective-slots direct-slots + longest-slot-name-length))) + (:inheritance + (list-all-slots-by-inheritance checklist object class + effective-slots direct-slots + longest-slot-name-length))) + (:newline) + (:action "[set value]" + ,(lambda () + (do-checklist (idx checklist) + (query-and-set-slot class object + (nth idx effective-slots)))) + :refreshp t) + " " + (:action "[make unbound]" + ,(lambda () + (do-checklist (idx checklist) + (swank-mop:slot-makunbound-using-class + class object (nth idx effective-slots)))) + :refreshp t) + (:newline)))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/mkcl.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/mkcl.lisp new file mode 100644 index 0000000..53696fb --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/mkcl.lisp @@ -0,0 +1,933 @@ +;;;; -*- indent-tabs-mode: nil -*- +;;; +;;; swank-mkcl.lisp --- SLIME backend for MKCL. +;;; +;;; This code has been placed in the Public Domain. All warranties +;;; are disclaimed. +;;; + +;;; Administrivia + +(defpackage swank/mkcl + (:use cl swank/backend)) + +(in-package swank/mkcl) + +;;(declaim (optimize (debug 3))) + +(defvar *tmp*) + +(defimplementation gray-package-name () + '#:gray) + +(eval-when (:compile-toplevel :load-toplevel) + + (swank/backend::import-swank-mop-symbols :clos + ;; '(:eql-specializer + ;; :eql-specializer-object + ;; :generic-function-declarations + ;; :specializer-direct-methods + ;; :compute-applicable-methods-using-classes) + nil + )) + + +;;; UTF8 + +(defimplementation string-to-utf8 (string) + (mkcl:octets (si:utf-8 string))) + +(defimplementation utf8-to-string (octets) + (string (si:utf-8 octets))) + + +;;;; TCP Server + +(eval-when (:compile-toplevel :load-toplevel) + ;; At compile-time we need access to the sb-bsd-sockets package for the + ;; the following code to be read properly. + ;; It is a bit a shame we have to load the entire module to get that. + (require 'sockets)) + + +(defun resolve-hostname (name) + (car (sb-bsd-sockets:host-ent-addresses + (sb-bsd-sockets:get-host-by-name name)))) + +(defimplementation create-socket (host port &key backlog) + (let ((socket (make-instance 'sb-bsd-sockets:inet-socket + :type :stream + :protocol :tcp))) + (setf (sb-bsd-sockets:sockopt-reuse-address socket) t) + (sb-bsd-sockets:socket-bind socket (resolve-hostname host) port) + (sb-bsd-sockets:socket-listen socket (or backlog 5)) + socket)) + +(defimplementation local-port (socket) + (nth-value 1 (sb-bsd-sockets:socket-name socket))) + +(defimplementation close-socket (socket) + (sb-bsd-sockets:socket-close socket)) + +(defun accept (socket) + "Like socket-accept, but retry on EINTR." + (loop (handler-case + (return (sb-bsd-sockets:socket-accept socket)) + (sb-bsd-sockets:interrupted-error ())))) + +(defimplementation accept-connection (socket + &key external-format + buffering timeout) + (declare (ignore timeout)) + (sb-bsd-sockets:socket-make-stream (accept socket) + :output t ;; bogus + :input t ;; bogus + :buffering buffering ;; bogus + :element-type (if external-format + 'character + '(unsigned-byte 8)) + :external-format external-format + )) + +(defimplementation preferred-communication-style () + :spawn + ) + +(defvar *external-format-to-coding-system* + '((:iso-8859-1 + "latin-1" "latin-1-unix" "iso-latin-1-unix" + "iso-8859-1" "iso-8859-1-unix") + (:utf-8 "utf-8" "utf-8-unix"))) + +(defun external-format (coding-system) + (or (car (rassoc-if (lambda (x) (member coding-system x :test #'equal)) + *external-format-to-coding-system*)) + (find coding-system (si:all-encodings) :test #'string-equal))) + +(defimplementation find-external-format (coding-system) + #+unicode (external-format coding-system) + ;; Without unicode support, MKCL uses the one-byte encoding of the + ;; underlying OS, and will barf on anything except :DEFAULT. We + ;; return NIL here for known multibyte encodings, so + ;; SWANK:CREATE-SERVER will barf. + #-unicode (let ((xf (external-format coding-system))) + (if (member xf '(:utf-8)) + nil + :default))) + + + +;;;; Unix signals + +(defimplementation install-sigint-handler (handler) + (let ((old-handler (symbol-function 'si:terminal-interrupt))) + (setf (symbol-function 'si:terminal-interrupt) + (if (consp handler) + (car handler) + (lambda (&rest args) + (declare (ignore args)) + (funcall handler) + (continue)))) + (list old-handler))) + + +(defimplementation getpid () + (mkcl:getpid)) + +(defimplementation set-default-directory (directory) + (mk-ext::chdir (namestring directory)) + (default-directory)) + +(defimplementation default-directory () + (namestring (mk-ext:getcwd))) + +(defmacro progf (plist &rest forms) + `(let (_vars _vals) + (do ((p ,plist (cddr p))) + ((endp p)) + (push (car p) _vars) + (push (cadr p) _vals)) + (progv _vars _vals ,@forms) + ) + ) + +(defvar *inferior-lisp-sleeping-post* nil) + +(defimplementation quit-lisp () + (progf (ignore-errors (eval (read-from-string "swank::*saved-global-streams*"))) ;; restore original IO streams. + (when *inferior-lisp-sleeping-post* (mt:semaphore-signal *inferior-lisp-sleeping-post*)) + ;;(mk-ext:quit :verbose t) + )) + + +;;;; Compilation + +(defvar *buffer-name* nil) +(defvar *buffer-start-position*) +(defvar *buffer-string*) +(defvar *compile-filename*) + +(defun signal-compiler-condition (&rest args) + (signal (apply #'make-condition 'compiler-condition args))) + +#| +(defun handle-compiler-warning (condition) + (signal-compiler-condition + :original-condition condition + :message (format nil "~A" condition) + :severity :warning + :location + (if *buffer-name* + (make-location (list :buffer *buffer-name*) + (list :offset *buffer-start-position* 0)) + ;; ;; compiler::*current-form* + ;; (if compiler::*current-function* + ;; (make-location (list :file *compile-filename*) + ;; (list :function-name + ;; (symbol-name + ;; (slot-value compiler::*current-function* + ;; 'compiler::name)))) + (list :error "No location found.") + ;; ) + ))) +|# + +#| +(defun condition-location (condition) + (let ((file (compiler:compiler-message-file condition)) + (position (compiler:compiler-message-file-position condition))) + (if (and position (not (minusp position))) + (if *buffer-name* + (make-buffer-location *buffer-name* + *buffer-start-position* + position) + (make-file-location file position)) + (make-error-location "No location found.")))) +|# + +(defun condition-location (condition) + (if *buffer-name* + (make-location (list :buffer *buffer-name*) + (list :offset *buffer-start-position* 0)) + ;; ;; compiler::*current-form* ; + ;; (if compiler::*current-function* ; + ;; (make-location (list :file *compile-filename*) ; + ;; (list :function-name ; + ;; (symbol-name ; + ;; (slot-value compiler::*current-function* ; + ;; 'compiler::name)))) ; + (if (typep condition 'compiler::compiler-message) + (make-location (list :file (namestring (compiler:compiler-message-file condition))) + (list :end-position (compiler:compiler-message-file-end-position condition))) + (list :error "No location found.")) + ) + ) + +(defun handle-compiler-message (condition) + (unless (typep condition 'compiler::compiler-note) + (signal-compiler-condition + :original-condition condition + :message (princ-to-string condition) + :severity (etypecase condition + (compiler:compiler-fatal-error :error) + (compiler:compiler-error :error) + (error :error) + (style-warning :style-warning) + (warning :warning)) + :location (condition-location condition)))) + +(defimplementation call-with-compilation-hooks (function) + (handler-bind ((compiler:compiler-message #'handle-compiler-message)) + (funcall function))) + +(defimplementation swank-compile-file (input-file output-file + load-p external-format + &key policy) + (declare (ignore policy)) + (with-compilation-hooks () + (let ((*buffer-name* nil) + (*compile-filename* input-file)) + (handler-bind (#| + (compiler::compiler-note + #'(lambda (n) + (format t "~%swank saw a compiler note: ~A~%" n) (finish-output) nil)) + (compiler::compiler-warning + #'(lambda (w) + (format t "~%swank saw a compiler warning: ~A~%" w) (finish-output) nil)) + (compiler::compiler-error + #'(lambda (e) + (format t "~%swank saw a compiler error: ~A~%" e) (finish-output) nil)) + |# + ) + (multiple-value-bind (output-truename warnings-p failure-p) + (compile-file input-file :output-file output-file :external-format external-format) + (values output-truename warnings-p + (or failure-p + (and load-p (not (load output-truename)))))))))) + +(defimplementation swank-compile-string (string &key buffer position filename policy) + (declare (ignore filename policy)) + (with-compilation-hooks () + (let ((*buffer-name* buffer) + (*buffer-start-position* position) + (*buffer-string* string)) + (with-input-from-string (s string) + (when position (file-position position)) + (compile-from-stream s))))) + +(defun compile-from-stream (stream) + (let ((file (mkcl:mkstemp "TMP:MKCL-SWANK-TMPXXXXXX")) + output-truename + warnings-p + failure-p + ) + (with-open-file (s file :direction :output :if-exists :overwrite) + (do ((line (read-line stream nil) (read-line stream nil))) + ((not line)) + (write-line line s))) + (unwind-protect + (progn + (multiple-value-setq (output-truename warnings-p failure-p) + (compile-file file)) + (and (not failure-p) (load output-truename))) + (when (probe-file file) (delete-file file)) + (when (probe-file output-truename) (delete-file output-truename))))) + + +;;;; Documentation + +(defun grovel-docstring-for-arglist (name type) + (flet ((compute-arglist-offset (docstring) + (when docstring + (let ((pos1 (search "Args: " docstring))) + (if pos1 + (+ pos1 6) + (let ((pos2 (search "Syntax: " docstring))) + (when pos2 + (+ pos2 8)))))))) + (let* ((docstring (si::get-documentation name type)) + (pos (compute-arglist-offset docstring))) + (if pos + (multiple-value-bind (arglist errorp) + (ignore-errors + (values (read-from-string docstring t nil :start pos))) + (if (or errorp (not (listp arglist))) + :not-available + arglist + )) + :not-available )))) + +(defimplementation arglist (name) + (cond ((and (symbolp name) (special-operator-p name)) + (let ((arglist (grovel-docstring-for-arglist name 'function))) + (if (consp arglist) (cdr arglist) arglist))) + ((and (symbolp name) (macro-function name)) + (let ((arglist (grovel-docstring-for-arglist name 'function))) + (if (consp arglist) (cdr arglist) arglist))) + ((or (functionp name) (fboundp name)) + (multiple-value-bind (name fndef) + (if (functionp name) + (values (function-name name) name) + (values name (fdefinition name))) + (let ((fle (function-lambda-expression fndef))) + (case (car fle) + (si:lambda-block (caddr fle)) + (t (typecase fndef + (generic-function (clos::generic-function-lambda-list fndef)) + (compiled-function (grovel-docstring-for-arglist name 'function)) + (function :not-available))))))) + (t :not-available))) + +(defimplementation function-name (f) + (si:compiled-function-name f) + ) + +(eval-when (:compile-toplevel :load-toplevel) + ;; At compile-time we need access to the walker package for the + ;; the following code to be read properly. + ;; It is a bit a shame we have to load the entire module to get that. + (require 'walker)) + +(defimplementation macroexpand-all (form &optional env) + (declare (ignore env)) + (walker:macroexpand-all form)) + +(defimplementation describe-symbol-for-emacs (symbol) + (let ((result '())) + (dolist (type '(:VARIABLE :FUNCTION :CLASS)) + (let ((doc (describe-definition symbol type))) + (when doc + (setf result (list* type doc result))))) + result)) + +(defimplementation describe-definition (name type) + (case type + (:variable (documentation name 'variable)) + (:function (documentation name 'function)) + (:class (documentation name 'class)) + (t nil))) + +;;; Debugging + +(eval-when (:compile-toplevel :load-toplevel) + (import + '(si::*break-env* + si::*ihs-top* + si::*ihs-current* + si::*ihs-base* + si::*frs-base* + si::*frs-top* + si::*tpl-commands* + si::*tpl-level* + si::frs-top + si::ihs-top + si::ihs-fun + si::ihs-env + si::sch-frs-base + si::set-break-env + si::set-current-ihs + si::tpl-commands))) + +(defvar *backtrace* '()) + +(defun in-swank-package-p (x) + (and + (symbolp x) + (member (symbol-package x) + (list #.(find-package :swank) + #.(find-package :swank/backend) + #.(ignore-errors (find-package :swank-mop)) + #.(ignore-errors (find-package :swank-loader)))) + t)) + +(defun is-swank-source-p (name) + (setf name (pathname name)) + #+(or) + (pathname-match-p + name + (make-pathname :defaults swank-loader::*source-directory* + :name (pathname-name name) + :type (pathname-type name) + :version (pathname-version name))) + nil) + +(defun is-ignorable-fun-p (x) + (or + (in-swank-package-p (frame-name x)) + (multiple-value-bind (file position) + (ignore-errors (si::compiled-function-file (car x))) + (declare (ignore position)) + (if file (is-swank-source-p file))))) + +(defmacro find-ihs-top (x) + (declare (ignore x)) + '(si::ihs-top)) + +(defimplementation call-with-debugging-environment (debugger-loop-fn) + (declare (type function debugger-loop-fn)) + (let* (;;(*tpl-commands* si::tpl-commands) + (*ihs-base* 0) + (*ihs-top* (find-ihs-top 'call-with-debugging-environment)) + (*ihs-current* *ihs-top*) + (*frs-base* (or (sch-frs-base 0 #|*frs-top*|# *ihs-base*) (1+ (frs-top)))) + (*frs-top* (frs-top)) + (*read-suppress* nil) + ;;(*tpl-level* (1+ *tpl-level*)) + (*backtrace* (loop for ihs from 0 below *ihs-top* + collect (list (si::ihs-fun ihs) + (si::ihs-env ihs) + nil)))) + (declare (special *ihs-current*)) + (loop for f from *frs-base* to *frs-top* + do (let ((i (- (si::frs-ihs f) *ihs-base* 1))) + (when (plusp i) + (let* ((x (elt *backtrace* i)) + (name (si::frs-tag f))) + (unless (mkcl:fixnump name) + (push name (third x))))))) + (setf *backtrace* (remove-if #'is-ignorable-fun-p (nreverse *backtrace*))) + (setf *tmp* *backtrace*) + (set-break-env) + (set-current-ihs) + (let ((*ihs-base* *ihs-top*)) + (funcall debugger-loop-fn)))) + +(defimplementation call-with-debugger-hook (hook fun) + (let ((*debugger-hook* hook) + (*ihs-base* (find-ihs-top 'call-with-debugger-hook))) + (funcall fun))) + +(defimplementation compute-backtrace (start end) + (when (numberp end) + (setf end (min end (length *backtrace*)))) + (loop for f in (subseq *backtrace* start end) + collect f)) + +(defimplementation format-sldb-condition (condition) + "Format a condition for display in SLDB." + ;;(princ-to-string condition) + (format nil "~A~%In thread: ~S" condition mt:*thread*) + ) + +(defun frame-name (frame) + (let ((x (first frame))) + (if (symbolp x) + x + (function-name x)))) + +(defun function-position (fun) + (multiple-value-bind (file position) + (si::compiled-function-file fun) + (and file (make-location + `(:file ,(if (stringp file) file (namestring file))) + ;;`(:position ,position) + `(:end-position , position))))) + +(defun frame-function (frame) + (let* ((x (first frame)) + fun position) + (etypecase x + (symbol (and (fboundp x) + (setf fun (fdefinition x) + position (function-position fun)))) + (function (setf fun x position (function-position x)))) + (values fun position))) + +(defun frame-decode-env (frame) + (let ((functions '()) + (blocks '()) + (variables '())) + (setf frame (si::decode-ihs-env (second frame))) + (dolist (record frame) + (let* ((record0 (car record)) + (record1 (cdr record))) + (cond ((or (symbolp record0) (stringp record0)) + (setq variables (acons record0 record1 variables))) + ((not (mkcl:fixnump record0)) + (push record1 functions)) + ((symbolp record1) + (push record1 blocks)) + (t + )))) + (values functions blocks variables))) + +(defimplementation print-frame (frame stream) + (let ((function (first frame))) + (let ((fname +;;; (cond ((symbolp function) function) +;;; ((si:instancep function) (slot-value function 'name)) +;;; ((compiled-function-p function) +;;; (or (si::compiled-function-name function) 'lambda)) +;;; (t :zombi)) + (si::get-fname function) + )) + (if (eq fname 'si::bytecode) + (format stream "~A [Evaluation of: ~S]" + fname (function-lambda-expression function)) + (format stream "~A" fname) + ) + (when (si::closurep function) + (format stream + ", closure generated from ~A" + (si::get-fname (si:closure-producer function))) + ) + ) + ) + ) + +(defimplementation frame-source-location (frame-number) + (nth-value 1 (frame-function (elt *backtrace* frame-number)))) + +(defimplementation frame-catch-tags (frame-number) + (third (elt *backtrace* frame-number))) + +(defimplementation frame-locals (frame-number) + (loop for (name . value) in (nth-value 2 (frame-decode-env (elt *backtrace* frame-number))) + with i = 0 + collect (list :name name :id (prog1 i (incf i)) :value value))) + +(defimplementation frame-var-value (frame-number var-id) + (cdr (elt (nth-value 2 (frame-decode-env (elt *backtrace* frame-number))) var-id))) + +(defimplementation disassemble-frame (frame-number) + (let ((fun (frame-fun (elt *backtrace* frame-number)))) + (disassemble fun))) + +(defimplementation eval-in-frame (form frame-number) + (let ((env (second (elt *backtrace* frame-number)))) + (si:eval-in-env form env))) + +#| +(defimplementation gdb-initial-commands () + ;; These signals are used by the GC. + #+linux '("handle SIGPWR noprint nostop" + "handle SIGXCPU noprint nostop")) + +(defimplementation command-line-args () + (loop for n from 0 below (si:argc) collect (si:argv n))) +|# + +;;;; Inspector + +(defmethod emacs-inspect ((o t)) + ; ecl clos support leaves some to be desired + (cond + ((streamp o) + (list* + (format nil "~S is an ordinary stream~%" o) + (append + (list + "Open for " + (cond + ((ignore-errors (interactive-stream-p o)) "Interactive") + ((and (input-stream-p o) (output-stream-p o)) "Input and output") + ((input-stream-p o) "Input") + ((output-stream-p o) "Output")) + `(:newline) `(:newline)) + (label-value-line* + ("Element type" (stream-element-type o)) + ("External format" (stream-external-format o))) + (ignore-errors (label-value-line* + ("Broadcast streams" (broadcast-stream-streams o)))) + (ignore-errors (label-value-line* + ("Concatenated streams" (concatenated-stream-streams o)))) + (ignore-errors (label-value-line* + ("Echo input stream" (echo-stream-input-stream o)))) + (ignore-errors (label-value-line* + ("Echo output stream" (echo-stream-output-stream o)))) + (ignore-errors (label-value-line* + ("Output String" (get-output-stream-string o)))) + (ignore-errors (label-value-line* + ("Synonym symbol" (synonym-stream-symbol o)))) + (ignore-errors (label-value-line* + ("Input stream" (two-way-stream-input-stream o)))) + (ignore-errors (label-value-line* + ("Output stream" (two-way-stream-output-stream o))))))) + ((si:instancep o) ;;t + (let* ((cl (si:instance-class o)) + (slots (clos::class-slots cl))) + (list* (format nil "~S is an instance of class ~A~%" + o (clos::class-name cl)) + (loop for x in slots append + (let* ((name (clos::slot-definition-name x)) + (value (if (slot-boundp o name) + (clos::slot-value o name) + "Unbound" + ))) + (list + (format nil "~S: " name) + `(:value ,value) + `(:newline))))))) + (t (list (format nil "~A" o))))) + +;;;; Definitions + +(defimplementation find-definitions (name) + (if (fboundp name) + (let ((tmp (find-source-location (symbol-function name)))) + `(((defun ,name) ,tmp))))) + +(defimplementation find-source-location (obj) + (setf *tmp* obj) + (or + (typecase obj + (function + (multiple-value-bind (file pos) (ignore-errors (si::compiled-function-file obj)) + (if (and file pos) + (make-location + `(:file ,(if (stringp file) file (namestring file))) + `(:end-position ,pos) ;; `(:position ,pos) + `(:snippet + ,(with-open-file (s file) + (file-position s pos) + (skip-comments-and-whitespace s) + (read-snippet s)))))))) + `(:error (format nil "Source definition of ~S not found" obj)))) + +;;;; Profiling + + +(eval-when (:compile-toplevel :load-toplevel) + ;; At compile-time we need access to the profile package for the + ;; the following code to be read properly. + ;; It is a bit a shame we have to load the entire module to get that. + (require 'profile)) + + +(defimplementation profile (fname) + (when fname (eval `(profile:profile ,fname)))) + +(defimplementation unprofile (fname) + (when fname (eval `(profile:unprofile ,fname)))) + +(defimplementation unprofile-all () + (profile:unprofile-all) + "All functions unprofiled.") + +(defimplementation profile-report () + (profile:report)) + +(defimplementation profile-reset () + (profile:reset) + "Reset profiling counters.") + +(defimplementation profiled-functions () + (profile:profile)) + +(defimplementation profile-package (package callers methods) + (declare (ignore callers methods)) + (eval `(profile:profile ,(package-name (find-package package))))) + + +;;;; Threads + +(defvar *thread-id-counter* 0) + +(defvar *thread-id-counter-lock* + (mt:make-lock :name "thread id counter lock")) + +(defun next-thread-id () + (mt:with-lock (*thread-id-counter-lock*) + (incf *thread-id-counter*)) + ) + +(defparameter *thread-id-map* (make-hash-table)) +(defparameter *id-thread-map* (make-hash-table)) + +(defvar *thread-id-map-lock* + (mt:make-lock :name "thread id map lock")) + +(defparameter +default-thread-local-variables+ + '(*macroexpand-hook* + *default-pathname-defaults* + *readtable* + *random-state* + *compile-print* + *compile-verbose* + *load-print* + *load-verbose* + *print-array* + *print-base* + *print-case* + *print-circle* + *print-escape* + *print-gensym* + *print-length* + *print-level* + *print-lines* + *print-miser-width* + *print-pprint-dispatch* + *print-pretty* + *print-radix* + *print-readably* + *print-right-margin* + *read-base* + *read-default-float-format* + *read-eval* + *read-suppress* + )) + +(defun thread-local-default-bindings () + (let (local) + (dolist (var +default-thread-local-variables+ local) + (setq local (acons var (symbol-value var) local)) + ))) + +;; mkcl doesn't have weak pointers +(defimplementation spawn (fn &key name initial-bindings) + (let* ((local-defaults (thread-local-default-bindings)) + (thread + ;;(mt:make-thread :name name) + (mt:make-thread :name name + :initial-bindings (nconc initial-bindings + local-defaults)) + ) + (id (next-thread-id))) + (mt:with-lock (*thread-id-map-lock*) + (setf (gethash id *thread-id-map*) thread) + (setf (gethash thread *id-thread-map*) id)) + (mt:thread-preset + thread + #'(lambda () + (unwind-protect + (progn + ;;(format t "~&Starting thread: ~S.~%" name) (finish-output) + (mt:thread-detach nil) + (funcall fn)) + (progn + ;;(format t "~&Wrapping up thread: ~S.~%" name) (finish-output) + (mt:with-lock (*thread-id-map-lock*) + (remhash thread *id-thread-map*) + (remhash id *thread-id-map*)) + ;;(format t "~&Finished thread: ~S~%" name) (finish-output) + )))) + (mt:thread-enable thread) + (mt:thread-yield) + thread + )) + +(defimplementation thread-id (thread) + (block thread-id + (mt:with-lock (*thread-id-map-lock*) + (or (gethash thread *id-thread-map*) + (let ((id (next-thread-id))) + (setf (gethash id *thread-id-map*) thread) + (setf (gethash thread *id-thread-map*) id) + id))))) + +(defimplementation find-thread (id) + (mt:with-lock (*thread-id-map-lock*) + (gethash id *thread-id-map*))) + +(defimplementation thread-name (thread) + (mt:thread-name thread)) + +(defimplementation thread-status (thread) + (if (mt:thread-active-p thread) + "RUNNING" + "STOPPED")) + +(defimplementation make-lock (&key name) + (mt:make-lock :name name :recursive t)) + +(defimplementation call-with-lock-held (lock function) + (declare (type function function)) + (mt:with-lock (lock) (funcall function))) + +(defimplementation current-thread () + mt:*thread*) + +(defimplementation all-threads () + (mt:all-threads)) + +(defimplementation interrupt-thread (thread fn) + (mt:interrupt-thread thread fn)) + +(defimplementation kill-thread (thread) + (mt:interrupt-thread thread #'mt:terminate-thread) + ) + +(defimplementation thread-alive-p (thread) + (mt:thread-active-p thread)) + +(defvar *mailbox-lock* (mt:make-lock :name "mailbox lock")) +(defvar *mailboxes* (list)) +(declaim (type list *mailboxes*)) + +(defstruct (mailbox (:conc-name mailbox.)) + thread + locked-by + (mutex (mt:make-lock :name "thread mailbox")) + (semaphore (mt:make-semaphore)) + (queue '() :type list)) + +(defun mailbox (thread) + "Return THREAD's mailbox." + (mt:with-lock (*mailbox-lock*) + (or (find thread *mailboxes* :key #'mailbox.thread) + (let ((mb (make-mailbox :thread thread))) + (push mb *mailboxes*) + mb)))) + +(defimplementation send (thread message) + (handler-case + (let* ((mbox (mailbox thread)) + (mutex (mailbox.mutex mbox))) +;; (mt:interrupt-thread +;; thread +;; (lambda () +;; (mt:with-lock (mutex) +;; (setf (mailbox.queue mbox) +;; (nconc (mailbox.queue mbox) (list message)))))) + +;; (format t "~&! thread = ~S~% thread = ~S~% message = ~S~%" +;; mt:*thread* thread message) (finish-output) + (mt:with-lock (mutex) + (setf (mailbox.locked-by mbox) mt:*thread*) + (setf (mailbox.queue mbox) + (nconc (mailbox.queue mbox) (list message))) + ;;(format t "*") (finish-output) + (handler-case + (mt:semaphore-signal (mailbox.semaphore mbox)) + (condition (condition) + (format t "Something went bad with semaphore-signal ~A" condition) (finish-output) + ;;(break) + )) + (setf (mailbox.locked-by mbox) nil) + ) + ;;(format t "+") (finish-output) + ) + (condition (condition) + (format t "~&Error in send: ~S~%" condition) (finish-output)) + ) + ) + +;; (defimplementation receive () +;; (block got-mail +;; (let* ((mbox (mailbox mt:*thread*)) +;; (mutex (mailbox.mutex mbox))) +;; (loop +;; (mt:with-lock (mutex) +;; (if (mailbox.queue mbox) +;; (return-from got-mail (pop (mailbox.queue mbox))))) +;; ;;interrupt-thread will halt this if it takes longer than 1sec +;; (sleep 1))))) + + +(defimplementation receive-if (test &optional timeout) + (handler-case + (let* ((mbox (mailbox (current-thread))) + (mutex (mailbox.mutex mbox)) + got-one) + (assert (or (not timeout) (eq timeout t))) + (loop + (check-slime-interrupts) + ;;(format t "~&: ~S~%" mt:*thread*) (finish-output) + (handler-case + (setq got-one (mt:semaphore-wait (mailbox.semaphore mbox) 2)) + (condition (condition) + (format t "~&In (swank-mkcl) receive-if: Something went bad with semaphore-wait ~A~%" condition) + (finish-output) + nil + ) + ) + (mt:with-lock (mutex) + (setf (mailbox.locked-by mbox) mt:*thread*) + (let* ((q (mailbox.queue mbox)) + (tail (member-if test q))) + (when tail + (setf (mailbox.queue mbox) (nconc (ldiff q tail) (cdr tail))) + (setf (mailbox.locked-by mbox) nil) + ;;(format t "~&thread ~S received: ~S~%" mt:*thread* (car tail)) + (return (car tail)))) + (setf (mailbox.locked-by mbox) nil) + ) + + ;;(format t "/ ~S~%" mt:*thread*) (finish-output) + (when (eq timeout t) (return (values nil t))) +;; (unless got-one +;; (format t "~&In (swank-mkcl) receive-if: semaphore-wait timed out!~%")) + ) + ) + (condition (condition) + (format t "~&Error in (swank-mkcl) receive-if: ~S, ~A~%" condition condition) (finish-output) + nil + ) + ) + ) + + +(defmethod stream-finish-output ((stream stream)) + (finish-output stream)) + + +;; + +;;#+windows +(defimplementation doze-in-repl () + (setq *inferior-lisp-sleeping-post* (mt:make-semaphore)) + ;;(loop (sleep 1)) + (mt:semaphore-wait *inferior-lisp-sleeping-post*) + (mk-ext:quit :verbose t) + ) + diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/rpc.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/rpc.lisp new file mode 100644 index 0000000..e30cc2c --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/rpc.lisp @@ -0,0 +1,162 @@ +;;; -*- indent-tabs-mode: nil; coding: latin-1-unix -*- +;;; +;;; swank-rpc.lisp -- Pass remote calls and responses between lisp systems. +;;; +;;; Created 2010, Terje Norderhaug +;;; +;;; This code has been placed in the Public Domain. All warranties +;;; are disclaimed. +;;; + +(in-package swank/rpc) + + +;;;;; Input + +(define-condition swank-reader-error (reader-error) + ((packet :type string :initarg :packet + :reader swank-reader-error.packet) + (cause :type reader-error :initarg :cause + :reader swank-reader-error.cause))) + +(defun read-message (stream package) + (let ((packet (read-packet stream))) + (handler-case (values (read-form packet package)) + (reader-error (c) + (error 'swank-reader-error + :packet packet :cause c))))) + +(defun read-packet (stream) + (let* ((length (parse-header stream)) + (octets (read-chunk stream length))) + (handler-case (swank/backend:utf8-to-string octets) + (error (c) + (error 'swank-reader-error + :packet (asciify octets) + :cause c))))) + +(defun asciify (packet) + (with-output-to-string (*standard-output*) + (loop for code across (etypecase packet + (string (map 'vector #'char-code packet)) + (vector packet)) + do (cond ((<= code #x7f) (write-char (code-char code))) + (t (format t "\\x~x" code)))))) + +(defun parse-header (stream) + (parse-integer (map 'string #'code-char (read-chunk stream 6)) + :radix 16)) + +(defun read-chunk (stream length) + (let* ((buffer (make-array length :element-type '(unsigned-byte 8))) + (count (read-sequence buffer stream))) + (cond ((= count length) + buffer) + ((zerop count) + (error 'end-of-file :stream stream)) + (t + (error "Short read: length=~D count=~D" length count))))) + +(defparameter *validate-input* nil + "Set to true to require input that more strictly conforms to the protocol") + +(defun read-form (string package) + (with-standard-io-syntax + (let ((*package* package)) + (if *validate-input* + (validating-read string) + (read-from-string string))))) + +(defun validating-read (string) + (with-input-from-string (*standard-input* string) + (simple-read))) + +(defun simple-read () + "Read a form that conforms to the protocol, otherwise signal an error." + (let ((c (read-char))) + (case c + (#\( (loop collect (simple-read) + while (ecase (read-char) + (#\) nil) + (#\space t)))) + (#\' `(quote ,(simple-read))) + (t + (cond + ((digit-char-p c) + (parse-integer + (map 'simple-string #'identity + (loop for ch = c then (read-char nil nil) + while (and ch (digit-char-p ch)) + collect ch + finally (unread-char ch))))) + ((or (member c '(#\: #\")) (alpha-char-p c)) + (unread-char c) + (read-preserving-whitespace)) + (t (error "Invalid character ~:c" c))))))) + + +;;;;; Output + +(defun write-message (message package stream) + (let* ((string (prin1-to-string-for-emacs message package)) + (octets (handler-case (swank/backend:string-to-utf8 string) + (error (c) (encoding-error c string)))) + (length (length octets))) + (write-header stream length) + (write-sequence octets stream) + (finish-output stream))) + +;; FIXME: for now just tell emacs that we and an encoding problem. +(defun encoding-error (condition string) + (swank/backend:string-to-utf8 + (prin1-to-string-for-emacs + `(:reader-error + ,(asciify string) + ,(format nil "Error during string-to-utf8: ~a" + (or (ignore-errors (asciify (princ-to-string condition))) + (asciify (princ-to-string (type-of condition)))))) + (find-package :cl)))) + +(defun write-header (stream length) + (declare (type (unsigned-byte 24) length)) + ;;(format *trace-output* "length: ~d (#x~x)~%" length length) + (loop for c across (format nil "~6,'0x" length) + do (write-byte (char-code c) stream))) + +(defun switch-to-double-floats (x) + (typecase x + (double-float x) + (float (coerce x 'double-float)) + (null x) + (list (loop for (x . cdr) on x + collect (switch-to-double-floats x) into result + until (atom cdr) + finally (return (append result (switch-to-double-floats cdr))))) + (t x))) + +(defun prin1-to-string-for-emacs (object package) + (with-standard-io-syntax + (let ((*print-case* :downcase) + (*print-readably* nil) + (*print-pretty* nil) + (*package* package) + ;; Emacs has only double floats. + (*read-default-float-format* 'double-float)) + (prin1-to-string (switch-to-double-floats object))))) + + +#| TEST/DEMO: + +(defparameter *transport* + (with-output-to-string (out) + (write-message '(:message (hello "world")) *package* out) + (write-message '(:return 5) *package* out) + (write-message '(:emacs-rex NIL) *package* out))) + +*transport* + +(with-input-from-string (in *transport*) + (loop while (peek-char T in NIL) + collect (read-message in *package*))) + +|# diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/sbcl.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/sbcl.lisp new file mode 100644 index 0000000..430c906 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/sbcl.lisp @@ -0,0 +1,2025 @@ +;;;;; -*- indent-tabs-mode: nil -*- +;;; +;;; swank-sbcl.lisp --- SLIME backend for SBCL. +;;; +;;; Created 2003, Daniel Barlow +;;; +;;; This code has been placed in the Public Domain. All warranties are +;;; disclaimed. + +;;; Requires the SB-INTROSPECT contrib. + +;;; Administrivia + +(defpackage swank/sbcl + (:use cl swank/backend swank/source-path-parser swank/source-file-cache)) + +(in-package swank/sbcl) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (require 'sb-bsd-sockets) + (require 'sb-introspect) + (require 'sb-posix) + (require 'sb-cltl2)) + +(declaim (optimize (debug 2) + (sb-c::insert-step-conditions 0) + (sb-c::insert-debug-catch 0))) + +;;; backwards compability tests + +(eval-when (:compile-toplevel :load-toplevel :execute) + ;; Generate a form suitable for testing for stepper support (0.9.17) + ;; with #+. + (defun sbcl-with-new-stepper-p () + (with-symbol 'enable-stepping 'sb-impl)) + ;; Ditto for weak hash-tables + (defun sbcl-with-weak-hash-tables () + (with-symbol 'hash-table-weakness 'sb-ext)) + ;; And for xref support (1.0.1) + (defun sbcl-with-xref-p () + (with-symbol 'who-calls 'sb-introspect)) + ;; ... for restart-frame support (1.0.2) + (defun sbcl-with-restart-frame () + (with-symbol 'frame-has-debug-tag-p 'sb-debug)) + ;; ... for :setf :inverse info (1.1.17) + (defun sbcl-with-setf-inverse-meta-info () + (boolean-to-feature-expression + ;; going through FIND-SYMBOL since META-INFO was renamed from + ;; TYPE-INFO in 1.2.10. + (let ((sym (find-symbol "META-INFO" "SB-C"))) + (and sym + (fboundp sym) + (funcall sym :setf :inverse ())))))) + +;;; swank-mop + +(import-swank-mop-symbols :sb-mop '(:slot-definition-documentation)) + +(defun swank-mop:slot-definition-documentation (slot) + (sb-pcl::documentation slot t)) + +;; stream support + +(defimplementation gray-package-name () + "SB-GRAY") + +;; Pretty printer calls this, apparently +(defmethod sb-gray:stream-line-length + ((s sb-gray:fundamental-character-input-stream)) + nil) + +;;; Connection info + +(defimplementation lisp-implementation-type-name () + "sbcl") + +;; Declare return type explicitly to shut up STYLE-WARNINGS about +;; %SAP-ALIEN in ENABLE-SIGIO-ON-FD below. +(declaim (ftype (function () (values (signed-byte 32) &optional)) getpid)) +(defimplementation getpid () + (sb-posix:getpid)) + +;;; UTF8 + +(defimplementation string-to-utf8 (string) + (sb-ext:string-to-octets string :external-format :utf8)) + +(defimplementation utf8-to-string (octets) + (sb-ext:octets-to-string octets :external-format :utf8)) + +;;; TCP Server + +(defimplementation preferred-communication-style () + (cond + ;; fixme: when SBCL/win32 gains better select() support, remove + ;; this. + ((member :sb-thread *features*) :spawn) + ((member :win32 *features*) nil) + (t :fd-handler))) + + +(defun resolve-hostname (host) + "Returns valid IPv4 or IPv6 address for the host." + ;; get all IPv4 and IPv6 addresses as a list + (let* ((host-ents (multiple-value-list (sb-bsd-sockets:get-host-by-name host))) + ;; remove protocols for which we don't have an address + (addresses (remove-if-not #'sb-bsd-sockets:host-ent-address host-ents))) + ;; Return the first one or nil, + ;; but actually, it shouln't return nil, because + ;; get-host-by-name will signal NAME-SERVICE-ERROR condition + ;; if there isn't any address for the host. + (first addresses))) + + +(defimplementation create-socket (host port &key backlog) + (let* ((host-ent (resolve-hostname host)) + (socket (make-instance (cond #+#.(swank/backend:with-symbol 'inet6-socket 'sb-bsd-sockets) + ((eql (sb-bsd-sockets:host-ent-address-type host-ent) 10) + 'sb-bsd-sockets:inet6-socket) + (t + 'sb-bsd-sockets:inet-socket)) + :type :stream + :protocol :tcp))) + (setf (sb-bsd-sockets:sockopt-reuse-address socket) t) + (sb-bsd-sockets:socket-bind socket (sb-bsd-sockets:host-ent-address host-ent) port) + + (sb-bsd-sockets:socket-listen socket (or backlog 5)) + socket)) + +(defimplementation local-port (socket) + (nth-value 1 (sb-bsd-sockets:socket-name socket))) + +(defimplementation close-socket (socket) + (sb-sys:invalidate-descriptor (socket-fd socket)) + (sb-bsd-sockets:socket-close socket)) + +(defimplementation accept-connection (socket &key + external-format + buffering timeout) + (declare (ignore timeout)) + (make-socket-io-stream (accept socket) external-format + (ecase buffering + ((t :full) :full) + ((nil :none) :none) + ((:line) :line)))) + + +;; The SIGIO stuff should probably be removed as it's unlikey that +;; anybody uses it. +#-win32 +(progn + (defimplementation install-sigint-handler (function) + (sb-sys:enable-interrupt sb-unix:sigint + (lambda (&rest args) + (declare (ignore args)) + (sb-sys:invoke-interruption + (lambda () + (sb-sys:with-interrupts + (funcall function))))))) + + (defvar *sigio-handlers* '() + "List of (key . fn) pairs to be called on SIGIO.") + + (defun sigio-handler (signal code scp) + (declare (ignore signal code scp)) + (sb-sys:with-interrupts + (mapc (lambda (handler) + (funcall (the function (cdr handler)))) + *sigio-handlers*))) + + (defun set-sigio-handler () + (sb-sys:enable-interrupt sb-unix:sigio #'sigio-handler)) + + (defun enable-sigio-on-fd (fd) + (sb-posix::fcntl fd sb-posix::f-setfl sb-posix::o-async) + (sb-posix::fcntl fd sb-posix::f-setown (getpid)) + (values)) + + (defimplementation add-sigio-handler (socket fn) + (set-sigio-handler) + (let ((fd (socket-fd socket))) + (enable-sigio-on-fd fd) + (push (cons fd fn) *sigio-handlers*))) + + (defimplementation remove-sigio-handlers (socket) + (let ((fd (socket-fd socket))) + (setf *sigio-handlers* (delete fd *sigio-handlers* :key #'car)) + (sb-sys:invalidate-descriptor fd)) + (close socket))) + + +(defimplementation add-fd-handler (socket fun) + (let ((fd (socket-fd socket)) + (handler nil)) + (labels ((add () + (setq handler (sb-sys:add-fd-handler fd :input #'run))) + (run (fd) + (sb-sys:remove-fd-handler handler) ; prevent recursion + (unwind-protect + (funcall fun) + (when (sb-unix:unix-fstat fd) ; still open? + (add))))) + (add)))) + +(defimplementation remove-fd-handlers (socket) + (sb-sys:invalidate-descriptor (socket-fd socket))) + +(defimplementation socket-fd (socket) + (etypecase socket + (fixnum socket) + (sb-bsd-sockets:socket (sb-bsd-sockets:socket-file-descriptor socket)) + (file-stream (sb-sys:fd-stream-fd socket)))) + +(defimplementation command-line-args () + sb-ext:*posix-argv*) + +(defimplementation dup (fd) + (sb-posix:dup fd)) + +(defvar *wait-for-input-called*) + +(defimplementation wait-for-input (streams &optional timeout) + (assert (member timeout '(nil t))) + (when (boundp '*wait-for-input-called*) + (setq *wait-for-input-called* t)) + (let ((*wait-for-input-called* nil)) + (loop + (let ((ready (remove-if-not #'input-ready-p streams))) + (when ready (return ready))) + (when (check-slime-interrupts) + (return :interrupt)) + (when *wait-for-input-called* + (return :interrupt)) + (when timeout + (return nil)) + (sleep 0.1)))) + +(defun fd-stream-input-buffer-empty-p (stream) + (let ((buffer (sb-impl::fd-stream-ibuf stream))) + (or (not buffer) + (= (sb-impl::buffer-head buffer) + (sb-impl::buffer-tail buffer))))) + +#-win32 +(defun input-ready-p (stream) + (or (not (fd-stream-input-buffer-empty-p stream)) + #+#.(swank/backend:with-symbol 'fd-stream-fd-type 'sb-impl) + (eq :regular (sb-impl::fd-stream-fd-type stream)) + (not (sb-impl::sysread-may-block-p stream)))) + +#+win32 +(progn + (defun input-ready-p (stream) + (or (not (fd-stream-input-buffer-empty-p stream)) + (handle-listen (sockint::fd->handle (sb-impl::fd-stream-fd stream))))) + + (sb-alien:define-alien-routine ("WSACreateEvent" wsa-create-event) + sb-win32:handle) + + (sb-alien:define-alien-routine ("WSACloseEvent" wsa-close-event) + sb-alien:int + (event sb-win32:handle)) + + (defconstant +fd-read+ #.(ash 1 0)) + (defconstant +fd-close+ #.(ash 1 5)) + + (sb-alien:define-alien-routine ("WSAEventSelect" wsa-event-select) + sb-alien:int + (fd sb-alien:int) + (handle sb-win32:handle) + (mask sb-alien:long)) + + (sb-alien:load-shared-object "kernel32.dll") + (sb-alien:define-alien-routine ("WaitForSingleObjectEx" + wait-for-single-object-ex) + sb-alien:int + (event sb-win32:handle) + (milliseconds sb-alien:long) + (alertable sb-alien:int)) + + ;; see SB-WIN32:HANDLE-LISTEN + (defun handle-listen (handle) + (sb-alien:with-alien ((avail sb-win32:dword) + (buf (array char #.sb-win32::input-record-size))) + (unless (zerop (sb-win32:peek-named-pipe handle nil 0 nil + (sb-alien:alien-sap + (sb-alien:addr avail)) + nil)) + (return-from handle-listen (plusp avail))) + + (unless (zerop (sb-win32:peek-console-input handle + (sb-alien:alien-sap buf) + sb-win32::input-record-size + (sb-alien:alien-sap + (sb-alien:addr avail)))) + (return-from handle-listen (plusp avail)))) + + (let ((event (wsa-create-event))) + (wsa-event-select handle event (logior +fd-read+ +fd-close+)) + (let ((val (wait-for-single-object-ex event 0 0))) + (wsa-close-event event) + (unless (= val -1) + (return-from handle-listen (zerop val))))) + + nil) + + ) + +(defvar *external-format-to-coding-system* + '((:iso-8859-1 + "latin-1" "latin-1-unix" "iso-latin-1-unix" + "iso-8859-1" "iso-8859-1-unix") + (:utf-8 "utf-8" "utf-8-unix") + (:euc-jp "euc-jp" "euc-jp-unix") + (:us-ascii "us-ascii" "us-ascii-unix"))) + +;; C.f. R.M.Kreuter in <20536.1219412774@progn.net> on sbcl-general, +;; 2008-08-22. +(defvar *physical-pathname-host* (pathname-host (user-homedir-pathname))) + +(defimplementation filename-to-pathname (filename) + (sb-ext:parse-native-namestring filename *physical-pathname-host*)) + +(defimplementation find-external-format (coding-system) + (car (rassoc-if (lambda (x) (member coding-system x :test #'equal)) + *external-format-to-coding-system*))) + +(defimplementation set-default-directory (directory) + (let ((directory (truename (merge-pathnames directory)))) + (sb-posix:chdir directory) + (setf *default-pathname-defaults* directory) + (default-directory))) + +(defun make-socket-io-stream (socket external-format buffering) + (let ((args `(:output t + :input t + :element-type ,(if external-format + 'character + '(unsigned-byte 8)) + :buffering ,buffering + ,@(cond ((and external-format (sb-int:featurep :sb-unicode)) + `(:external-format ,external-format)) + (t '())) + :serve-events ,(eq :fd-handler swank:*communication-style*) + ;; SBCL < 1.0.42.43 doesn't support :SERVE-EVENTS + ;; argument. + :allow-other-keys t))) + (apply #'sb-bsd-sockets:socket-make-stream socket args))) + +(defun accept (socket) + "Like socket-accept, but retry on EAGAIN." + (loop (handler-case + (return (sb-bsd-sockets:socket-accept socket)) + (sb-bsd-sockets:interrupted-error ())))) + + +;;;; Support for SBCL syntax + +;;; SBCL's source code is riddled with #! reader macros. Also symbols +;;; containing `!' have special meaning. We have to work long and +;;; hard to be able to read the source. To deal with #! reader +;;; macros, we use a special readtable. The special symbols are +;;; converted by a condition handler. + +(defun feature-in-list-p (feature list) + (etypecase feature + (symbol (member feature list :test #'eq)) + (cons (flet ((subfeature-in-list-p (subfeature) + (feature-in-list-p subfeature list))) + ;; Don't use ECASE since SBCL also has :host-feature, + ;; don't need to handle it or anything else appearing in + ;; the future or in erronous code. + (case (first feature) + (:or (some #'subfeature-in-list-p (rest feature))) + (:and (every #'subfeature-in-list-p (rest feature))) + (:not (destructuring-bind (e) (cdr feature) + (not (subfeature-in-list-p e))))))))) + +(defun shebang-reader (stream sub-character infix-parameter) + (declare (ignore sub-character)) + (when infix-parameter + (error "illegal read syntax: #~D!" infix-parameter)) + (let ((next-char (read-char stream))) + (unless (find next-char "+-") + (error "illegal read syntax: #!~C" next-char)) + ;; When test is not satisfied + ;; FIXME: clearer if order of NOT-P and (NOT NOT-P) were reversed? then + ;; would become "unless test is satisfied".. + (when (let* ((*package* (find-package "KEYWORD")) + (*read-suppress* nil) + (not-p (char= next-char #\-)) + (feature (read stream))) + (if (feature-in-list-p feature *features*) + not-p + (not not-p))) + ;; Read (and discard) a form from input. + (let ((*read-suppress* t)) + (read stream t nil t)))) + (values)) + +(defvar *shebang-readtable* + (let ((*readtable* (copy-readtable nil))) + (set-dispatch-macro-character #\# #\! + (lambda (s c n) (shebang-reader s c n)) + *readtable*) + *readtable*)) + +(defun shebang-readtable () + *shebang-readtable*) + +(defun sbcl-package-p (package) + (let ((name (package-name package))) + (eql (mismatch "SB-" name) 3))) + +(defun sbcl-source-file-p (filename) + (when filename + (loop for (nil pattern) in (logical-pathname-translations "SYS") + thereis (pathname-match-p filename pattern)))) + +(defun guess-readtable-for-filename (filename) + (if (sbcl-source-file-p filename) + (shebang-readtable) + *readtable*)) + +(defvar *debootstrap-packages* t) + +(defun call-with-debootstrapping (fun) + (handler-bind ((sb-int:bootstrap-package-not-found + #'sb-int:debootstrap-package)) + (funcall fun))) + +(defmacro with-debootstrapping (&body body) + `(call-with-debootstrapping (lambda () ,@body))) + +(defimplementation call-with-syntax-hooks (fn) + (cond ((and *debootstrap-packages* + (sbcl-package-p *package*)) + (with-debootstrapping (funcall fn))) + (t + (funcall fn)))) + +(defimplementation default-readtable-alist () + (let ((readtable (shebang-readtable))) + (loop for p in (remove-if-not #'sbcl-package-p (list-all-packages)) + collect (cons (package-name p) readtable)))) + +;;; Packages + +#+#.(swank/backend:with-symbol 'package-local-nicknames 'sb-ext) +(defimplementation package-local-nicknames (package) + (sb-ext:package-local-nicknames package)) + +;;; Utilities + +#+#.(swank/backend:with-symbol 'function-lambda-list 'sb-introspect) +(defimplementation arglist (fname) + (sb-introspect:function-lambda-list fname)) + +#-#.(swank/backend:with-symbol 'function-lambda-list 'sb-introspect) +(defimplementation arglist (fname) + (sb-introspect:function-arglist fname)) + +(defimplementation function-name (f) + (check-type f function) + (sb-impl::%fun-name f)) + +(defmethod declaration-arglist ((decl-identifier (eql 'optimize))) + (flet ((ensure-list (thing) (if (listp thing) thing (list thing)))) + (let* ((flags (sb-cltl2:declaration-information decl-identifier))) + (if flags + ;; Symbols aren't printed with package qualifiers, but the + ;; FLAGS would have to be fully qualified when used inside a + ;; declaration. So we strip those as long as there's no + ;; better way. (FIXME) + `(&any ,@(remove-if-not + #'(lambda (qualifier) + (find-symbol (symbol-name (first qualifier)) :cl)) + flags :key #'ensure-list)) + (call-next-method))))) + +#+#.(swank/backend:with-symbol 'deftype-lambda-list 'sb-introspect) +(defmethod type-specifier-arglist :around (typespec-operator) + (multiple-value-bind (arglist foundp) + (sb-introspect:deftype-lambda-list typespec-operator) + (if foundp arglist (call-next-method)))) + +(defimplementation type-specifier-p (symbol) + (or (sb-ext:valid-type-specifier-p symbol) + (not (eq (type-specifier-arglist symbol) :not-available)))) + +(defvar *buffer-name* nil) +(defvar *buffer-tmpfile* nil) +(defvar *buffer-offset*) +(defvar *buffer-substring* nil) + +(defvar *previous-compiler-condition* nil + "Used to detect duplicates.") + +(defun handle-notification-condition (condition) + "Handle a condition caused by a compiler warning. +This traps all compiler conditions at a lower-level than using +C:*COMPILER-NOTIFICATION-FUNCTION*. The advantage is that we get to +craft our own error messages, which can omit a lot of redundant +information." + (unless (or (eq condition *previous-compiler-condition*)) + ;; First resignal warnings, so that outer handlers -- which may choose to + ;; muffle this -- get a chance to run. + (when (typep condition 'warning) + (signal condition)) + (setq *previous-compiler-condition* condition) + (signal-compiler-condition (real-condition condition) + (sb-c::find-error-context nil)))) + +(defun signal-compiler-condition (condition context) + (signal 'compiler-condition + :original-condition condition + :severity (etypecase condition + (sb-ext:compiler-note :note) + (sb-c:compiler-error :error) + (reader-error :read-error) + (error :error) + #+#.(swank/backend:with-symbol early-deprecation-warning sb-ext) + (sb-ext::early-deprecation-warning :early-deprecation-warning) + #+#.(swank/backend:with-symbol late-deprecation-warning sb-ext) + (sb-ext::late-deprecation-warning :late-deprecation-warning) + #+#.(swank/backend:with-symbol final-deprecation-warning sb-ext) + (sb-ext::final-deprecation-warning :final-deprecation-warning) + #+#.(swank/backend:with-symbol redefinition-warning + sb-kernel) + (sb-kernel:redefinition-warning + :redefinition) + (style-warning :style-warning) + (warning :warning)) + :references (condition-references condition) + :message (brief-compiler-message-for-emacs condition) + :source-context (compiler-error-context context) + :location (compiler-note-location condition context))) + +(defun real-condition (condition) + "Return the encapsulated condition or CONDITION itself." + (typecase condition + (sb-int:encapsulated-condition (sb-int:encapsulated-condition condition)) + (t condition))) + +(defun condition-references (condition) + (if (typep condition 'sb-int:reference-condition) + (externalize-reference + (sb-int:reference-condition-references condition)))) + +(defun compiler-note-location (condition context) + (flet ((bailout () + (return-from compiler-note-location + (make-error-location "No error location available")))) + (cond (context + (locate-compiler-note + (sb-c::compiler-error-context-file-name context) + (compiler-source-path context) + (sb-c::compiler-error-context-original-source context))) + ((typep condition 'reader-error) + (let* ((stream (stream-error-stream condition)) + (file (pathname stream))) + (unless (open-stream-p stream) + (bailout)) + (if (compiling-from-buffer-p file) + ;; The stream position for e.g. "comma not inside + ;; backquote" is at the character following the + ;; comma, :offset is 0-based, hence the 1-. + (make-location (list :buffer *buffer-name*) + (list :offset *buffer-offset* + (1- (file-position stream)))) + (progn + (assert (compiling-from-file-p file)) + ;; No 1- because :position is 1-based. + (make-location (list :file (namestring file)) + (list :position (file-position stream))))))) + (t (bailout))))) + +(defun compiling-from-buffer-p (filename) + (and *buffer-name* + ;; The following is to trigger COMPILING-FROM-GENERATED-CODE-P + ;; in LOCATE-COMPILER-NOTE, and allows handling nested + ;; compilation from eg. hitting C-C on (eval-when ... (require ..))). + ;; + ;; PROBE-FILE to handle tempfile directory being a symlink. + (pathnamep filename) + (let ((true1 (probe-file filename)) + (true2 (probe-file *buffer-tmpfile*))) + (and true1 (equal true1 true2))))) + +(defun compiling-from-file-p (filename) + (and (pathnamep filename) + (or (null *buffer-name*) + (null *buffer-tmpfile*) + (let ((true1 (probe-file filename)) + (true2 (probe-file *buffer-tmpfile*))) + (not (and true1 (equal true1 true2))))))) + +(defun compiling-from-generated-code-p (filename source) + (and (eq filename :lisp) (stringp source))) + +(defun locate-compiler-note (file source-path source) + (cond ((compiling-from-buffer-p file) + (make-location (list :buffer *buffer-name*) + (list :offset *buffer-offset* + (source-path-string-position + source-path *buffer-substring*)))) + ((compiling-from-file-p file) + (let ((position (source-path-file-position source-path file))) + (make-location (list :file (namestring file)) + (list :position (and position + (1+ position)))))) + ((compiling-from-generated-code-p file source) + (make-location (list :source-form source) + (list :position 1))) + (t + (error "unhandled case in compiler note ~S ~S ~S" + file source-path source)))) + +(defun brief-compiler-message-for-emacs (condition) + "Briefly describe a compiler error for Emacs. +When Emacs presents the message it already has the source popped up +and the source form highlighted. This makes much of the information in +the error-context redundant." + (let ((sb-int:*print-condition-references* nil)) + (princ-to-string condition))) + +(defun compiler-error-context (error-context) + "Describe a compiler error for Emacs including context information." + (declare (type (or sb-c::compiler-error-context null) error-context)) + (multiple-value-bind (enclosing source) + (if error-context + (values (sb-c::compiler-error-context-enclosing-source error-context) + (sb-c::compiler-error-context-source error-context))) + (and (or enclosing source) + (format nil "~@[--> ~{~<~%--> ~1:;~A~> ~}~%~]~@[~{==>~%~A~%~}~]" + enclosing source)))) + +(defun compiler-source-path (context) + "Return the source-path for the current compiler error. +Returns NIL if this cannot be determined by examining internal +compiler state." + (cond ((sb-c::node-p context) + (reverse + (sb-c::source-path-original-source + (sb-c::node-source-path context)))) + ((sb-c::compiler-error-context-p context) + (reverse + (sb-c::compiler-error-context-original-source-path context))))) + +(defimplementation call-with-compilation-hooks (function) + (declare (type function function)) + (handler-bind + ;; N.B. Even though these handlers are called HANDLE-FOO they + ;; actually decline, i.e. the signalling of the original + ;; condition continues upward. + ((sb-c:fatal-compiler-error #'handle-notification-condition) + (sb-c:compiler-error #'handle-notification-condition) + (sb-ext:compiler-note #'handle-notification-condition) + (error #'handle-notification-condition) + (warning #'handle-notification-condition)) + (funcall function))) + +;;; HACK: SBCL 1.2.12 shipped with a bug where +;;; SB-EXT:RESTRICT-COMPILER-POLICY would signal an error when there +;;; were no policy restrictions in place. This workaround ensures the +;;; existence of at least one dummy restriction. +(handler-case (sb-ext:restrict-compiler-policy) + (error () (sb-ext:restrict-compiler-policy 'debug))) + +(defun compiler-policy (qualities) + "Return compiler policy qualities present in the QUALITIES alist. +QUALITIES is an alist with (quality . value)" + #+#.(swank/backend:with-symbol 'restrict-compiler-policy 'sb-ext) + (loop with policy = (sb-ext:restrict-compiler-policy) + for (quality) in qualities + collect (cons quality + (or (cdr (assoc quality policy)) + 0)))) + +(defun (setf compiler-policy) (policy) + (declare (ignorable policy)) + #+#.(swank/backend:with-symbol 'restrict-compiler-policy 'sb-ext) + (loop for (qual . value) in policy + do (sb-ext:restrict-compiler-policy qual value))) + +(defmacro with-compiler-policy (policy &body body) + (let ((current-policy (gensym))) + `(let ((,current-policy (compiler-policy ,policy))) + (setf (compiler-policy) ,policy) + (unwind-protect (progn ,@body) + (setf (compiler-policy) ,current-policy))))) + +(defimplementation swank-compile-file (input-file output-file + load-p external-format + &key policy) + (multiple-value-bind (output-file warnings-p failure-p) + (with-compiler-policy policy + (with-compilation-hooks () + (compile-file input-file :output-file output-file + :external-format external-format))) + (values output-file warnings-p + (or failure-p + (when load-p + ;; Cache the latest source file for definition-finding. + (source-cache-get input-file + (file-write-date input-file)) + (not (load output-file))))))) + +;;;; compile-string + +;;; We copy the string to a temporary file in order to get adequate +;;; semantics for :COMPILE-TOPLEVEL and :LOAD-TOPLEVEL EVAL-WHEN forms +;;; which the previous approach using +;;; (compile nil `(lambda () ,(read-from-string string))) +;;; did not provide. + +(locally (declare (sb-ext:muffle-conditions sb-ext:compiler-note)) + +(sb-alien:define-alien-routine (#-win32 "tempnam" #+win32 "_tempnam" tempnam) + sb-alien:c-string + (dir sb-alien:c-string) + (prefix sb-alien:c-string))) + +(defun temp-file-name () + "Return a temporary file name to compile strings into." + (tempnam nil "slime")) + +(defvar *trap-load-time-warnings* t) + +(defimplementation swank-compile-string (string &key buffer position filename + policy) + (let ((*buffer-name* buffer) + (*buffer-offset* position) + (*buffer-substring* string) + (*buffer-tmpfile* (temp-file-name))) + (labels ((load-it (filename) + (cond (*trap-load-time-warnings* + (with-compilation-hooks () (load filename))) + (t (load filename)))) + (cf () + (with-compiler-policy policy + (with-compilation-unit + (:source-plist (list :emacs-buffer buffer + :emacs-filename filename + :emacs-package (package-name *package*) + :emacs-position position + :emacs-string string) + :source-namestring filename + :allow-other-keys t) + (compile-file *buffer-tmpfile* :external-format :utf-8))))) + (with-open-file (s *buffer-tmpfile* :direction :output :if-exists :error + :external-format :utf-8) + (write-string string s)) + (unwind-protect + (multiple-value-bind (output-file warningsp failurep) + (with-compilation-hooks () (cf)) + (declare (ignore warningsp)) + (when output-file + (load-it output-file)) + (not failurep)) + (ignore-errors + (delete-file *buffer-tmpfile*) + (delete-file (compile-file-pathname *buffer-tmpfile*))))))) + +;;;; Definitions + +(defparameter *definition-types* + '(:variable defvar + :constant defconstant + :type deftype + :symbol-macro define-symbol-macro + :macro defmacro + :compiler-macro define-compiler-macro + :function defun + :generic-function defgeneric + :method defmethod + :setf-expander define-setf-expander + :structure defstruct + :condition define-condition + :class defclass + :method-combination define-method-combination + :package defpackage + :transform :deftransform + :optimizer :defoptimizer + :vop :define-vop + :source-transform :define-source-transform + :ir1-convert :def-ir1-translator + :declaration declaim + :alien-type :define-alien-type) + "Map SB-INTROSPECT definition type names to Slime-friendly forms") + +(defun definition-specifier (type) + "Return a pretty specifier for NAME representing a definition of type TYPE." + (getf *definition-types* type)) + +(defun make-dspec (type name source-location) + (list* (definition-specifier type) + name + (sb-introspect::definition-source-description source-location))) + +(defimplementation find-definitions (name) + (loop for type in *definition-types* by #'cddr + for defsrcs = (sb-introspect:find-definition-sources-by-name name type) + append (loop for defsrc in defsrcs collect + (list (make-dspec type name defsrc) + (converting-errors-to-error-location + (definition-source-for-emacs defsrc + type name)))))) + +(defimplementation find-source-location (obj) + (flet ((general-type-of (obj) + (typecase obj + (method :method) + (generic-function :generic-function) + (function :function) + (structure-class :structure-class) + (class :class) + (method-combination :method-combination) + (package :package) + (condition :condition) + (structure-object :structure-object) + (standard-object :standard-object) + (t :thing))) + (to-string (obj) + (typecase obj + ;; Packages are possibly named entities. + (package (princ-to-string obj)) + ((or structure-object standard-object condition) + (with-output-to-string (s) + (print-unreadable-object (obj s :type t :identity t)))) + (t (princ-to-string obj))))) + (converting-errors-to-error-location + (let ((defsrc (sb-introspect:find-definition-source obj))) + (definition-source-for-emacs defsrc + (general-type-of obj) + (to-string obj)))))) + +(defmacro with-definition-source ((&rest names) obj &body body) + "Like with-slots but works only for structs." + (flet ((reader (slot) + ;; Use read-from-string instead of intern so that + ;; conc-name can be a string such as ext:struct- and not + ;; cause errors and not force interning ext::struct- + (read-from-string + (concatenate 'string "sb-introspect:definition-source-" + (string slot))))) + (let ((tmp (gensym "OO-"))) + ` (let ((,tmp ,obj)) + (symbol-macrolet + ,(loop for name in names collect + (typecase name + (symbol `(,name (,(reader name) ,tmp))) + (cons `(,(first name) (,(reader (second name)) ,tmp))) + (t (error "Malformed syntax in WITH-STRUCT: ~A" name)))) + ,@body))))) + +(defun categorize-definition-source (definition-source) + (with-definition-source (pathname form-path character-offset plist) + definition-source + (let ((file-p (and pathname (probe-file pathname) + (or form-path character-offset)))) + (cond ((and (getf plist :emacs-buffer) file-p) :buffer-and-file) + ((getf plist :emacs-buffer) :buffer) + (file-p :file) + (pathname :file-without-position) + (t :invalid))))) + +#+#.(swank/backend:with-symbol 'definition-source-form-number 'sb-introspect) +(defun form-number-position (definition-source stream) + (let* ((tlf-number (car (sb-introspect:definition-source-form-path definition-source))) + (form-number (sb-introspect:definition-source-form-number definition-source))) + (multiple-value-bind (tlf pos-map) (read-source-form tlf-number stream) + (let* ((path-table (sb-di::form-number-translations tlf 0)) + (path (cond ((<= (length path-table) form-number) + (warn "inconsistent form-number-translations") + (list 0)) + (t + (reverse (cdr (aref path-table form-number))))))) + (source-path-source-position path tlf pos-map))))) + +#+#.(swank/backend:with-symbol 'definition-source-form-number 'sb-introspect) +(defun file-form-number-position (definition-source) + (let* ((code-date (sb-introspect:definition-source-file-write-date definition-source)) + (filename (sb-introspect:definition-source-pathname definition-source)) + (*readtable* (guess-readtable-for-filename filename)) + (source-code (get-source-code filename code-date))) + (with-debootstrapping + (with-input-from-string (s source-code) + (form-number-position definition-source s))))) + +#+#.(swank/backend:with-symbol 'definition-source-form-number 'sb-introspect) +(defun string-form-number-position (definition-source string) + (with-input-from-string (s string) + (form-number-position definition-source s))) + +(defun definition-source-buffer-location (definition-source) + (with-definition-source (form-path character-offset plist) definition-source + (destructuring-bind (&key emacs-buffer emacs-position emacs-directory + emacs-string &allow-other-keys) + plist + (let ((*readtable* (guess-readtable-for-filename emacs-directory)) + start + end) + (with-debootstrapping + (or + (and form-path + (or + #+#.(swank/backend:with-symbol 'definition-source-form-number 'sb-introspect) + (setf (values start end) + (and (sb-introspect:definition-source-form-number definition-source) + (string-form-number-position definition-source emacs-string))) + (setf (values start end) + (source-path-string-position form-path emacs-string)))) + (setf start character-offset + end most-positive-fixnum))) + (make-location + `(:buffer ,emacs-buffer) + `(:offset ,emacs-position ,start) + `(:snippet + ,(subseq emacs-string + start + (min end (+ start *source-snippet-size*))))))))) + +(defun definition-source-file-location (definition-source) + (with-definition-source (pathname form-path character-offset plist + file-write-date) definition-source + (let* ((namestring (namestring (translate-logical-pathname pathname))) + (pos (or (and form-path + (or + #+#.(swank/backend:with-symbol 'definition-source-form-number 'sb-introspect) + (and (sb-introspect:definition-source-form-number definition-source) + (ignore-errors (file-form-number-position definition-source))) + (ignore-errors + (source-file-position namestring file-write-date + form-path)))) + character-offset)) + (snippet (source-hint-snippet namestring file-write-date pos))) + (make-location `(:file ,namestring) + ;; /file positions/ in Common Lisp start from + ;; 0, buffer positions in Emacs start from 1. + `(:position ,(1+ pos)) + `(:snippet ,snippet))))) + +(defun definition-source-buffer-and-file-location (definition-source) + (let ((buffer (definition-source-buffer-location definition-source))) + (make-location (list :buffer-and-file + (cadr (location-buffer buffer)) + (namestring (sb-introspect:definition-source-pathname + definition-source))) + (location-position buffer) + (location-hints buffer)))) + +(defun definition-source-for-emacs (definition-source type name) + (with-definition-source (pathname form-path character-offset plist + file-write-date) + definition-source + (ecase (categorize-definition-source definition-source) + (:buffer-and-file + (definition-source-buffer-and-file-location definition-source)) + (:buffer + (definition-source-buffer-location definition-source)) + (:file + (definition-source-file-location definition-source)) + (:file-without-position + (make-location `(:file ,(namestring + (translate-logical-pathname pathname))) + '(:position 1) + (when (eql type :function) + `(:snippet ,(format nil "(defun ~a " + (symbol-name name)))))) + (:invalid + (error "DEFINITION-SOURCE of ~(~A~) ~A did not contain ~ + meaningful information." + type name))))) + +(defun source-file-position (filename write-date form-path) + (let ((source (get-source-code filename write-date)) + (*readtable* (guess-readtable-for-filename filename))) + (with-debootstrapping + (source-path-string-position form-path source)))) + +(defun source-hint-snippet (filename write-date position) + (read-snippet-from-string (get-source-code filename write-date) position)) + +(defun function-source-location (function &optional name) + (declare (type function function)) + (definition-source-for-emacs (sb-introspect:find-definition-source function) + :function + (or name (function-name function)))) + +(defun setf-expander (symbol) + (or + #+#.(swank/sbcl::sbcl-with-setf-inverse-meta-info) + (sb-int:info :setf :inverse symbol) + (sb-int:info :setf :expander symbol))) + +(defimplementation describe-symbol-for-emacs (symbol) + "Return a plist describing SYMBOL. +Return NIL if the symbol is unbound." + (let ((result '())) + (flet ((doc (kind) + (or (documentation symbol kind) :not-documented)) + (maybe-push (property value) + (when value + (setf result (list* property value result))))) + (maybe-push + :variable (multiple-value-bind (kind recorded-p) + (sb-int:info :variable :kind symbol) + (declare (ignore kind)) + (if (or (boundp symbol) recorded-p) + (doc 'variable)))) + (when (fboundp symbol) + (maybe-push + (cond ((macro-function symbol) :macro) + ((special-operator-p symbol) :special-operator) + ((typep (fdefinition symbol) 'generic-function) + :generic-function) + (t :function)) + (doc 'function))) + (maybe-push + :setf (and (setf-expander symbol) + (doc 'setf))) + (maybe-push + :type (if (sb-int:info :type :kind symbol) + (doc 'type))) + result))) + +(defimplementation describe-definition (symbol type) + (case type + (:variable + (describe symbol)) + (:function + (describe (symbol-function symbol))) + (:setf + (describe (setf-expander symbol))) + (:class + (describe (find-class symbol))) + (:type + (describe (sb-kernel:values-specifier-type symbol))))) + +#+#.(swank/sbcl::sbcl-with-xref-p) +(progn + (defmacro defxref (name &optional fn-name) + `(defimplementation ,name (what) + (sanitize-xrefs + (mapcar #'source-location-for-xref-data + (,(find-symbol (symbol-name (if fn-name + fn-name + name)) + "SB-INTROSPECT") + what))))) + (defxref who-calls) + (defxref who-binds) + (defxref who-sets) + (defxref who-references) + (defxref who-macroexpands) + #+#.(swank/backend:with-symbol 'who-specializes-directly 'sb-introspect) + (defxref who-specializes who-specializes-directly)) + +(defun source-location-for-xref-data (xref-data) + (destructuring-bind (name . defsrc) xref-data + (list name (converting-errors-to-error-location + (definition-source-for-emacs defsrc 'function name))))) + +(defimplementation list-callers (symbol) + (let ((fn (fdefinition symbol))) + (sanitize-xrefs + (mapcar #'function-dspec (sb-introspect:find-function-callers fn))))) + +(defimplementation list-callees (symbol) + (let ((fn (fdefinition symbol))) + (sanitize-xrefs + (mapcar #'function-dspec (sb-introspect:find-function-callees fn))))) + +(defun sanitize-xrefs (xrefs) + (remove-duplicates + (remove-if (lambda (f) + (member f (ignored-xref-function-names))) + (loop for entry in xrefs + for name = (car entry) + collect (if (and (consp name) + (member (car name) + '(sb-pcl::fast-method + sb-pcl::slow-method + sb-pcl::method))) + (cons (cons 'defmethod (cdr name)) + (cdr entry)) + entry)) + :key #'car) + :test (lambda (a b) + (and (eq (first a) (first b)) + (equal (second a) (second b)))))) + +(defun ignored-xref-function-names () + #-#.(swank/sbcl::sbcl-with-new-stepper-p) + '(nil sb-c::step-form sb-c::step-values) + #+#.(swank/sbcl::sbcl-with-new-stepper-p) + '(nil)) + +(defun function-dspec (fn) + "Describe where the function FN was defined. +Return a list of the form (NAME LOCATION)." + (let ((name (function-name fn))) + (list name (converting-errors-to-error-location + (function-source-location fn name))))) + +;;; macroexpansion + +(defimplementation macroexpand-all (form &optional env) + (sb-cltl2:macroexpand-all form env)) + +(defimplementation collect-macro-forms (form &optional environment) + (let ((macro-forms '()) + (compiler-macro-forms '()) + (function-quoted-forms '())) + (sb-walker:walk-form + form environment + (lambda (form context environment) + (declare (ignore context)) + (when (and (consp form) + (symbolp (car form))) + (cond ((eq (car form) 'function) + (push (cadr form) function-quoted-forms)) + ((member form function-quoted-forms) + nil) + ((macro-function (car form) environment) + (push form macro-forms)) + ((not (eq form (compiler-macroexpand-1 form environment))) + (push form compiler-macro-forms)))) + form)) + (values macro-forms compiler-macro-forms))) + + +;;; Debugging + +;;; Notice that SB-EXT:*INVOKE-DEBUGGER-HOOK* is slightly stronger +;;; than just a hook into BREAK. In particular, it'll make +;;; (LET ((*DEBUGGER-HOOK* NIL)) ..error..) drop into SLDB rather +;;; than the native debugger. That should probably be considered a +;;; feature. + +(defun make-invoke-debugger-hook (hook) + (when hook + #'(sb-int:named-lambda swank-invoke-debugger-hook + (condition old-hook) + (if *debugger-hook* + nil ; decline, *DEBUGGER-HOOK* will be tried next. + (funcall hook condition old-hook))))) + +(defun set-break-hook (hook) + (setq sb-ext:*invoke-debugger-hook* (make-invoke-debugger-hook hook))) + +(defun call-with-break-hook (hook continuation) + (let ((sb-ext:*invoke-debugger-hook* (make-invoke-debugger-hook hook))) + (funcall continuation))) + +(defimplementation install-debugger-globally (function) + (setq *debugger-hook* function) + (set-break-hook function)) + +(defimplementation condition-extras (condition) + (cond #+#.(swank/sbcl::sbcl-with-new-stepper-p) + ((typep condition 'sb-impl::step-form-condition) + `((:show-frame-source 0))) + ((typep condition 'sb-int:reference-condition) + (let ((refs (sb-int:reference-condition-references condition))) + (if refs + `((:references ,(externalize-reference refs)))))))) + +(defun externalize-reference (ref) + (etypecase ref + (null nil) + (cons (cons (externalize-reference (car ref)) + (externalize-reference (cdr ref)))) + ((or string number) ref) + (symbol + (cond ((eq (symbol-package ref) (symbol-package :test)) + ref) + (t (symbol-name ref)))))) + +(defvar *sldb-stack-top*) + +(defimplementation call-with-debugging-environment (debugger-loop-fn) + (declare (type function debugger-loop-fn)) + (let ((*sldb-stack-top* + (if (and (not *debug-swank-backend*) + sb-debug:*stack-top-hint*) + #+#.(swank/backend:with-symbol 'resolve-stack-top-hint 'sb-debug) + (sb-debug::resolve-stack-top-hint) + #-#.(swank/backend:with-symbol 'resolve-stack-top-hint 'sb-debug) + sb-debug:*stack-top-hint* + (sb-di:top-frame))) + (sb-debug:*stack-top-hint* nil)) + (handler-bind ((sb-di:debug-condition + (lambda (condition) + (signal 'sldb-condition + :original-condition condition)))) + (funcall debugger-loop-fn)))) + +#+#.(swank/sbcl::sbcl-with-new-stepper-p) +(progn + (defimplementation activate-stepping (frame) + (declare (ignore frame)) + (sb-impl::enable-stepping)) + (defimplementation sldb-stepper-condition-p (condition) + (typep condition 'sb-ext:step-form-condition)) + (defimplementation sldb-step-into () + (invoke-restart 'sb-ext:step-into)) + (defimplementation sldb-step-next () + (invoke-restart 'sb-ext:step-next)) + (defimplementation sldb-step-out () + (invoke-restart 'sb-ext:step-out))) + +(defimplementation call-with-debugger-hook (hook fun) + (let ((*debugger-hook* hook) + #+#.(swank/sbcl::sbcl-with-new-stepper-p) + (sb-ext:*stepper-hook* + (lambda (condition) + (typecase condition + (sb-ext:step-form-condition + (let ((sb-debug:*stack-top-hint* (sb-di::find-stepped-frame))) + (sb-impl::invoke-debugger condition))))))) + (handler-bind (#+#.(swank/sbcl::sbcl-with-new-stepper-p) + (sb-ext:step-condition #'sb-impl::invoke-stepper)) + (call-with-break-hook hook fun)))) + +(defun nth-frame (index) + (do ((frame *sldb-stack-top* (sb-di:frame-down frame)) + (i index (1- i))) + ((zerop i) frame))) + +(defimplementation compute-backtrace (start end) + "Return a list of frames starting with frame number START and +continuing to frame number END or, if END is nil, the last frame on the +stack." + (let ((end (or end most-positive-fixnum))) + (loop for f = (nth-frame start) then (sb-di:frame-down f) + for i from start below end + while f collect f))) + +(defimplementation print-frame (frame stream) + (sb-debug::print-frame-call frame stream + :allow-other-keys t + :emergency-best-effort t)) + +(defimplementation frame-restartable-p (frame) + #+#.(swank/sbcl::sbcl-with-restart-frame) + (not (null (sb-debug:frame-has-debug-tag-p frame)))) + +(defimplementation frame-call (frame-number) + (multiple-value-bind (name args) + (sb-debug::frame-call (nth-frame frame-number)) + (with-output-to-string (stream) + (locally (declare (sb-ext:muffle-conditions sb-ext:compiler-note)) + (pprint-logical-block (stream nil :prefix "(" :suffix ")") + (locally (declare (sb-ext:unmuffle-conditions sb-ext:compiler-note)) + (let ((*print-length* nil) + (*print-level* nil)) + (prin1 (sb-debug::ensure-printable-object name) stream)) + (let ((args (sb-debug::ensure-printable-object args))) + (if (listp args) + (format stream "~{ ~_~S~}" args) + (format stream " ~S" args))))))))) + +;;;; Code-location -> source-location translation + +;;; If debug-block info is avaibale, we determine the file position of +;;; the source-path for a code-location. If the code was compiled +;;; with C-c C-c, we have to search the position in the source string. +;;; If there's no debug-block info, we return the (less precise) +;;; source-location of the corresponding function. + +(defun code-location-source-location (code-location) + (let* ((dsource (sb-di:code-location-debug-source code-location)) + (plist (sb-c::debug-source-plist dsource)) + (package (getf plist :emacs-package)) + (*package* (or (and package + (find-package package)) + *package*))) + (if (getf plist :emacs-buffer) + (emacs-buffer-source-location code-location plist) + #+#.(swank/backend:with-symbol 'debug-source-from 'sb-di) + (ecase (sb-di:debug-source-from dsource) + (:file (file-source-location code-location)) + (:lisp (lisp-source-location code-location))) + #-#.(swank/backend:with-symbol 'debug-source-from 'sb-di) + (if (sb-di:debug-source-namestring dsource) + (file-source-location code-location) + (lisp-source-location code-location))))) + +;;; FIXME: The naming policy of source-location functions is a bit +;;; fuzzy: we have FUNCTION-SOURCE-LOCATION which returns the +;;; source-location for a function, and we also have FILE-SOURCE-LOCATION &co +;;; which returns the source location for a _code-location_. +;;; +;;; Maybe these should be named code-location-file-source-location, +;;; etc, turned into generic functions, or something. In the very +;;; least the names should indicate the main entry point vs. helper +;;; status. + +(defun file-source-location (code-location) + (if (code-location-has-debug-block-info-p code-location) + (source-file-source-location code-location) + (fallback-source-location code-location))) + +(defun fallback-source-location (code-location) + (let ((fun (code-location-debug-fun-fun code-location))) + (cond (fun (function-source-location fun)) + (t (error "Cannot find source location for: ~A " code-location))))) + +(defun lisp-source-location (code-location) + (let ((source (prin1-to-string + (sb-debug::code-location-source-form code-location 100))) + (condition swank:*swank-debugger-condition*)) + (if (and (typep condition 'sb-impl::step-form-condition) + (search "SB-IMPL::WITH-STEPPING-ENABLED" source + :test #'char-equal) + (search "SB-IMPL::STEP-FINISHED" source :test #'char-equal)) + ;; The initial form is utterly uninteresting -- and almost + ;; certainly right there in the REPL. + (make-error-location "Stepping...") + (make-location `(:source-form ,source) '(:position 1))))) + +(defun emacs-buffer-source-location (code-location plist) + (if (code-location-has-debug-block-info-p code-location) + (destructuring-bind (&key emacs-buffer emacs-position emacs-string + &allow-other-keys) + plist + (let* ((pos (string-source-position code-location emacs-string)) + (snipped (read-snippet-from-string emacs-string pos))) + (make-location `(:buffer ,emacs-buffer) + `(:offset ,emacs-position ,pos) + `(:snippet ,snipped)))) + (fallback-source-location code-location))) + +(defun source-file-source-location (code-location) + (let* ((code-date (code-location-debug-source-created code-location)) + (filename (code-location-debug-source-name code-location)) + (*readtable* (guess-readtable-for-filename filename)) + (source-code (get-source-code filename code-date))) + (with-debootstrapping + (with-input-from-string (s source-code) + (let* ((pos (stream-source-position code-location s)) + (snippet (read-snippet s pos))) + (make-location `(:file ,filename) + `(:position ,pos) + `(:snippet ,snippet))))))) + +(defun code-location-debug-source-name (code-location) + (namestring (truename (#.(swank/backend:choose-symbol + 'sb-c 'debug-source-name + 'sb-c 'debug-source-namestring) + (sb-di::code-location-debug-source code-location))))) + +(defun code-location-debug-source-created (code-location) + (sb-c::debug-source-created + (sb-di::code-location-debug-source code-location))) + +(defun code-location-debug-fun-fun (code-location) + (sb-di:debug-fun-fun (sb-di:code-location-debug-fun code-location))) + +(defun code-location-has-debug-block-info-p (code-location) + (handler-case + (progn (sb-di:code-location-debug-block code-location) + t) + (sb-di:no-debug-blocks () nil))) + +(defun stream-source-position (code-location stream) + (let* ((cloc (sb-debug::maybe-block-start-location code-location)) + (tlf-number (sb-di::code-location-toplevel-form-offset cloc)) + (form-number (sb-di::code-location-form-number cloc))) + (multiple-value-bind (tlf pos-map) (read-source-form tlf-number stream) + (let* ((path-table (sb-di::form-number-translations tlf 0)) + (path (cond ((<= (length path-table) form-number) + (warn "inconsistent form-number-translations") + (list 0)) + (t + (reverse (cdr (aref path-table form-number))))))) + (source-path-source-position path tlf pos-map))))) + +(defun string-source-position (code-location string) + (with-input-from-string (s string) + (stream-source-position code-location s))) + +;;; source-path-file-position and friends are in source-path-parser + +(defimplementation frame-source-location (index) + (converting-errors-to-error-location + (code-location-source-location + (sb-di:frame-code-location (nth-frame index))))) + +(defvar *keep-non-valid-locals* nil) + +(defun frame-debug-vars (frame) + "Return a vector of debug-variables in frame." + (let ((all-vars (sb-di::debug-fun-debug-vars (sb-di:frame-debug-fun frame)))) + (cond (*keep-non-valid-locals* all-vars) + (t (let ((loc (sb-di:frame-code-location frame))) + (remove-if (lambda (var) + (ecase (sb-di:debug-var-validity var loc) + (:valid nil) + ((:invalid :unknown) t))) + all-vars)))))) + +(defun debug-var-value (var frame location) + (ecase (sb-di:debug-var-validity var location) + (:valid (sb-di:debug-var-value var frame)) + ((:invalid :unknown) ':))) + +(defun debug-var-info (var) + ;; Introduced by SBCL 1.0.49.76. + (let ((s (find-symbol "DEBUG-VAR-INFO" :sb-di))) + (when (and s (fboundp s)) + (funcall s var)))) + +(defimplementation frame-locals (index) + (let* ((frame (nth-frame index)) + (loc (sb-di:frame-code-location frame)) + (vars (frame-debug-vars frame)) + ;; Since SBCL 1.0.49.76 PREPROCESS-FOR-EVAL understands SB-DEBUG::MORE + ;; specially. + (more-name (or (find-symbol "MORE" :sb-debug) 'more)) + (more-context nil) + (more-count nil)) + (when vars + (let ((locals + (loop for v across vars + unless + (case (debug-var-info v) + (:more-context + (setf more-context (debug-var-value v frame loc)) + t) + (:more-count + (setf more-count (debug-var-value v frame loc)) + t)) + collect + (list :name (sb-di:debug-var-symbol v) + :id (sb-di:debug-var-id v) + :value (debug-var-value v frame loc))))) + (when (and more-context more-count) + (setf locals (append locals + (list + (list :name more-name + :id 0 + :value (multiple-value-list + (sb-c:%more-arg-values + more-context + 0 more-count))))))) + locals)))) + +(defimplementation frame-var-value (frame var) + (let* ((frame (nth-frame frame)) + (vars (frame-debug-vars frame)) + (loc (sb-di:frame-code-location frame)) + (dvar (if (= var (length vars)) + ;; If VAR is out of bounds, it must be the fake var + ;; we made up for &MORE. + (let* ((context-var (find :more-context vars + :key #'debug-var-info)) + (more-context (debug-var-value context-var frame + loc)) + (count-var (find :more-count vars + :key #'debug-var-info)) + (more-count (debug-var-value count-var frame loc))) + (return-from frame-var-value + (multiple-value-list (sb-c:%more-arg-values + more-context + 0 more-count)))) + (aref vars var)))) + (debug-var-value dvar frame loc))) + +(defimplementation frame-catch-tags (index) + (mapcar #'car (sb-di:frame-catches (nth-frame index)))) + +(defimplementation eval-in-frame (form index) + (let ((frame (nth-frame index))) + (funcall (the function + (sb-di:preprocess-for-eval form + (sb-di:frame-code-location frame))) + frame))) + +(defimplementation frame-package (frame-number) + (let* ((frame (nth-frame frame-number)) + (fun (sb-di:debug-fun-fun (sb-di:frame-debug-fun frame)))) + (when fun + (let ((name (function-name fun))) + (typecase name + (null nil) + (symbol (symbol-package name)) + ((cons (eql setf) (cons symbol)) (symbol-package (cadr name)))))))) + +#+#.(swank/sbcl::sbcl-with-restart-frame) +(progn + (defimplementation return-from-frame (index form) + (let* ((frame (nth-frame index))) + (cond ((sb-debug:frame-has-debug-tag-p frame) + (let ((values (multiple-value-list (eval-in-frame form index)))) + (sb-debug:unwind-to-frame-and-call frame + (lambda () + (values-list values))))) + (t (format nil "Cannot return from frame: ~S" frame))))) + + (defimplementation restart-frame (index) + (let ((frame (nth-frame index))) + (when (sb-debug:frame-has-debug-tag-p frame) + (multiple-value-bind (fname args) (sb-debug::frame-call frame) + (multiple-value-bind (fun arglist) + (if (and (sb-int:legal-fun-name-p fname) (fboundp fname)) + (values (fdefinition fname) args) + (values (sb-di:debug-fun-fun (sb-di:frame-debug-fun frame)) + (sb-debug::frame-args-as-list frame))) + (when (functionp fun) + (sb-debug:unwind-to-frame-and-call + frame + (lambda () + ;; Ensure TCO. + (declare (optimize (debug 0))) + (apply fun arglist))))))) + (format nil "Cannot restart frame: ~S" frame)))) + +;; FIXME: this implementation doesn't unwind the stack before +;; re-invoking the function, but it's better than no implementation at +;; all. +#-#.(swank/sbcl::sbcl-with-restart-frame) +(progn + (defun sb-debug-catch-tag-p (tag) + (and (symbolp tag) + (not (symbol-package tag)) + (string= tag :sb-debug-catch-tag))) + + (defimplementation return-from-frame (index form) + (let* ((frame (nth-frame index)) + (probe (assoc-if #'sb-debug-catch-tag-p + (sb-di::frame-catches frame)))) + (cond (probe (throw (car probe) (eval-in-frame form index))) + (t (format nil "Cannot return from frame: ~S" frame))))) + + (defimplementation restart-frame (index) + (let ((frame (nth-frame index))) + (return-from-frame index (sb-debug::frame-call-as-list frame))))) + +;;;;; reference-conditions + +(defimplementation print-condition (condition stream) + (let ((sb-int:*print-condition-references* nil)) + (princ condition stream))) + + +;;;; Profiling + +(defimplementation profile (fname) + (when fname (eval `(sb-profile:profile ,fname)))) + +(defimplementation unprofile (fname) + (when fname (eval `(sb-profile:unprofile ,fname)))) + +(defimplementation unprofile-all () + (sb-profile:unprofile) + "All functions unprofiled.") + +(defimplementation profile-report () + (sb-profile:report)) + +(defimplementation profile-reset () + (sb-profile:reset) + "Reset profiling counters.") + +(defimplementation profiled-functions () + (sb-profile:profile)) + +(defimplementation profile-package (package callers methods) + (declare (ignore callers methods)) + (eval `(sb-profile:profile ,(package-name (find-package package))))) + + +;;;; Inspector + +(defmethod emacs-inspect ((o t)) + (cond ((sb-di::indirect-value-cell-p o) + (label-value-line* (:value (sb-kernel:value-cell-ref o)))) + (t + (multiple-value-bind (text label parts) (sb-impl::inspected-parts o) + (list* (string-right-trim '(#\Newline) text) + '(:newline) + (if label + (loop for (l . v) in parts + append (label-value-line l v)) + (loop for value in parts + for i from 0 + append (label-value-line i value)))))))) + +(defmethod emacs-inspect ((o function)) + (cond ((sb-kernel:simple-fun-p o) + (label-value-line* + (:name (sb-kernel:%simple-fun-name o)) + (:arglist (sb-kernel:%simple-fun-arglist o)) + (:next (sb-kernel:%simple-fun-next o)) + (:type (sb-kernel:%simple-fun-type o)) + (:code (sb-kernel:fun-code-header o)))) + ((sb-kernel:closurep o) + (append + (label-value-line :function (sb-kernel:%closure-fun o)) + `("Closed over values:" (:newline)) + (loop for i below (1- (sb-kernel:get-closure-length o)) + append (label-value-line + i (sb-kernel:%closure-index-ref o i))))) + (t (call-next-method o)))) + +(defmethod emacs-inspect ((o sb-kernel:code-component)) + (append + (label-value-line* + (:code-size (sb-kernel:%code-code-size o)) + (:entry-points (sb-kernel:%code-entry-points o)) + (:debug-info (sb-kernel:%code-debug-info o))) + `("Constants:" (:newline)) + (loop for i from sb-vm:code-constants-offset + below + (#.(swank/backend:choose-symbol 'sb-kernel 'code-header-words + 'sb-kernel 'get-header-data) + o) + append (label-value-line i (sb-kernel:code-header-ref o i))) + `("Code:" (:newline) + ,(with-output-to-string (s) + (sb-disassem:disassemble-code-component o :stream s))))) + +(defmethod emacs-inspect ((o sb-ext:weak-pointer)) + (label-value-line* + (:value (sb-ext:weak-pointer-value o)))) + +(defmethod emacs-inspect ((o sb-kernel:fdefn)) + (label-value-line* + (:name (sb-kernel:fdefn-name o)) + (:function (sb-kernel:fdefn-fun o)))) + +(defmethod emacs-inspect :around ((o generic-function)) + (append + (call-next-method) + (label-value-line* + (:pretty-arglist (sb-pcl::generic-function-pretty-arglist o)) + (:initial-methods (sb-pcl::generic-function-initial-methods o)) + ))) + + +;;;; Multiprocessing + +#+(and sb-thread + #.(swank/backend:with-symbol "THREAD-NAME" "SB-THREAD")) +(progn + (defvar *thread-id-counter* 0) + + (defvar *thread-id-counter-lock* + (sb-thread:make-mutex :name "thread id counter lock")) + + (defun next-thread-id () + (sb-thread:with-mutex (*thread-id-counter-lock*) + (incf *thread-id-counter*))) + + (defparameter *thread-id-map* (make-hash-table)) + + ;; This should be a thread -> id map but as weak keys are not + ;; supported it is id -> map instead. + (defvar *thread-id-map-lock* + (sb-thread:make-mutex :name "thread id map lock")) + + (defimplementation spawn (fn &key name) + (sb-thread:make-thread fn :name name)) + + (defimplementation thread-id (thread) + (block thread-id + (sb-thread:with-mutex (*thread-id-map-lock*) + (loop for id being the hash-key in *thread-id-map* + using (hash-value thread-pointer) + do + (let ((maybe-thread (sb-ext:weak-pointer-value thread-pointer))) + (cond ((null maybe-thread) + ;; the value is gc'd, remove it manually + (remhash id *thread-id-map*)) + ((eq thread maybe-thread) + (return-from thread-id id))))) + ;; lazy numbering + (let ((id (next-thread-id))) + (setf (gethash id *thread-id-map*) (sb-ext:make-weak-pointer thread)) + id)))) + + (defimplementation find-thread (id) + (sb-thread:with-mutex (*thread-id-map-lock*) + (let ((thread-pointer (gethash id *thread-id-map*))) + (if thread-pointer + (let ((maybe-thread (sb-ext:weak-pointer-value thread-pointer))) + (if maybe-thread + maybe-thread + ;; the value is gc'd, remove it manually + (progn + (remhash id *thread-id-map*) + nil))) + nil)))) + + (defimplementation thread-name (thread) + ;; sometimes the name is not a string (e.g. NIL) + (princ-to-string (sb-thread:thread-name thread))) + + (defimplementation thread-status (thread) + (if (sb-thread:thread-alive-p thread) + "Running" + "Stopped")) + + (defimplementation make-lock (&key name) + (sb-thread:make-mutex :name name)) + + (defimplementation call-with-lock-held (lock function) + (declare (type function function)) + (sb-thread:with-recursive-lock (lock) (funcall function))) + + (defimplementation current-thread () + sb-thread:*current-thread*) + + (defimplementation all-threads () + (sb-thread:list-all-threads)) + + (defimplementation interrupt-thread (thread fn) + (sb-thread:interrupt-thread thread fn)) + + (defimplementation kill-thread (thread) + (sb-thread:terminate-thread thread)) + + (defimplementation thread-alive-p (thread) + (sb-thread:thread-alive-p thread)) + + (defvar *mailbox-lock* (sb-thread:make-mutex :name "mailbox lock")) + (defvar *mailboxes* (list)) + (declaim (type list *mailboxes*)) + + (defstruct (mailbox (:conc-name mailbox.)) + thread + (mutex (sb-thread:make-mutex)) + (waitqueue (sb-thread:make-waitqueue)) + (queue '() :type list)) + + (defun mailbox (thread) + "Return THREAD's mailbox." + (sb-thread:with-mutex (*mailbox-lock*) + (or (find thread *mailboxes* :key #'mailbox.thread) + (let ((mb (make-mailbox :thread thread))) + (push mb *mailboxes*) + mb)))) + + (defimplementation wake-thread (thread) + (let* ((mbox (mailbox thread)) + (mutex (mailbox.mutex mbox))) + (sb-thread:with-recursive-lock (mutex) + (sb-thread:condition-broadcast (mailbox.waitqueue mbox))))) + + (defimplementation send (thread message) + (let* ((mbox (mailbox thread)) + (mutex (mailbox.mutex mbox))) + (sb-thread:with-mutex (mutex) + (setf (mailbox.queue mbox) + (nconc (mailbox.queue mbox) (list message))) + (sb-thread:condition-broadcast (mailbox.waitqueue mbox))))) + + (defimplementation receive-if (test &optional timeout) + (let* ((mbox (mailbox (current-thread))) + (mutex (mailbox.mutex mbox)) + (waitq (mailbox.waitqueue mbox))) + (assert (or (not timeout) (eq timeout t))) + (loop + (check-slime-interrupts) + (sb-thread:with-mutex (mutex) + (let* ((q (mailbox.queue mbox)) + (tail (member-if test q))) + (when tail + (setf (mailbox.queue mbox) (nconc (ldiff q tail) (cdr tail))) + (return (car tail)))) + (when (eq timeout t) (return (values nil t))) + (sb-thread:condition-wait waitq mutex))))) + + (let ((alist '()) + (mutex (sb-thread:make-mutex :name "register-thread"))) + + (defimplementation register-thread (name thread) + (declare (type symbol name)) + (sb-thread:with-mutex (mutex) + (etypecase thread + (null + (setf alist (delete name alist :key #'car))) + (sb-thread:thread + (let ((probe (assoc name alist))) + (cond (probe (setf (cdr probe) thread)) + (t (setf alist (acons name thread alist)))))))) + nil) + + (defimplementation find-registered (name) + (sb-thread:with-mutex (mutex) + (cdr (assoc name alist)))))) + +(defimplementation quit-lisp () + #+#.(swank/backend:with-symbol 'exit 'sb-ext) + (sb-ext:exit) + #-#.(swank/backend:with-symbol 'exit 'sb-ext) + (progn + #+sb-thread + (dolist (thread (remove (current-thread) (all-threads))) + (ignore-errors (sb-thread:terminate-thread thread))) + (sb-ext:quit))) + + + +;;Trace implementations +;;In SBCL, we have: +;; (trace ) +;; (trace :methods ') ;to trace all methods of the gf +;; (trace (method ? (+))) +;; can be a normal name or a (setf name) + +(defun toggle-trace-aux (fspec &rest args) + (cond ((member fspec (eval '(trace)) :test #'equal) + (eval `(untrace ,fspec)) + (format nil "~S is now untraced." fspec)) + (t + (eval `(trace ,@(if args `(:encapsulate nil) (list)) ,fspec ,@args)) + (format nil "~S is now traced." fspec)))) + +(defun process-fspec (fspec) + (cond ((consp fspec) + (ecase (first fspec) + ((:defun :defgeneric) (second fspec)) + ((:defmethod) `(method ,@(rest fspec))) + ((:labels) `(labels ,(process-fspec (second fspec)) ,(third fspec))) + ((:flet) `(flet ,(process-fspec (second fspec)) ,(third fspec))))) + (t + fspec))) + +(defimplementation toggle-trace (spec) + (ecase (car spec) + ((setf) + (toggle-trace-aux spec)) + ((:defmethod) + (toggle-trace-aux `(sb-pcl::fast-method ,@(rest (process-fspec spec))))) + ((:defgeneric) + (toggle-trace-aux (second spec) :methods t)) + ((:call) + (destructuring-bind (caller callee) (cdr spec) + (toggle-trace-aux callee :wherein (list (process-fspec caller))))))) + +;;; Weak datastructures + +(defimplementation make-weak-key-hash-table (&rest args) + #+#.(swank/sbcl::sbcl-with-weak-hash-tables) + (apply #'make-hash-table :weakness :key args) + #-#.(swank/sbcl::sbcl-with-weak-hash-tables) + (apply #'make-hash-table args)) + +(defimplementation make-weak-value-hash-table (&rest args) + #+#.(swank/sbcl::sbcl-with-weak-hash-tables) + (apply #'make-hash-table :weakness :value args) + #-#.(swank/sbcl::sbcl-with-weak-hash-tables) + (apply #'make-hash-table args)) + +(defimplementation hash-table-weakness (hashtable) + #+#.(swank/sbcl::sbcl-with-weak-hash-tables) + (sb-ext:hash-table-weakness hashtable)) + +;;; Floating point + +(defimplementation float-nan-p (float) + (sb-ext:float-nan-p float)) + +(defimplementation float-infinity-p (float) + (sb-ext:float-infinity-p float)) + +#-win32 +(defimplementation save-image (filename &optional restart-function) + (flet ((restart-sbcl () + (sb-debug::enable-debugger) + (setf sb-impl::*descriptor-handlers* nil) + (funcall restart-function))) + (let ((pid (sb-posix:fork))) + (cond ((= pid 0) + (sb-debug::disable-debugger) + (apply #'sb-ext:save-lisp-and-die filename + (when restart-function + (list :toplevel #'restart-sbcl)))) + (t + (multiple-value-bind (rpid status) (sb-posix:waitpid pid 0) + (assert (= pid rpid)) + (assert (and (sb-posix:wifexited status) + (zerop (sb-posix:wexitstatus status)))))))))) + +#+unix +(progn + (sb-alien:define-alien-routine ("execv" sys-execv) sb-alien:int + (program sb-alien:c-string) + (argv (* sb-alien:c-string))) + + (defun execv (program args) + "Replace current executable with another one." + (let ((a-args (sb-alien:make-alien sb-alien:c-string + (+ 1 (length args))))) + (unwind-protect + (progn + (loop for index from 0 by 1 + and item in (append args '(nil)) + do (setf (sb-alien:deref a-args index) + item)) + (when (minusp + (sys-execv program a-args)) + (error "execv(3) returned."))) + (sb-alien:free-alien a-args)))) + + (defun runtime-pathname () + #+#.(swank/backend:with-symbol + '*runtime-pathname* 'sb-ext) + sb-ext:*runtime-pathname* + #-#.(swank/backend:with-symbol + '*runtime-pathname* 'sb-ext) + (car sb-ext:*posix-argv*)) + + (defimplementation exec-image (image-file args) + (loop with fd-arg = + (loop for arg in args + and key = "" then arg + when (string-equal key "--swank-fd") + return (parse-integer arg)) + for my-fd from 3 to 1024 + when (/= my-fd fd-arg) + do (ignore-errors (sb-posix:fcntl my-fd sb-posix:f-setfd 1))) + (let* ((self-string (pathname-to-filename (runtime-pathname)))) + (execv + self-string + (apply 'list self-string "--core" image-file args))))) + +(defimplementation make-fd-stream (fd external-format) + (sb-sys:make-fd-stream fd :input t :output t + :element-type 'character + :buffering :full + :dual-channel-p t + :external-format external-format)) + +#-win32 +(defimplementation background-save-image (filename &key restart-function + completion-function) + (flet ((restart-sbcl () + (sb-debug::enable-debugger) + (setf sb-impl::*descriptor-handlers* nil) + (funcall restart-function))) + (multiple-value-bind (pipe-in pipe-out) (sb-posix:pipe) + (let ((pid (sb-posix:fork))) + (cond ((= pid 0) + (sb-posix:close pipe-in) + (sb-debug::disable-debugger) + (apply #'sb-ext:save-lisp-and-die filename + (when restart-function + (list :toplevel #'restart-sbcl)))) + (t + (sb-posix:close pipe-out) + (sb-sys:add-fd-handler + pipe-in :input + (lambda (fd) + (sb-sys:invalidate-descriptor fd) + (sb-posix:close fd) + (multiple-value-bind (rpid status) (sb-posix:waitpid pid 0) + (assert (= pid rpid)) + (assert (sb-posix:wifexited status)) + (funcall completion-function + (zerop (sb-posix:wexitstatus status)))))))))))) + +(pushnew 'deinit-log-output sb-ext:*save-hooks*) + + +;;;; wrap interface implementation + +(defun sbcl-version>= (&rest subversions) + #+#.(swank/backend:with-symbol 'assert-version->= 'sb-ext) + (values (ignore-errors (apply #'sb-ext:assert-version->= subversions) t)) + #-#.(swank/backend:with-symbol 'assert-version->= 'sb-ext) + nil) + +(defimplementation wrap (spec indicator &key before after replace) + (when (wrapped-p spec indicator) + (warn "~a already wrapped with indicator ~a, unwrapping first" + spec indicator) + (sb-int:unencapsulate spec indicator)) + (sb-int:encapsulate spec indicator + #-#.(swank/backend:with-symbol 'arg-list 'sb-int) + (lambda (function &rest args) + (sbcl-wrap spec before after replace function args)) + #+#.(swank/backend:with-symbol 'arg-list 'sb-int) + (if (sbcl-version>= 1 1 16) + (lambda () + (sbcl-wrap spec before after replace + (symbol-value 'sb-int:basic-definition) + (symbol-value 'sb-int:arg-list))) + `(sbcl-wrap ',spec ,before ,after ,replace + (symbol-value 'sb-int:basic-definition) + (symbol-value 'sb-int:arg-list))))) + +(defimplementation unwrap (spec indicator) + (sb-int:unencapsulate spec indicator)) + +(defimplementation wrapped-p (spec indicator) + (sb-int:encapsulated-p spec indicator)) + +(defun sbcl-wrap (spec before after replace function args) + (declare (ignore spec)) + (let (retlist completed) + (unwind-protect + (progn + (when before + (funcall before args)) + (setq retlist (multiple-value-list (if replace + (funcall replace + args) + (apply function args)))) + (setq completed t) + (values-list retlist)) + (when after + (funcall after (if completed retlist :exited-non-locally)))))) + +#+#.(swank/backend:with-symbol 'comma-expr 'sb-impl) +(progn + (defmethod sexp-in-bounds-p ((s sb-impl::comma) i) + (= i 1)) + + (defmethod sexp-ref ((s sb-impl::comma) i) + (sb-impl::comma-expr s))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/scl.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/scl.lisp new file mode 100644 index 0000000..7327133 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/scl.lisp @@ -0,0 +1,1726 @@ +;;; -*- indent-tabs-mode: nil; outline-regexp: ";;;;+" -*- +;;; +;;; Scieneer Common Lisp code for SLIME. +;;; +;;; This code has been placed in the Public Domain. All warranties +;;; are disclaimed. +;;; + +(defpackage swank/scl + (:use cl swank/backend swank/source-path-parser swank/source-file-cache)) + +(in-package swank/scl) + + + +;;; swank-mop + +(import-swank-mop-symbols :clos '(:slot-definition-documentation)) + +(defun swank-mop:slot-definition-documentation (slot) + (documentation slot t)) + + +;;;; TCP server +;;; +;;; SCL only supports the :spawn communication style. +;;; + +(defimplementation preferred-communication-style () + :spawn) + +(defimplementation create-socket (host port &key backlog) + (let ((addr (resolve-hostname host))) + (ext:create-inet-listener port :stream :host addr :reuse-address t + :backlog (or backlog 5)))) + +(defimplementation local-port (socket) + (nth-value 1 (ext::get-socket-host-and-port (socket-fd socket)))) + +(defimplementation close-socket (socket) + (ext:close-socket (socket-fd socket))) + +(defimplementation accept-connection (socket + &key external-format buffering timeout) + (let ((buffering (or buffering :full)) + (fd (socket-fd socket))) + (loop + (let ((ready (sys:wait-until-fd-usable fd :input timeout))) + (unless ready + (error "Timeout accepting connection on socket: ~S~%" socket))) + (let ((new-fd (ignore-errors (ext:accept-tcp-connection fd)))) + (when new-fd + (return (make-socket-io-stream new-fd external-format + (ecase buffering + ((t) :full) + ((nil) :none) + (:line :line))))))))) + +(defimplementation set-stream-timeout (stream timeout) + (check-type timeout (or null real)) + (if (fboundp 'ext::stream-timeout) + (setf (ext::stream-timeout stream) timeout) + (setf (slot-value (slot-value stream 'lisp::stream) 'lisp::timeout) + timeout))) + +;;;;; Sockets + +(defun socket-fd (socket) + "Return the file descriptor for the socket represented by 'socket." + (etypecase socket + (fixnum socket) + (stream (sys:fd-stream-fd socket)))) + +(defun resolve-hostname (hostname) + "Return the IP address of 'hostname as an integer (in host byte-order)." + (let ((hostent (ext:lookup-host-entry hostname))) + (car (ext:host-entry-addr-list hostent)))) + +(defvar *external-format-to-coding-system* + '((:iso-8859-1 + "latin-1" "latin-1-unix" "iso-latin-1-unix" + "iso-8859-1" "iso-8859-1-unix") + (:utf-8 "utf-8" "utf-8-unix") + (:euc-jp "euc-jp" "euc-jp-unix"))) + +(defimplementation find-external-format (coding-system) + (car (rassoc-if (lambda (x) (member coding-system x :test #'equal)) + *external-format-to-coding-system*))) + +(defun make-socket-io-stream (fd external-format buffering) + "Create a new input/output fd-stream for 'fd." + (cond ((not external-format) + (sys:make-fd-stream fd :input t :output t :buffering buffering + :element-type '(unsigned-byte 8))) + (t + (let* ((stream (sys:make-fd-stream fd :input t :output t + :element-type 'base-char + :buffering buffering + :external-format external-format))) + ;; Ignore character conversion errors. Without this the + ;; communication channel is prone to lockup if a character + ;; conversion error occurs. + (setf (lisp::character-conversion-stream-input-error-value stream) + #\?) + (setf (lisp::character-conversion-stream-output-error-value stream) + #\?) + stream)))) + + +;;;; Stream handling + +(defimplementation gray-package-name () + '#:ext) + + +;;;; Compilation Commands + +(defvar *previous-compiler-condition* nil + "Used to detect duplicates.") + +(defvar *previous-context* nil + "Previous compiler error context.") + +(defvar *buffer-name* nil + "The name of the Emacs buffer we are compiling from. + Nil if we aren't compiling from a buffer.") + +(defvar *buffer-start-position* nil) +(defvar *buffer-substring* nil) + +(defimplementation call-with-compilation-hooks (function) + (let ((*previous-compiler-condition* nil) + (*previous-context* nil) + (*print-readably* nil)) + (handler-bind ((c::compiler-error #'handle-notification-condition) + (c::style-warning #'handle-notification-condition) + (c::warning #'handle-notification-condition)) + (funcall function)))) + +(defimplementation swank-compile-file (input-file output-file + load-p external-format + &key policy) + (declare (ignore policy)) + (with-compilation-hooks () + (let ((*buffer-name* nil) + (ext:*ignore-extra-close-parentheses* nil)) + (multiple-value-bind (output-file warnings-p failure-p) + (compile-file input-file + :output-file output-file + :external-format external-format) + (values output-file warnings-p + (or failure-p + (when load-p + ;; Cache the latest source file for definition-finding. + (source-cache-get input-file + (file-write-date input-file)) + (not (load output-file))))))))) + +(defimplementation swank-compile-string (string &key buffer position filename + policy) + (declare (ignore filename policy)) + (with-compilation-hooks () + (let ((*buffer-name* buffer) + (*buffer-start-position* position) + (*buffer-substring* string)) + (with-input-from-string (stream string) + (ext:compile-from-stream + stream + :source-info `(:emacs-buffer ,buffer + :emacs-buffer-offset ,position + :emacs-buffer-string ,string)))))) + + +;;;;; Trapping notes +;;; +;;; We intercept conditions from the compiler and resignal them as +;;; `swank:compiler-condition's. + +(defun handle-notification-condition (condition) + "Handle a condition caused by a compiler warning." + (unless (eq condition *previous-compiler-condition*) + (let ((context (c::find-error-context nil))) + (setq *previous-compiler-condition* condition) + (setq *previous-context* context) + (signal-compiler-condition condition context)))) + +(defun signal-compiler-condition (condition context) + (signal 'compiler-condition + :original-condition condition + :severity (severity-for-emacs condition) + :message (brief-compiler-message-for-emacs condition) + :source-context (compiler-error-context context) + :location (if (read-error-p condition) + (read-error-location condition) + (compiler-note-location context)))) + +(defun severity-for-emacs (condition) + "Return the severity of 'condition." + (etypecase condition + ((satisfies read-error-p) :read-error) + (c::compiler-error :error) + (c::style-warning :note) + (c::warning :warning))) + +(defun read-error-p (condition) + (eq (type-of condition) 'c::compiler-read-error)) + +(defun brief-compiler-message-for-emacs (condition) + "Briefly describe a compiler error for Emacs. + When Emacs presents the message it already has the source popped up + and the source form highlighted. This makes much of the information in + the error-context redundant." + (princ-to-string condition)) + +(defun compiler-error-context (error-context) + "Describe a compiler error for Emacs including context information." + (declare (type (or c::compiler-error-context null) error-context)) + (multiple-value-bind (enclosing source) + (if error-context + (values (c::compiler-error-context-enclosing-source error-context) + (c::compiler-error-context-source error-context))) + (if (and enclosing source) + (format nil "~@[--> ~{~<~%--> ~1:;~A~> ~}~%~]~@[~{==>~%~A~^~%~}~]" + enclosing source)))) + +(defun read-error-location (condition) + (let* ((finfo (car (c::source-info-current-file c::*source-info*))) + (file (c::file-info-name finfo)) + (pos (c::compiler-read-error-position condition))) + (cond ((and (eq file :stream) *buffer-name*) + (make-location (list :buffer *buffer-name*) + (list :offset *buffer-start-position* pos))) + ((and (pathnamep file) (not *buffer-name*)) + (make-location (list :file (unix-truename file)) + (list :position (1+ pos)))) + (t (break))))) + +(defun compiler-note-location (context) + "Derive the location of a complier message from its context. + Return a `location' record, or (:error ) on failure." + (if (null context) + (note-error-location) + (let ((file (c::compiler-error-context-file-name context)) + (source (c::compiler-error-context-original-source context)) + (path + (reverse + (c::compiler-error-context-original-source-path context)))) + (or (locate-compiler-note file source path) + (note-error-location))))) + +(defun note-error-location () + "Pseudo-location for notes that can't be located." + (list :error "No error location available.")) + +(defun locate-compiler-note (file source source-path) + (cond ((and (eq file :stream) *buffer-name*) + ;; Compiling from a buffer + (make-location (list :buffer *buffer-name*) + (list :offset *buffer-start-position* + (source-path-string-position + source-path *buffer-substring*)))) + ((and (pathnamep file) (null *buffer-name*)) + ;; Compiling from a file + (make-location (list :file (unix-truename file)) + (list :position (1+ (source-path-file-position + source-path file))))) + ((and (eq file :lisp) (stringp source)) + ;; No location known, but we have the source form. + ;; XXX How is this case triggered? -luke (16/May/2004) + ;; This can happen if the compiler needs to expand a macro + ;; but the macro-expander is not yet compiled. Calling the + ;; (interpreted) macro-expander triggers IR1 conversion of + ;; the lambda expression for the expander and invokes the + ;; compiler recursively. + (make-location (list :source-form source) + (list :position 1))))) + +(defun unix-truename (pathname) + (ext:unix-namestring (truename pathname))) + + + +;;; TODO +(defimplementation who-calls (name) nil) +(defimplementation who-references (name) nil) +(defimplementation who-binds (name) nil) +(defimplementation who-sets (name) nil) +(defimplementation who-specializes (symbol) nil) +(defimplementation who-macroexpands (name) nil) + + +;;;; Find callers and callees +;;; +;;; Find callers and callees by looking at the constant pool of +;;; compiled code objects. We assume every fdefn object in the +;;; constant pool corresponds to a call to that function. A better +;;; strategy would be to use the disassembler to find actual +;;; call-sites. + +(declaim (inline map-code-constants)) +(defun map-code-constants (code fn) + "Call 'fn for each constant in 'code's constant pool." + (check-type code kernel:code-component) + (loop for i from vm:code-constants-offset below (kernel:get-header-data code) + do (funcall fn (kernel:code-header-ref code i)))) + +(defun function-callees (function) + "Return 'function's callees as a list of functions." + (let ((callees '())) + (map-code-constants + (vm::find-code-object function) + (lambda (obj) + (when (kernel:fdefn-p obj) + (push (kernel:fdefn-function obj) callees)))) + callees)) + +(declaim (ext:maybe-inline map-allocated-code-components)) +(defun map-allocated-code-components (spaces fn) + "Call FN for each allocated code component in one of 'spaces. FN + receives the object as argument. 'spaces should be a list of the + symbols :dynamic, :static, or :read-only." + (dolist (space spaces) + (declare (inline vm::map-allocated-objects) + (optimize (ext:inhibit-warnings 3))) + (vm::map-allocated-objects + (lambda (obj header size) + (declare (type fixnum size) (ignore size)) + (when (= vm:code-header-type header) + (funcall fn obj))) + space))) + +(declaim (ext:maybe-inline map-caller-code-components)) +(defun map-caller-code-components (function spaces fn) + "Call 'fn for each code component with a fdefn for 'function in its + constant pool." + (let ((function (coerce function 'function))) + (declare (inline map-allocated-code-components)) + (map-allocated-code-components + spaces + (lambda (obj) + (map-code-constants + obj + (lambda (constant) + (when (and (kernel:fdefn-p constant) + (eq (kernel:fdefn-function constant) + function)) + (funcall fn obj)))))))) + +(defun function-callers (function &optional (spaces '(:read-only :static + :dynamic))) + "Return 'function's callers. The result is a list of code-objects." + (let ((referrers '())) + (declare (inline map-caller-code-components)) + (map-caller-code-components function spaces + (lambda (code) (push code referrers))) + referrers)) + +(defun debug-info-definitions (debug-info) + "Return the defintions for a debug-info. This should only be used + for code-object without entry points, i.e., byte compiled + code (are theree others?)" + ;; This mess has only been tested with #'ext::skip-whitespace, a + ;; byte-compiled caller of #'read-char . + (check-type debug-info (and (not c::compiled-debug-info) c::debug-info)) + (let ((name (c::debug-info-name debug-info)) + (source (c::debug-info-source debug-info))) + (destructuring-bind (first) source + (ecase (c::debug-source-from first) + (:file + (list (list name + (make-location + (list :file (unix-truename (c::debug-source-name first))) + (list :function-name (string name)))))))))) + +(defun valid-function-name-p (name) + (or (symbolp name) (and (consp name) + (eq (car name) 'setf) + (symbolp (cadr name)) + (not (cddr name))))) + +(defun code-component-entry-points (code) + "Return a list ((name location) ...) of function definitons for + the code omponent 'code." + (let ((names '())) + (do ((f (kernel:%code-entry-points code) (kernel::%function-next f))) + ((not f)) + (let ((name (kernel:%function-name f))) + (when (valid-function-name-p name) + (push (list name (function-location f)) names)))) + names)) + +(defimplementation list-callers (symbol) + "Return a list ((name location) ...) of callers." + (let ((components (function-callers symbol)) + (xrefs '())) + (dolist (code components) + (let* ((entry (kernel:%code-entry-points code)) + (defs (if entry + (code-component-entry-points code) + ;; byte compiled stuff + (debug-info-definitions + (kernel:%code-debug-info code))))) + (setq xrefs (nconc defs xrefs)))) + xrefs)) + +(defimplementation list-callees (symbol) + (let ((fns (function-callees symbol))) + (mapcar (lambda (fn) + (list (kernel:%function-name fn) + (function-location fn))) + fns))) + + +;;;; Resolving source locations +;;; +;;; Our mission here is to "resolve" references to code locations into +;;; actual file/buffer names and character positions. The references +;;; we work from come out of the compiler's statically-generated debug +;;; information, such as `code-location''s and `debug-source''s. For +;;; more details, see the "Debugger Programmer's Interface" section of +;;; the SCL manual. +;;; +;;; The first step is usually to find the corresponding "source-path" +;;; for the location. Once we have the source-path we can pull up the +;;; source file and `READ' our way through to the right position. The +;;; main source-code groveling work is done in +;;; `source-path-parser.lisp'. + +(defvar *debug-definition-finding* nil + "When true don't handle errors while looking for definitions. + This is useful when debugging the definition-finding code.") + +(defmacro safe-definition-finding (&body body) + "Execute 'body and return the source-location it returns. + If an error occurs and `*debug-definition-finding*' is false, then + return an error pseudo-location. + + The second return value is 'nil if no error occurs, otherwise it is the + condition object." + `(flet ((body () ,@body)) + (if *debug-definition-finding* + (body) + (handler-case (values (progn ,@body) nil) + (error (c) (values (list :error (princ-to-string c)) c)))))) + +(defun code-location-source-location (code-location) + "Safe wrapper around `code-location-from-source-location'." + (safe-definition-finding + (source-location-from-code-location code-location))) + +(defun source-location-from-code-location (code-location) + "Return the source location for 'code-location." + (let ((debug-fun (di:code-location-debug-function code-location))) + (when (di::bogus-debug-function-p debug-fun) + ;; Those lousy cheapskates! They've put in a bogus debug source + ;; because the code was compiled at a low debug setting. + (error "Bogus debug function: ~A" debug-fun))) + (let* ((debug-source (di:code-location-debug-source code-location)) + (from (di:debug-source-from debug-source)) + (name (di:debug-source-name debug-source))) + (ecase from + (:file + (location-in-file name code-location debug-source)) + (:stream + (location-in-stream code-location debug-source)) + (:lisp + ;; The location comes from a form passed to `compile'. + ;; The best we can do is return the form itself for printing. + (make-location + (list :source-form (with-output-to-string (*standard-output*) + (debug::print-code-location-source-form + code-location 100 t))) + (list :position 1)))))) + +(defun location-in-file (filename code-location debug-source) + "Resolve the source location for 'code-location in 'filename." + (let* ((code-date (di:debug-source-created debug-source)) + (source-code (get-source-code filename code-date))) + (with-input-from-string (s source-code) + (make-location (list :file (unix-truename filename)) + (list :position (1+ (code-location-stream-position + code-location s))) + `(:snippet ,(read-snippet s)))))) + +(defun location-in-stream (code-location debug-source) + "Resolve the source location for a 'code-location from a stream. + This only succeeds if the code was compiled from an Emacs buffer." + (unless (debug-source-info-from-emacs-buffer-p debug-source) + (error "The code is compiled from a non-SLIME stream.")) + (let* ((info (c::debug-source-info debug-source)) + (string (getf info :emacs-buffer-string)) + (position (code-location-string-offset + code-location + string))) + (make-location + (list :buffer (getf info :emacs-buffer)) + (list :offset (getf info :emacs-buffer-offset) position) + (list :snippet (with-input-from-string (s string) + (file-position s position) + (read-snippet s)))))) + +;;;;; Function-name locations +;;; +(defun debug-info-function-name-location (debug-info) + "Return a function-name source-location for 'debug-info. + Function-name source-locations are a fallback for when precise + positions aren't available." + (with-struct (c::debug-info- (fname name) source) debug-info + (with-struct (c::debug-source- info from name) (car source) + (ecase from + (:file + (make-location (list :file (namestring (truename name))) + (list :function-name (string fname)))) + (:stream + (assert (debug-source-info-from-emacs-buffer-p (car source))) + (make-location (list :buffer (getf info :emacs-buffer)) + (list :function-name (string fname)))) + (:lisp + (make-location (list :source-form (princ-to-string (aref name 0))) + (list :position 1))))))) + +(defun debug-source-info-from-emacs-buffer-p (debug-source) + "Does the `info' slot of 'debug-source contain an Emacs buffer location? + This is true for functions that were compiled directly from buffers." + (info-from-emacs-buffer-p (c::debug-source-info debug-source))) + +(defun info-from-emacs-buffer-p (info) + (and info + (consp info) + (eq :emacs-buffer (car info)))) + + +;;;;; Groveling source-code for positions + +(defun code-location-stream-position (code-location stream) + "Return the byte offset of 'code-location in 'stream. Extract the + toplevel-form-number and form-number from 'code-location and use that + to find the position of the corresponding form. + + Finish with 'stream positioned at the start of the code location." + (let* ((location (debug::maybe-block-start-location code-location)) + (tlf-offset (di:code-location-top-level-form-offset location)) + (form-number (di:code-location-form-number location))) + (let ((pos (form-number-stream-position tlf-offset form-number stream))) + (file-position stream pos) + pos))) + +(defun form-number-stream-position (tlf-number form-number stream) + "Return the starting character position of a form in 'stream. + 'tlf-number is the top-level-form number. + 'form-number is an index into a source-path table for the TLF." + (multiple-value-bind (tlf position-map) (read-source-form tlf-number stream) + (let* ((path-table (di:form-number-translations tlf 0)) + (source-path + (if (<= (length path-table) form-number) ; source out of sync? + (list 0) ; should probably signal a condition + (reverse (cdr (aref path-table form-number)))))) + (source-path-source-position source-path tlf position-map)))) + +(defun code-location-string-offset (code-location string) + "Return the byte offset of 'code-location in 'string. + See 'code-location-stream-position." + (with-input-from-string (s string) + (code-location-stream-position code-location s))) + + +;;;; Finding definitions + +;;; There are a great many different types of definition for us to +;;; find. We search for definitions of every kind and return them in a +;;; list. + +(defimplementation find-definitions (name) + (append (function-definitions name) + (setf-definitions name) + (variable-definitions name) + (class-definitions name) + (type-definitions name) + (compiler-macro-definitions name) + (source-transform-definitions name) + (function-info-definitions name) + (ir1-translator-definitions name))) + +;;;;; Functions, macros, generic functions, methods +;;; +;;; We make extensive use of the compile-time debug information that +;;; SCL records, in particular "debug functions" and "code +;;; locations." Refer to the "Debugger Programmer's Interface" section +;;; of the SCL manual for more details. + +(defun function-definitions (name) + "Return definitions for 'name in the \"function namespace\", i.e., + regular functions, generic functions, methods and macros. + 'name can any valid function name (e.g, (setf car))." + (let ((macro? (and (symbolp name) (macro-function name))) + (special? (and (symbolp name) (special-operator-p name))) + (function? (and (valid-function-name-p name) + (ext:info :function :definition name) + (if (symbolp name) (fboundp name) t)))) + (cond (macro? + (list `((defmacro ,name) + ,(function-location (macro-function name))))) + (special? + (list `((:special-operator ,name) + (:error ,(format nil "Special operator: ~S" name))))) + (function? + (let ((function (fdefinition name))) + (if (genericp function) + (generic-function-definitions name function) + (list (list `(function ,name) + (function-location function))))))))) + +;;;;;; Ordinary (non-generic/macro/special) functions +;;; +;;; First we test if FUNCTION is a closure created by defstruct, and +;;; if so extract the defstruct-description (`dd') from the closure +;;; and find the constructor for the struct. Defstruct creates a +;;; defun for the default constructor and we use that as an +;;; approximation to the source location of the defstruct. +;;; +;;; For an ordinary function we return the source location of the +;;; first code-location we find. +;;; +(defun function-location (function) + "Return the source location for FUNCTION." + (cond ((struct-closure-p function) + (struct-closure-location function)) + ((c::byte-function-or-closure-p function) + (byte-function-location function)) + (t + (compiled-function-location function)))) + +(defun compiled-function-location (function) + "Return the location of a regular compiled function." + (multiple-value-bind (code-location error) + (safe-definition-finding (function-first-code-location function)) + (cond (error (list :error (princ-to-string error))) + (t (code-location-source-location code-location))))) + +(defun function-first-code-location (function) + "Return the first code-location we can find for 'function." + (and (function-has-debug-function-p function) + (di:debug-function-start-location + (di:function-debug-function function)))) + +(defun function-has-debug-function-p (function) + (di:function-debug-function function)) + +(defun function-code-object= (closure function) + (and (eq (vm::find-code-object closure) + (vm::find-code-object function)) + (not (eq closure function)))) + + +(defun byte-function-location (fn) + "Return the location of the byte-compiled function 'fn." + (etypecase fn + ((or c::hairy-byte-function c::simple-byte-function) + (let* ((component (c::byte-function-component fn)) + (debug-info (kernel:%code-debug-info component))) + (debug-info-function-name-location debug-info))) + (c::byte-closure + (byte-function-location (c::byte-closure-function fn))))) + +;;; Here we deal with structure accessors. Note that `dd' is a +;;; "defstruct descriptor" structure in SCL. A `dd' describes a +;;; `defstruct''d structure. + +(defun struct-closure-p (function) + "Is 'function a closure created by defstruct?" + (or (function-code-object= function #'kernel::structure-slot-accessor) + (function-code-object= function #'kernel::structure-slot-setter) + (function-code-object= function #'kernel::%defstruct))) + +(defun struct-closure-location (function) + "Return the location of the structure that 'function belongs to." + (assert (struct-closure-p function)) + (safe-definition-finding + (dd-location (struct-closure-dd function)))) + +(defun struct-closure-dd (function) + "Return the defstruct-definition (dd) of FUNCTION." + (assert (= (kernel:get-type function) vm:closure-header-type)) + (flet ((find-layout (function) + (sys:find-if-in-closure + (lambda (x) + (let ((value (if (di::indirect-value-cell-p x) + (c:value-cell-ref x) + x))) + (when (kernel::layout-p value) + (return-from find-layout value)))) + function))) + (kernel:layout-info (find-layout function)))) + +(defun dd-location (dd) + "Return the location of a `defstruct'." + ;; Find the location in a constructor. + (function-location (struct-constructor dd))) + +(defun struct-constructor (dd) + "Return a constructor function from a defstruct definition. +Signal an error if no constructor can be found." + (let ((constructor (or (kernel:dd-default-constructor dd) + (car (kernel::dd-constructors dd))))) + (when (or (null constructor) + (and (consp constructor) (null (car constructor)))) + (error "Cannot find structure's constructor: ~S" + (kernel::dd-name dd))) + (coerce (if (consp constructor) (first constructor) constructor) + 'function))) + +;;;;;; Generic functions and methods + +(defun generic-function-definitions (name function) + "Return the definitions of a generic function and its methods." + (cons (list `(defgeneric ,name) (gf-location function)) + (gf-method-definitions function))) + +(defun gf-location (gf) + "Return the location of the generic function GF." + (definition-source-location gf (clos:generic-function-name gf))) + +(defun gf-method-definitions (gf) + "Return the locations of all methods of the generic function GF." + (mapcar #'method-definition (clos:generic-function-methods gf))) + +(defun method-definition (method) + (list (method-dspec method) + (method-location method))) + +(defun method-dspec (method) + "Return a human-readable \"definition specifier\" for METHOD." + (let* ((gf (clos:method-generic-function method)) + (name (clos:generic-function-name gf)) + (specializers (clos:method-specializers method)) + (qualifiers (clos:method-qualifiers method))) + `(method ,name ,@qualifiers ,specializers + #+nil (clos::unparse-specializers specializers)))) + +;; XXX maybe special case setters/getters +(defun method-location (method) + (function-location (clos:method-function method))) + +(defun genericp (fn) + (typep fn 'generic-function)) + +;;;;;; Types and classes + +(defun type-definitions (name) + "Return `deftype' locations for type NAME." + (maybe-make-definition (ext:info :type :expander name) 'deftype name)) + +(defun maybe-make-definition (function kind name) + "If FUNCTION is non-nil then return its definition location." + (if function + (list (list `(,kind ,name) (function-location function))))) + +(defun class-definitions (name) + "Return the definition locations for the class called NAME." + (if (symbolp name) + (let ((class (find-class name nil))) + (etypecase class + (null '()) + (structure-class + (list (list `(defstruct ,name) + (dd-location (find-dd name))))) + (standard-class + (list (list `(defclass ,name) + (class-location (find-class name))))) + ((or built-in-class + kernel:funcallable-structure-class) + (list (list `(kernel::define-type-class ,name) + `(:error + ,(format nil "No source info for ~A" name))))))))) + +(defun class-location (class) + "Return the `defclass' location for CLASS." + (definition-source-location class (class-name class))) + +(defun find-dd (name) + "Find the defstruct-definition by the name of its structure-class." + (let ((layout (ext:info :type :compiler-layout name))) + (if layout + (kernel:layout-info layout)))) + +(defun condition-class-location (class) + (let ((name (class-name class))) + `(:error ,(format nil "No location info for condition: ~A" name)))) + +(defun make-name-in-file-location (file string) + (multiple-value-bind (filename c) + (ignore-errors + (unix-truename (merge-pathnames (make-pathname :type "lisp") + file))) + (cond (filename (make-location `(:file ,filename) + `(:function-name ,(string string)))) + (t (list :error (princ-to-string c)))))) + +(defun definition-source-location (object name) + `(:error ,(format nil "No source info for: ~A" object))) + +(defun setf-definitions (name) + (let ((function (or (ext:info :setf :inverse name) + (ext:info :setf :expander name)))) + (if function + (list (list `(setf ,name) + (function-location (coerce function 'function))))))) + + +(defun variable-location (symbol) + `(:error ,(format nil "No source info for variable ~S" symbol))) + +(defun variable-definitions (name) + (if (symbolp name) + (multiple-value-bind (kind recorded-p) (ext:info :variable :kind name) + (if recorded-p + (list (list `(variable ,kind ,name) + (variable-location name))))))) + +(defun compiler-macro-definitions (symbol) + (maybe-make-definition (compiler-macro-function symbol) + 'define-compiler-macro + symbol)) + +(defun source-transform-definitions (name) + (maybe-make-definition (ext:info :function :source-transform name) + 'c:def-source-transform + name)) + +(defun function-info-definitions (name) + (let ((info (ext:info :function :info name))) + (if info + (append (loop for transform in (c::function-info-transforms info) + collect (list `(c:deftransform ,name + ,(c::type-specifier + (c::transform-type transform))) + (function-location (c::transform-function + transform)))) + (maybe-make-definition (c::function-info-derive-type info) + 'c::derive-type name) + (maybe-make-definition (c::function-info-optimizer info) + 'c::optimizer name) + (maybe-make-definition (c::function-info-ltn-annotate info) + 'c::ltn-annotate name) + (maybe-make-definition (c::function-info-ir2-convert info) + 'c::ir2-convert name) + (loop for template in (c::function-info-templates info) + collect (list `(c::vop ,(c::template-name template)) + (function-location + (c::vop-info-generator-function + template)))))))) + +(defun ir1-translator-definitions (name) + (maybe-make-definition (ext:info :function :ir1-convert name) + 'c:def-ir1-translator name)) + + +;;;; Documentation. + +(defimplementation describe-symbol-for-emacs (symbol) + (let ((result '())) + (flet ((doc (kind) + (or (documentation symbol kind) :not-documented)) + (maybe-push (property value) + (when value + (setf result (list* property value result))))) + (maybe-push + :variable (multiple-value-bind (kind recorded-p) + (ext:info variable kind symbol) + (declare (ignore kind)) + (if (or (boundp symbol) recorded-p) + (doc 'variable)))) + (when (fboundp symbol) + (maybe-push + (cond ((macro-function symbol) :macro) + ((special-operator-p symbol) :special-operator) + ((genericp (fdefinition symbol)) :generic-function) + (t :function)) + (doc 'function))) + (maybe-push + :setf (if (or (ext:info setf inverse symbol) + (ext:info setf expander symbol)) + (doc 'setf))) + (maybe-push + :type (if (ext:info type kind symbol) + (doc 'type))) + (maybe-push + :class (if (find-class symbol nil) + (doc 'class))) + (maybe-push + :alien-type (if (not (eq (ext:info alien-type kind symbol) :unknown)) + (doc 'alien-type))) + (maybe-push + :alien-struct (if (ext:info alien-type struct symbol) + (doc nil))) + (maybe-push + :alien-union (if (ext:info alien-type union symbol) + (doc nil))) + (maybe-push + :alien-enum (if (ext:info alien-type enum symbol) + (doc nil))) + result))) + +(defimplementation describe-definition (symbol namespace) + (describe (ecase namespace + (:variable + symbol) + ((:function :generic-function) + (symbol-function symbol)) + (:setf + (or (ext:info setf inverse symbol) + (ext:info setf expander symbol))) + (:type + (kernel:values-specifier-type symbol)) + (:class + (find-class symbol)) + (:alien-struct + (ext:info :alien-type :struct symbol)) + (:alien-union + (ext:info :alien-type :union symbol)) + (:alien-enum + (ext:info :alien-type :enum symbol)) + (:alien-type + (ecase (ext:info :alien-type :kind symbol) + (:primitive + (let ((alien::*values-type-okay* t)) + (funcall (ext:info :alien-type :translator symbol) + (list symbol)))) + ((:defined) + (ext:info :alien-type :definition symbol)) + (:unknown :unknown)))))) + +;;;;; Argument lists + +(defimplementation arglist (fun) + (multiple-value-bind (args winp) + (ext:function-arglist fun) + (if winp args :not-available))) + +(defimplementation function-name (function) + (cond ((eval:interpreted-function-p function) + (eval:interpreted-function-name function)) + ((typep function 'generic-function) + (clos:generic-function-name function)) + ((c::byte-function-or-closure-p function) + (c::byte-function-name function)) + (t (kernel:%function-name (kernel:%function-self function))))) + + +;;; A harder case: an approximate arglist is derived from available +;;; debugging information. + +(defun debug-function-arglist (debug-function) + "Derive the argument list of DEBUG-FUNCTION from debug info." + (let ((args (di::debug-function-lambda-list debug-function)) + (required '()) + (optional '()) + (rest '()) + (key '())) + ;; collect the names of debug-vars + (dolist (arg args) + (etypecase arg + (di::debug-variable + (push (di::debug-variable-symbol arg) required)) + ((member :deleted) + (push ':deleted required)) + (cons + (ecase (car arg) + (:keyword + (push (second arg) key)) + (:optional + (push (debug-variable-symbol-or-deleted (second arg)) optional)) + (:rest + (push (debug-variable-symbol-or-deleted (second arg)) rest)))))) + ;; intersperse lambda keywords as needed + (append (nreverse required) + (if optional (cons '&optional (nreverse optional))) + (if rest (cons '&rest (nreverse rest))) + (if key (cons '&key (nreverse key)))))) + +(defun debug-variable-symbol-or-deleted (var) + (etypecase var + (di:debug-variable + (di::debug-variable-symbol var)) + ((member :deleted) + '#:deleted))) + +(defun symbol-debug-function-arglist (fname) + "Return FNAME's debug-function-arglist and %function-arglist. + A utility for debugging DEBUG-FUNCTION-ARGLIST." + (let ((fn (fdefinition fname))) + (values (debug-function-arglist (di::function-debug-function fn)) + (kernel:%function-arglist (kernel:%function-self fn))))) + + +;;;; Miscellaneous. + +(defimplementation macroexpand-all (form &optional env) + (declare (ignore env)) + (macroexpand form)) + +(defimplementation set-default-directory (directory) + (setf (ext:default-directory) (namestring directory)) + ;; Setting *default-pathname-defaults* to an absolute directory + ;; makes the behavior of MERGE-PATHNAMES a bit more intuitive. + (setf *default-pathname-defaults* (pathname (ext:default-directory))) + (default-directory)) + +(defimplementation default-directory () + (namestring (ext:default-directory))) + +(defimplementation pathname-to-filename (pathname) + (ext:unix-namestring pathname nil)) + +(defimplementation getpid () + (unix:unix-getpid)) + +(defimplementation lisp-implementation-type-name () + (if (eq ext:*case-mode* :upper) "scl" "scl-lower")) + +(defimplementation quit-lisp () + (ext:quit)) + +;;; source-path-{stream,file,string,etc}-position moved into +;;; source-path-parser + + +;;;; Debugging + +(defvar *sldb-stack-top*) + +(defimplementation call-with-debugging-environment (debugger-loop-fn) + (let* ((*sldb-stack-top* (or debug:*stack-top-hint* (di:top-frame))) + (debug:*stack-top-hint* nil) + (kernel:*current-level* 0)) + (handler-bind ((di::unhandled-condition + (lambda (condition) + (error 'sldb-condition + :original-condition condition)))) + (funcall debugger-loop-fn)))) + +(defun frame-down (frame) + (handler-case (di:frame-down frame) + (di:no-debug-info () nil))) + +(defun nth-frame (index) + (do ((frame *sldb-stack-top* (frame-down frame)) + (i index (1- i))) + ((zerop i) frame))) + +(defimplementation compute-backtrace (start end) + (let ((end (or end most-positive-fixnum))) + (loop for f = (nth-frame start) then (frame-down f) + for i from start below end + while f collect f))) + +(defimplementation print-frame (frame stream) + (let ((*standard-output* stream)) + (handler-case + (debug::print-frame-call frame :verbosity 1 :number nil) + (error (e) + (ignore-errors (princ e stream)))))) + +(defimplementation frame-source-location (index) + (code-location-source-location (di:frame-code-location (nth-frame index)))) + +(defimplementation eval-in-frame (form index) + (di:eval-in-frame (nth-frame index) form)) + +(defun frame-debug-vars (frame) + "Return a vector of debug-variables in frame." + (di::debug-function-debug-variables (di:frame-debug-function frame))) + +(defun debug-var-value (var frame location) + (let ((validity (di:debug-variable-validity var location))) + (ecase validity + (:valid (di:debug-variable-value var frame)) + ((:invalid :unknown) (make-symbol (string validity)))))) + +(defimplementation frame-locals (index) + (let* ((frame (nth-frame index)) + (loc (di:frame-code-location frame)) + (vars (frame-debug-vars frame))) + (loop for v across vars collect + (list :name (di:debug-variable-symbol v) + :id (di:debug-variable-id v) + :value (debug-var-value v frame loc))))) + +(defimplementation frame-var-value (frame var) + (let* ((frame (nth-frame frame)) + (dvar (aref (frame-debug-vars frame) var))) + (debug-var-value dvar frame (di:frame-code-location frame)))) + +(defimplementation frame-catch-tags (index) + (mapcar #'car (di:frame-catches (nth-frame index)))) + +(defimplementation return-from-frame (index form) + (let ((sym (find-symbol (symbol-name '#:find-debug-tag-for-frame) + :debug-internals))) + (if sym + (let* ((frame (nth-frame index)) + (probe (funcall sym frame))) + (cond (probe (throw (car probe) (eval-in-frame form index))) + (t (format nil "Cannot return from frame: ~S" frame)))) + "return-from-frame is not implemented in this version of SCL."))) + +(defimplementation activate-stepping (frame) + (set-step-breakpoints (nth-frame frame))) + +(defimplementation sldb-break-on-return (frame) + (break-on-return (nth-frame frame))) + +;;; We set the breakpoint in the caller which might be a bit confusing. +;;; +(defun break-on-return (frame) + (let* ((caller (di:frame-down frame)) + (cl (di:frame-code-location caller))) + (flet ((hook (frame bp) + (when (frame-pointer= frame caller) + (di:delete-breakpoint bp) + (signal-breakpoint bp frame)))) + (let* ((info (ecase (di:code-location-kind cl) + ((:single-value-return :unknown-return) nil) + (:known-return (debug-function-returns + (di:frame-debug-function frame))))) + (bp (di:make-breakpoint #'hook cl :kind :code-location + :info info))) + (di:activate-breakpoint bp) + `(:ok ,(format nil "Set breakpoint in ~A" caller)))))) + +(defun frame-pointer= (frame1 frame2) + "Return true if the frame pointers of FRAME1 and FRAME2 are the same." + (sys:sap= (di::frame-pointer frame1) (di::frame-pointer frame2))) + +;;; The PC in escaped frames at a single-return-value point is +;;; actually vm:single-value-return-byte-offset bytes after the +;;; position given in the debug info. Here we try to recognize such +;;; cases. +;;; +(defun next-code-locations (frame code-location) + "Like `debug::next-code-locations' but be careful in escaped frames." + (let ((next (debug::next-code-locations code-location))) + (flet ((adjust-pc () + (let ((cl (di::copy-compiled-code-location code-location))) + (incf (di::compiled-code-location-pc cl) + vm:single-value-return-byte-offset) + cl))) + (cond ((and (di::compiled-frame-escaped frame) + (eq (di:code-location-kind code-location) + :single-value-return) + (= (length next) 1) + (di:code-location= (car next) (adjust-pc))) + (debug::next-code-locations (car next))) + (t + next))))) + +(defun set-step-breakpoints (frame) + (let ((cl (di:frame-code-location frame))) + (when (di:debug-block-elsewhere-p (di:code-location-debug-block cl)) + (error "Cannot step in elsewhere code")) + (let* ((debug::*bad-code-location-types* + (remove :call-site debug::*bad-code-location-types*)) + (next (next-code-locations frame cl))) + (cond (next + (let ((steppoints '())) + (flet ((hook (bp-frame bp) + (signal-breakpoint bp bp-frame) + (mapc #'di:delete-breakpoint steppoints))) + (dolist (code-location next) + (let ((bp (di:make-breakpoint #'hook code-location + :kind :code-location))) + (di:activate-breakpoint bp) + (push bp steppoints)))))) + (t + (break-on-return frame)))))) + + +;; XXX the return values at return breakpoints should be passed to the +;; user hooks. debug-int.lisp should be changed to do this cleanly. + +;;; The sigcontext and the PC for a breakpoint invocation are not +;;; passed to user hook functions, but we need them to extract return +;;; values. So we advice di::handle-breakpoint and bind the values to +;;; special variables. +;;; +(defvar *breakpoint-sigcontext*) +(defvar *breakpoint-pc*) + +(defun sigcontext-object (sc index) + "Extract the lisp object in sigcontext SC at offset INDEX." + (kernel:make-lisp-obj (vm:ucontext-register sc index))) + +(defun known-return-point-values (sigcontext sc-offsets) + (let ((fp (system:int-sap (vm:ucontext-register sigcontext + vm::cfp-offset)))) + (system:without-gcing + (loop for sc-offset across sc-offsets + collect (di::sub-access-debug-var-slot fp sc-offset sigcontext))))) + +;;; SCL returns the first few values in registers and the rest on +;;; the stack. In the multiple value case, the number of values is +;;; stored in a dedicated register. The values of the registers can be +;;; accessed in the sigcontext for the breakpoint. There are 3 kinds +;;; of return conventions: :single-value-return, :unknown-return, and +;;; :known-return. +;;; +;;; The :single-value-return convention returns the value in a +;;; register without setting the nargs registers. +;;; +;;; The :unknown-return variant is used for multiple values. A +;;; :unknown-return point consists actually of 2 breakpoints: one for +;;; the single value case and one for the general case. The single +;;; value breakpoint comes vm:single-value-return-byte-offset after +;;; the multiple value breakpoint. +;;; +;;; The :known-return convention is used by local functions. +;;; :known-return is currently not supported because we don't know +;;; where the values are passed. +;;; +(defun breakpoint-values (breakpoint) + "Return the list of return values for a return point." + (flet ((1st (sc) (sigcontext-object sc (car vm::register-arg-offsets)))) + (let ((sc (locally (declare (optimize (ext:inhibit-warnings 3))) + (alien:sap-alien *breakpoint-sigcontext* (* unix:ucontext)))) + (cl (di:breakpoint-what breakpoint))) + (ecase (di:code-location-kind cl) + (:single-value-return + (list (1st sc))) + (:known-return + (let ((info (di:breakpoint-info breakpoint))) + (if (vectorp info) + (known-return-point-values sc info) + (progn + ;;(break) + (list "<>" info))))) + (:unknown-return + (let ((mv-return-pc (di::compiled-code-location-pc cl))) + (if (= mv-return-pc *breakpoint-pc*) + (mv-function-end-breakpoint-values sc) + (list (1st sc))))))))) + +(defun mv-function-end-breakpoint-values (sigcontext) + (let ((sym (find-symbol + (symbol-name '#:function-end-breakpoint-values/standard) + :debug-internals))) + (cond (sym (funcall sym sigcontext)) + (t (di::get-function-end-breakpoint-values sigcontext))))) + +(defun debug-function-returns (debug-fun) + "Return the return style of DEBUG-FUN." + (let* ((cdfun (di::compiled-debug-function-compiler-debug-fun debug-fun))) + (c::compiled-debug-function-returns cdfun))) + +(define-condition breakpoint (simple-condition) + ((message :initarg :message :reader breakpoint.message) + (values :initarg :values :reader breakpoint.values)) + (:report (lambda (c stream) (princ (breakpoint.message c) stream)))) + +#+nil +(defimplementation condition-extras ((c breakpoint)) + ;; simply pop up the source buffer + `((:short-frame-source 0))) + +(defun signal-breakpoint (breakpoint frame) + "Signal a breakpoint condition for BREAKPOINT in FRAME. +Try to create a informative message." + (flet ((brk (values fstring &rest args) + (let ((msg (apply #'format nil fstring args)) + (debug:*stack-top-hint* frame)) + (break 'breakpoint :message msg :values values)))) + (with-struct (di::breakpoint- kind what) breakpoint + (case kind + (:code-location + (case (di:code-location-kind what) + ((:single-value-return :known-return :unknown-return) + (let ((values (breakpoint-values breakpoint))) + (brk values "Return value: ~{~S ~}" values))) + (t + #+(or) + (when (eq (di:code-location-kind what) :call-site) + (call-site-function breakpoint frame)) + (brk nil "Breakpoint: ~S ~S" + (di:code-location-kind what) + (di::compiled-code-location-pc what))))) + (:function-start + (brk nil "Function start breakpoint")) + (t (brk nil "Breakpoint: ~A in ~A" breakpoint frame)))))) + +#+nil +(defimplementation sldb-break-at-start (fname) + (let ((debug-fun (di:function-debug-function (coerce fname 'function)))) + (cond ((not debug-fun) + `(:error ,(format nil "~S has no debug-function" fname))) + (t + (flet ((hook (frame bp &optional args cookie) + (declare (ignore args cookie)) + (signal-breakpoint bp frame))) + (let ((bp (di:make-breakpoint #'hook debug-fun + :kind :function-start))) + (di:activate-breakpoint bp) + `(:ok ,(format nil "Set breakpoint in ~S" fname)))))))) + +(defun frame-cfp (frame) + "Return the Control-Stack-Frame-Pointer for FRAME." + (etypecase frame + (di::compiled-frame (di::frame-pointer frame)) + ((or di::interpreted-frame null) -1))) + +(defun frame-ip (frame) + "Return the (absolute) instruction pointer and the relative pc of FRAME." + (if (not frame) + -1 + (let ((debug-fun (di::frame-debug-function frame))) + (etypecase debug-fun + (di::compiled-debug-function + (let* ((code-loc (di:frame-code-location frame)) + (component (di::compiled-debug-function-component debug-fun)) + (pc (di::compiled-code-location-pc code-loc)) + (ip (sys:without-gcing + (sys:sap-int + (sys:sap+ (kernel:code-instructions component) pc))))) + (values ip pc))) + ((or di::bogus-debug-function di::interpreted-debug-function) + -1))))) + +(defun frame-registers (frame) + "Return the lisp registers CSP, CFP, IP, OCFP, LRA for FRAME-NUMBER." + (let* ((cfp (frame-cfp frame)) + (csp (frame-cfp (di::frame-up frame))) + (ip (frame-ip frame)) + (ocfp (frame-cfp (di::frame-down frame))) + (lra (frame-ip (di::frame-down frame)))) + (values csp cfp ip ocfp lra))) + +(defun print-frame-registers (frame-number) + (let ((frame (di::frame-real-frame (nth-frame frame-number)))) + (flet ((fixnum (p) (etypecase p + (integer p) + (sys:system-area-pointer (sys:sap-int p))))) + (apply #'format t "~ +CSP = ~X +CFP = ~X +IP = ~X +OCFP = ~X +LRA = ~X~%" (mapcar #'fixnum + (multiple-value-list (frame-registers frame))))))) + + +(defimplementation disassemble-frame (frame-number) + "Return a string with the disassembly of frames code." + (print-frame-registers frame-number) + (terpri) + (let* ((frame (di::frame-real-frame (nth-frame frame-number))) + (debug-fun (di::frame-debug-function frame))) + (etypecase debug-fun + (di::compiled-debug-function + (let* ((component (di::compiled-debug-function-component debug-fun)) + (fun (di:debug-function-function debug-fun))) + (if fun + (disassemble fun) + (disassem:disassemble-code-component component)))) + (di::bogus-debug-function + (format t "~%[Disassembling bogus frames not implemented]"))))) + + +;;;; Inspecting + +(defconstant +lowtag-symbols+ + '(vm:even-fixnum-type + vm:instance-pointer-type + vm:other-immediate-0-type + vm:list-pointer-type + vm:odd-fixnum-type + vm:function-pointer-type + vm:other-immediate-1-type + vm:other-pointer-type) + "Names of the constants that specify type tags. +The `symbol-value' of each element is a type tag.") + +(defconstant +header-type-symbols+ + (labels ((suffixp (suffix string) + (and (>= (length string) (length suffix)) + (string= string suffix :start1 (- (length string) + (length suffix))))) + (header-type-symbol-p (x) + (and (suffixp (symbol-name '#:-type) (symbol-name x)) + (not (member x +lowtag-symbols+)) + (boundp x) + (typep (symbol-value x) 'fixnum)))) + (remove-if-not #'header-type-symbol-p + (append (apropos-list (symbol-name '#:-type) :vm) + (apropos-list (symbol-name '#:-type) :bignum)))) + "A list of names of the type codes in boxed objects.") + +(defimplementation describe-primitive-type (object) + (with-output-to-string (*standard-output*) + (let* ((lowtag (kernel:get-lowtag object)) + (lowtag-symbol (find lowtag +lowtag-symbols+ :key #'symbol-value))) + (format t "lowtag: ~A" lowtag-symbol) + (when (member lowtag (list vm:other-pointer-type + vm:function-pointer-type + vm:other-immediate-0-type + vm:other-immediate-1-type + )) + (let* ((type (kernel:get-type object)) + (type-symbol (find type +header-type-symbols+ + :key #'symbol-value))) + (format t ", type: ~A" type-symbol)))))) + +(defmethod emacs-inspect ((o t)) + (cond ((di::indirect-value-cell-p o) + `("Value: " (:value ,(c:value-cell-ref o)))) + ((alien::alien-value-p o) + (inspect-alien-value o)) + (t + (scl-inspect o)))) + +(defun scl-inspect (o) + (destructuring-bind (text labeledp . parts) + (inspect::describe-parts o) + (list* (format nil "~A~%" text) + (if labeledp + (loop for (label . value) in parts + append (label-value-line label value)) + (loop for value in parts for i from 0 + append (label-value-line i value)))))) + +(defmethod emacs-inspect ((o function)) + (let ((header (kernel:get-type o))) + (cond ((= header vm:function-header-type) + (list* (format nil "~A is a function.~%" o) + (append (label-value-line* + ("Self" (kernel:%function-self o)) + ("Next" (kernel:%function-next o)) + ("Name" (kernel:%function-name o)) + ("Arglist" (kernel:%function-arglist o)) + ("Type" (kernel:%function-type o)) + ("Code" (kernel:function-code-header o))) + (list + (with-output-to-string (s) + (disassem:disassemble-function o :stream s)))))) + ((= header vm:closure-header-type) + (list* (format nil "~A is a closure.~%" o) + (append + (label-value-line "Function" (kernel:%closure-function o)) + `("Environment:" (:newline)) + (loop for i from 0 below (- (kernel:get-closure-length o) + (1- vm:closure-info-offset)) + append (label-value-line + i (kernel:%closure-index-ref o i)))))) + ((eval::interpreted-function-p o) + (scl-inspect o)) + (t + (call-next-method))))) + + +(defmethod emacs-inspect ((o kernel:code-component)) + (append + (label-value-line* + ("code-size" (kernel:%code-code-size o)) + ("entry-points" (kernel:%code-entry-points o)) + ("debug-info" (kernel:%code-debug-info o)) + ("trace-table-offset" (kernel:code-header-ref + o vm:code-trace-table-offset-slot))) + `("Constants:" (:newline)) + (loop for i from vm:code-constants-offset + below (kernel:get-header-data o) + append (label-value-line i (kernel:code-header-ref o i))) + `("Code:" (:newline) + , (with-output-to-string (s) + (cond ((kernel:%code-debug-info o) + (disassem:disassemble-code-component o :stream s)) + (t + (disassem:disassemble-memory + (disassem::align + (+ (logandc2 (kernel:get-lisp-obj-address o) + vm:lowtag-mask) + (* vm:code-constants-offset vm:word-bytes)) + (ash 1 vm:lowtag-bits)) + (ash (kernel:%code-code-size o) vm:word-shift) + :stream s))))))) + +(defmethod emacs-inspect ((o kernel:fdefn)) + (label-value-line* + ("name" (kernel:fdefn-name o)) + ("function" (kernel:fdefn-function o)) + ("raw-addr" (sys:sap-ref-32 + (sys:int-sap (kernel:get-lisp-obj-address o)) + (* vm:fdefn-raw-addr-slot vm:word-bytes))))) + +(defmethod emacs-inspect ((o array)) + (cond ((kernel:array-header-p o) + (list* (format nil "~A is an array.~%" o) + (label-value-line* + (:header (describe-primitive-type o)) + (:rank (array-rank o)) + (:fill-pointer (kernel:%array-fill-pointer o)) + (:fill-pointer-p (kernel:%array-fill-pointer-p o)) + (:elements (kernel:%array-available-elements o)) + (:data (kernel:%array-data-vector o)) + (:displacement (kernel:%array-displacement o)) + (:displaced-p (kernel:%array-displaced-p o)) + (:dimensions (array-dimensions o))))) + (t + (list* (format nil "~A is an simple-array.~%" o) + (label-value-line* + (:header (describe-primitive-type o)) + (:length (length o))))))) + +(defmethod emacs-inspect ((o simple-vector)) + (list* (format nil "~A is a vector.~%" o) + (append + (label-value-line* + (:header (describe-primitive-type o)) + (:length (c::vector-length o))) + (unless (eq (array-element-type o) 'nil) + (loop for i below (length o) + append (label-value-line i (aref o i))))))) + +(defun inspect-alien-record (alien) + (with-struct (alien::alien-value- sap type) alien + (with-struct (alien::alien-record-type- kind name fields) type + (append + (label-value-line* + (:sap sap) + (:kind kind) + (:name name)) + (loop for field in fields + append (let ((slot (alien::alien-record-field-name field))) + (label-value-line slot (alien:slot alien slot)))))))) + +(defun inspect-alien-pointer (alien) + (with-struct (alien::alien-value- sap type) alien + (label-value-line* + (:sap sap) + (:type type) + (:to (alien::deref alien))))) + +(defun inspect-alien-value (alien) + (typecase (alien::alien-value-type alien) + (alien::alien-record-type (inspect-alien-record alien)) + (alien::alien-pointer-type (inspect-alien-pointer alien)) + (t (scl-inspect alien)))) + +;;;; Profiling +(defimplementation profile (fname) + (eval `(profile:profile ,fname))) + +(defimplementation unprofile (fname) + (eval `(profile:unprofile ,fname))) + +(defimplementation unprofile-all () + (eval `(profile:unprofile)) + "All functions unprofiled.") + +(defimplementation profile-report () + (eval `(profile:report-time))) + +(defimplementation profile-reset () + (eval `(profile:reset-time)) + "Reset profiling counters.") + +(defimplementation profiled-functions () + profile:*timed-functions*) + +(defimplementation profile-package (package callers methods) + (profile:profile-all :package package + :callers-p callers + #+nil :methods #+nil methods)) + + +;;;; Multiprocessing + +(defimplementation spawn (fn &key name) + (thread:thread-create fn :name (or name "Anonymous"))) + +(defvar *thread-id-counter* 0) +(defvar *thread-id-counter-lock* (thread:make-lock "Thread ID counter")) + +(defimplementation thread-id (thread) + (thread:with-lock-held (*thread-id-counter-lock*) + (or (getf (thread:thread-plist thread) 'id) + (setf (getf (thread:thread-plist thread) 'id) + (incf *thread-id-counter*))))) + +(defimplementation find-thread (id) + (block find-thread + (thread:map-over-threads + #'(lambda (thread) + (when (eql (getf (thread:thread-plist thread) 'id) id) + (return-from find-thread thread)))))) + +(defimplementation thread-name (thread) + (princ-to-string (thread:thread-name thread))) + +(defimplementation thread-status (thread) + (let ((dynamic-values (thread::thread-dynamic-values thread))) + (if (zerop dynamic-values) "Exited" "Running"))) + +(defimplementation make-lock (&key name) + (thread:make-lock name)) + +(defimplementation call-with-lock-held (lock function) + (declare (type function function)) + (thread:with-lock-held (lock) (funcall function))) + +(defimplementation current-thread () + thread:*thread*) + +(defimplementation all-threads () + (let ((all-threads nil)) + (thread:map-over-threads #'(lambda (thread) (push thread all-threads))) + all-threads)) + +(defimplementation interrupt-thread (thread fn) + (thread:thread-interrupt thread #'(lambda () + (sys:with-interrupts + (funcall fn))))) + +(defimplementation kill-thread (thread) + (thread:destroy-thread thread)) + +(defimplementation thread-alive-p (thread) + (not (zerop (thread::thread-dynamic-values thread)))) + +(defvar *mailbox-lock* (thread:make-lock "Mailbox lock" :interruptible nil)) + +(defstruct (mailbox) + (lock (thread:make-lock "Thread mailbox" :type :error-check + :interruptible nil) + :type thread:error-check-lock) + (queue '() :type list)) + +(defun mailbox (thread) + "Return 'thread's mailbox." + (sys:without-interrupts + (thread:with-lock-held (*mailbox-lock*) + (or (getf (thread:thread-plist thread) 'mailbox) + (setf (getf (thread:thread-plist thread) 'mailbox) + (make-mailbox)))))) + +(defimplementation send (thread message) + (let* ((mbox (mailbox thread)) + (lock (mailbox-lock mbox))) + (sys:without-interrupts + (thread:with-lock-held (lock "Mailbox Send") + (setf (mailbox-queue mbox) (nconc (mailbox-queue mbox) + (list message))))) + (mp:process-wakeup thread))) + +#+nil +(defimplementation receive () + (receive-if (constantly t))) + +(defimplementation receive-if (test &optional timeout) + (let ((mbox (mailbox thread:*thread*))) + (assert (or (not timeout) (eq timeout t))) + (loop + (check-slime-interrupts) + (sys:without-interrupts + (mp:with-lock-held ((mailbox-lock mbox)) + (let* ((q (mailbox-queue mbox)) + (tail (member-if test q))) + (when tail + (setf (mailbox-queue mbox) + (nconc (ldiff q tail) (cdr tail))) + (return (car tail)))))) + (when (eq timeout t) (return (values nil t))) + (mp:process-wait-with-timeout + "Mailbox read wait" 0.5 (lambda () (some test (mailbox-queue mbox))))))) + + + +(defimplementation emacs-connected ()) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;Trace implementations +;; In SCL, we have: +;; (trace ) +;; (trace (method ? (+))) +;; (trace :methods t ') ;;to trace all methods of the gf +;; can be a normal name or a (setf name) + +(defun tracedp (spec) + (member spec (eval '(trace)) :test #'equal)) + +(defun toggle-trace-aux (spec &rest options) + (cond ((tracedp spec) + (eval `(untrace ,spec)) + (format nil "~S is now untraced." spec)) + (t + (eval `(trace ,spec ,@options)) + (format nil "~S is now traced." spec)))) + +(defimplementation toggle-trace (spec) + (ecase (car spec) + ((setf) + (toggle-trace-aux spec)) + ((:defgeneric) + (let ((name (second spec))) + (toggle-trace-aux name :methods name))) + ((:defmethod) + nil) + ((:call) + (destructuring-bind (caller callee) (cdr spec) + (toggle-trace-aux (process-fspec callee) + :wherein (list (process-fspec caller))))))) + +(defun process-fspec (fspec) + (cond ((consp fspec) + (ecase (first fspec) + ((:defun :defgeneric) (second fspec)) + ((:defmethod) + `(method ,(second fspec) ,@(third fspec) ,(fourth fspec))) + ;; this isn't actually supported + ((:labels) `(labels ,(process-fspec (second fspec)) ,(third fspec))) + ((:flet) `(flet ,(process-fspec (second fspec)) ,(third fspec))))) + (t + fspec))) + +;;; Weak datastructures + +;;; Not implemented in SCL. +(defimplementation make-weak-key-hash-table (&rest args) + (apply #'make-hash-table :weak-p t args)) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/source-file-cache.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/source-file-cache.lisp new file mode 100644 index 0000000..e639ea1 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/source-file-cache.lisp @@ -0,0 +1,136 @@ +;;;; Source-file cache +;;; +;;; To robustly find source locations in CMUCL and SBCL it's useful to +;;; have the exact source code that the loaded code was compiled from. +;;; In this source we can accurately find the right location, and from +;;; that location we can extract a "snippet" of code to show what the +;;; definition looks like. Emacs can use this snippet in a best-match +;;; search to locate the right definition, which works well even if +;;; the buffer has been modified. +;;; +;;; The idea is that if a definition previously started with +;;; `(define-foo bar' then it probably still does. +;;; +;;; Whenever we see that the file on disk has the same +;;; `file-write-date' as a location we're looking for we cache the +;;; whole file inside Lisp. That way we will still have the matching +;;; version even if the file is later modified on disk. If the file is +;;; later recompiled and reloaded then we replace our cache entry. +;;; +;;; This code has been placed in the Public Domain. All warranties +;;; are disclaimed. + +(defpackage swank/source-file-cache + (:use cl) + (:import-from swank/backend + defimplementation buffer-first-change + guess-external-format + find-external-format) + (:export + get-source-code + source-cache-get ;FIXME: isn't it odd that both are exported? + + *source-snippet-size* + read-snippet + read-snippet-from-string + )) + +(in-package swank/source-file-cache) + +(defvar *cache-sourcecode* t + "When true complete source files are cached. +The cache is used to keep known good copies of the source text which +correspond to the loaded code. Finding definitions is much more +reliable when the exact source is available, so we cache it in case it +gets edited on disk later.") + +(defvar *source-file-cache* (make-hash-table :test 'equal) + "Cache of source file contents. +Maps from truename to source-cache-entry structure.") + +(defstruct (source-cache-entry + (:conc-name source-cache-entry.) + (:constructor make-source-cache-entry (text date))) + text date) + +(defimplementation buffer-first-change (filename) + "Load a file into the cache when the user modifies its buffer. +This is a win if the user then saves the file and tries to M-. into it." + (unless (source-cached-p filename) + (ignore-errors + (source-cache-get filename (file-write-date filename)))) + nil) + +(defun get-source-code (filename code-date) + "Return the source code for FILENAME as written on DATE in a string. +If the exact version cannot be found then return the current one from disk." + (or (source-cache-get filename code-date) + (read-file filename))) + +(defun source-cache-get (filename date) + "Return the source code for FILENAME as written on DATE in a string. +Return NIL if the right version cannot be found." + (when *cache-sourcecode* + (let ((entry (gethash filename *source-file-cache*))) + (cond ((and entry (equal date (source-cache-entry.date entry))) + ;; Cache hit. + (source-cache-entry.text entry)) + ((or (null entry) + (not (equal date (source-cache-entry.date entry)))) + ;; Cache miss. + (if (equal (file-write-date filename) date) + ;; File on disk has the correct version. + (let ((source (read-file filename))) + (setf (gethash filename *source-file-cache*) + (make-source-cache-entry source date)) + source) + nil)))))) + +(defun source-cached-p (filename) + "Is any version of FILENAME in the source cache?" + (if (gethash filename *source-file-cache*) t)) + +(defun read-file (filename) + "Return the entire contents of FILENAME as a string." + (with-open-file (s filename :direction :input + :external-format (or (guess-external-format filename) + (find-external-format "latin-1") + :default)) + (let* ((string (make-string (file-length s))) + (length (read-sequence string s))) + (subseq string 0 length)))) + +;;;; Snippets + +(defvar *source-snippet-size* 256 + "Maximum number of characters in a snippet of source code. +Snippets at the beginning of definitions are used to tell Emacs what +the definitions looks like, so that it can accurately find them by +text search.") + +(defun read-snippet (stream &optional position) + "Read a string of upto *SOURCE-SNIPPET-SIZE* characters from STREAM. +If POSITION is given, set the STREAM's file position first." + (when position + (file-position stream position)) + #+sbcl (skip-comments-and-whitespace stream) + (read-upto-n-chars stream *source-snippet-size*)) + +(defun read-snippet-from-string (string &optional position) + (with-input-from-string (s string) + (read-snippet s position))) + +(defun skip-comments-and-whitespace (stream) + (case (peek-char nil stream nil nil) + ((#\Space #\Tab #\Newline #\Linefeed #\Page) + (read-char stream) + (skip-comments-and-whitespace stream)) + (#\; + (read-line stream) + (skip-comments-and-whitespace stream)))) + +(defun read-upto-n-chars (stream n) + "Return a string of upto N chars from STREAM." + (let* ((string (make-string n)) + (chars (read-sequence string stream))) + (subseq string 0 chars))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/source-path-parser.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/source-path-parser.lisp new file mode 100644 index 0000000..bb9c35c --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/swank/source-path-parser.lisp @@ -0,0 +1,239 @@ +;;;; Source-paths + +;;; CMUCL/SBCL use a data structure called "source-path" to locate +;;; subforms. The compiler assigns a source-path to each form in a +;;; compilation unit. Compiler notes usually contain the source-path +;;; of the error location. +;;; +;;; Compiled code objects don't contain source paths, only the +;;; "toplevel-form-number" and the (sub-) "form-number". To get from +;;; the form-number to the source-path we need the entire toplevel-form +;;; (i.e. we have to read the source code). CMUCL has already some +;;; utilities to do this translation, but we use some extended +;;; versions, because we need more exact position info. Apparently +;;; Hemlock is happy with the position of the toplevel-form; we also +;;; need the position of subforms. +;;; +;;; We use a special readtable to get the positions of the subforms. +;;; The readtable stores the start and end position for each subform in +;;; hashtable for later retrieval. +;;; +;;; This code has been placed in the Public Domain. All warranties +;;; are disclaimed. + +;;; Taken from swank-cmucl.lisp, by Helmut Eller + +(defpackage swank/source-path-parser + (:use cl) + (:export + read-source-form + source-path-string-position + source-path-file-position + source-path-source-position + + sexp-in-bounds-p + sexp-ref) + (:shadow ignore-errors)) + +(in-package swank/source-path-parser) + +;; Some test to ensure the required conformance +(let ((rt (copy-readtable nil))) + (assert (or (not (get-macro-character #\space rt)) + (nth-value 1 (get-macro-character #\space rt)))) + (assert (not (get-macro-character #\\ rt)))) + +(eval-when (:compile-toplevel) + (defmacro ignore-errors (&rest forms) + ;;`(progn . ,forms) ; for debugging + `(cl:ignore-errors . ,forms))) + +(defun make-sharpdot-reader (orig-sharpdot-reader) + (lambda (s c n) + ;; We want things like M-. to work regardless of any #.-fu in + ;; the source file that is to be visited. (For instance, when a + ;; file contains #. forms referencing constants that do not + ;; currently exist in the image.) + (ignore-errors (funcall orig-sharpdot-reader s c n)))) + +(defun make-source-recorder (fn source-map) + "Return a macro character function that does the same as FN, but +additionally stores the result together with the stream positions +before and after of calling FN in the hashtable SOURCE-MAP." + (lambda (stream char) + (let ((start (1- (file-position stream))) + (values (multiple-value-list (funcall fn stream char))) + (end (file-position stream))) + #+(or) + (format t "[~D \"~{~A~^, ~}\" ~D ~D ~S]~%" + start values end (char-code char) char) + (when values + (destructuring-bind (&optional existing-start &rest existing-end) + (car (gethash (car values) source-map)) + ;; Some macros may return what a sub-call to another macro + ;; produced, e.g. "#+(and) (a)" may end up saving (a) twice, + ;; once from #\# and once from #\(. If the saved form + ;; is a subform, don't save it again. + (unless (and existing-start existing-end + (<= start existing-start end) + (<= start existing-end end)) + (push (cons start end) (gethash (car values) source-map))))) + (values-list values)))) + +(defun make-source-recording-readtable (readtable source-map) + (declare (type readtable readtable) (type hash-table source-map)) + "Return a source position recording copy of READTABLE. +The source locations are stored in SOURCE-MAP." + (flet ((install-special-sharpdot-reader (rt) + (let ((fun (ignore-errors + (get-dispatch-macro-character #\# #\. rt)))) + (when fun + (let ((wrapper (make-sharpdot-reader fun))) + (set-dispatch-macro-character #\# #\. wrapper rt))))) + (install-wrappers (rt) + (dotimes (code 128) + (let ((char (code-char code))) + (multiple-value-bind (fun nt) (get-macro-character char rt) + (when fun + (let ((wrapper (make-source-recorder fun source-map))) + (set-macro-character char wrapper nt rt)))))))) + (let ((rt (copy-readtable readtable))) + (install-special-sharpdot-reader rt) + (install-wrappers rt) + rt))) + +;; FIXME: try to do this with *READ-SUPPRESS* = t to avoid interning. +;; Should be possible as we only need the right "list structure" and +;; not the right atoms. +(defun read-and-record-source-map (stream) + "Read the next object from STREAM. +Return the object together with a hashtable that maps +subexpressions of the object to stream positions." + (let* ((source-map (make-hash-table :test #'eq)) + (*readtable* (make-source-recording-readtable *readtable* source-map)) + (*read-suppress* nil) + (start (file-position stream)) + (form (ignore-errors (read stream))) + (end (file-position stream))) + ;; ensure that at least FORM is in the source-map + (unless (gethash form source-map) + (push (cons start end) (gethash form source-map))) + (values form source-map))) + +(defun starts-with-p (string prefix) + (declare (type string string prefix)) + (not (mismatch string prefix + :end1 (min (length string) (length prefix)) + :test #'char-equal))) + +(defun extract-package (line) + (declare (type string line)) + (let ((name (cadr (read-from-string line)))) + (find-package name))) + +#+(or) +(progn + (assert (extract-package "(in-package cl)")) + (assert (extract-package "(cl:in-package cl)")) + (assert (extract-package "(in-package \"CL\")")) + (assert (extract-package "(in-package #:cl)"))) + +;; FIXME: do something cleaner than this. +(defun readtable-for-package (package) + ;; KLUDGE: due to the load order we can't reference the swank + ;; package. + (funcall (read-from-string "swank::guess-buffer-readtable") + (string-upcase (package-name package)))) + +;; Search STREAM for a "(in-package ...)" form. Use that to derive +;; the values for *PACKAGE* and *READTABLE*. +;; +;; IDEA: move GUESS-READER-STATE to swank.lisp so that all backends +;; use the same heuristic and to avoid the need to access +;; swank::guess-buffer-readtable from here. +(defun guess-reader-state (stream) + (let* ((point (file-position stream)) + (pkg *package*)) + (file-position stream 0) + (loop for line = (read-line stream nil nil) do + (when (not line) (return)) + (when (or (starts-with-p line "(in-package ") + (starts-with-p line "(cl:in-package ")) + (let ((p (extract-package line))) + (when p (setf pkg p))) + (return))) + (file-position stream point) + (values (readtable-for-package pkg) pkg))) + +(defun skip-whitespace (stream) + (peek-char t stream nil nil)) + +;; Skip over N toplevel forms. +(defun skip-toplevel-forms (n stream) + (let ((*read-suppress* t)) + (dotimes (i n) + (read stream)) + (skip-whitespace stream))) + +(defun read-source-form (n stream) + "Read the Nth toplevel form number with source location recording. +Return the form and the source-map." + (multiple-value-bind (*readtable* *package*) (guess-reader-state stream) + (skip-toplevel-forms n stream) + (read-and-record-source-map stream))) + +(defun source-path-stream-position (path stream) + "Search the source-path PATH in STREAM and return its position." + (check-source-path path) + (destructuring-bind (tlf-number . path) path + (multiple-value-bind (form source-map) (read-source-form tlf-number stream) + (source-path-source-position (cons 0 path) form source-map)))) + +(defun check-source-path (path) + (unless (and (consp path) + (every #'integerp path)) + (error "The source-path ~S is not valid." path))) + +(defun source-path-string-position (path string) + (with-input-from-string (s string) + (source-path-stream-position path s))) + +(defun source-path-file-position (path filename) + ;; We go this long way round, and don't directly operate on the file + ;; stream because FILE-POSITION (used above) is not totally savy even + ;; on file character streams; on SBCL, FILE-POSITION returns the binary + ;; offset, and not the character offset---screwing up on Unicode. + (let ((toplevel-number (first path)) + (buffer)) + (with-open-file (file filename) + (skip-toplevel-forms (1+ toplevel-number) file) + (let ((endpos (file-position file))) + (setq buffer (make-array (list endpos) :element-type 'character + :initial-element #\Space)) + (assert (file-position file 0)) + (read-sequence buffer file :end endpos))) + (source-path-string-position path buffer))) + +(defgeneric sexp-in-bounds-p (sexp i) + (:method ((list list) i) + (< i (loop for e on list + count t))) + (:method ((sexp t) i) nil)) + +(defgeneric sexp-ref (sexp i) + (:method ((s list) i) (elt s i))) + +(defun source-path-source-position (path form source-map) + "Return the start position of PATH from FORM and SOURCE-MAP. All +subforms along the path are considered and the start and end position +of the deepest (i.e. smallest) possible form is returned." + ;; compute all subforms along path + (let ((forms (loop for i in path + for f = form then (if (sexp-in-bounds-p f i) + (sexp-ref f i)) + collect f))) + ;; select the first subform present in source-map + (loop for form in (nreverse forms) + for ((start . end) . rest) = (gethash form source-map) + when (and start end (not rest)) + return (return (values start end))))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/xref.lisp b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/xref.lisp new file mode 100644 index 0000000..e09a150 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/slime-v2.24/xref.lisp @@ -0,0 +1,2906 @@ +;;; -*- Mode: LISP; Package: XREF; Syntax: Common-lisp; -*- +;;; Mon Jan 21 16:21:20 1991 by Mark Kantrowitz +;;; xref.lisp + +;;; **************************************************************** +;;; List Callers: A Static Analysis Cross Referencing Tool for Lisp +;;; **************************************************************** +;;; +;;; The List Callers system is a portable Common Lisp cross referencing +;;; utility. It grovels over a set of files and compiles a database of the +;;; locations of all references for each symbol used in the files. +;;; List Callers is similar to the Symbolics Who-Calls and the +;;; Xerox Masterscope facilities. +;;; +;;; When you change a function or variable definition, it can be useful +;;; to know its callers, in order to update each of them to the new +;;; definition. Similarly, having a graphic display of the structure +;;; (e.g., call graph) of a program can help make undocumented code more +;;; understandable. This static code analyzer facilitates both capabilities. +;;; The database compiled by xref is suitable for viewing by a graphical +;;; browser. (Note: the reference graph is not necessarily a DAG. Since many +;;; graphical browsers assume a DAG, this will lead to infinite loops. +;;; Some code which is useful in working around this problem is included, +;;; as well as a sample text-indenting outliner and an interface to Bates' +;;; PSGraph Postscript Graphing facility.) +;;; +;;; Written by Mark Kantrowitz, July 1990. +;;; +;;; Address: School of Computer Science +;;; Carnegie Mellon University +;;; Pittsburgh, PA 15213 +;;; +;;; Copyright (c) 1990. All rights reserved. +;;; +;;; See general license below. +;;; + +;;; **************************************************************** +;;; General License Agreement and Lack of Warranty ***************** +;;; **************************************************************** +;;; +;;; This software is distributed in the hope that it will be useful (both +;;; in and of itself and as an example of lisp programming), but WITHOUT +;;; ANY WARRANTY. The author(s) do not accept responsibility to anyone for +;;; the consequences of using it or for whether it serves any particular +;;; purpose or works at all. No warranty is made about the software or its +;;; performance. +;;; +;;; Use and copying of this software and the preparation of derivative +;;; works based on this software are permitted, so long as the following +;;; conditions are met: +;;; o The copyright notice and this entire notice are included intact +;;; and prominently carried on all copies and supporting documentation. +;;; o No fees or compensation are charged for use, copies, or +;;; access to this software. You may charge a nominal +;;; distribution fee for the physical act of transferring a +;;; copy, but you may not charge for the program itself. +;;; o If you modify this software, you must cause the modified +;;; file(s) to carry prominent notices (a Change Log) +;;; describing the changes, who made the changes, and the date +;;; of those changes. +;;; o Any work distributed or published that in whole or in part +;;; contains or is a derivative of this software or any part +;;; thereof is subject to the terms of this agreement. The +;;; aggregation of another unrelated program with this software +;;; or its derivative on a volume of storage or distribution +;;; medium does not bring the other program under the scope +;;; of these terms. +;;; o Permission is granted to manufacturers and distributors of +;;; lisp compilers and interpreters to include this software +;;; with their distribution. +;;; +;;; This software is made available AS IS, and is distributed without +;;; warranty of any kind, either expressed or implied. +;;; +;;; In no event will the author(s) or their institutions be liable to you +;;; for damages, including lost profits, lost monies, or other special, +;;; incidental or consequential damages arising out of or in connection +;;; with the use or inability to use (including but not limited to loss of +;;; data or data being rendered inaccurate or losses sustained by third +;;; parties or a failure of the program to operate as documented) the +;;; program, even if you have been advised of the possibility of such +;;; damanges, or for any claim by any other party, whether in an action of +;;; contract, negligence, or other tortious action. +;;; +;;; The current version of this software and a variety of related utilities +;;; may be obtained by anonymous ftp from ftp.cs.cmu.edu in the directory +;;; user/ai/lang/lisp/code/tools/xref/ +;;; +;;; Please send bug reports, comments, questions and suggestions to +;;; mkant@cs.cmu.edu. We would also appreciate receiving any changes +;;; or improvements you may make. +;;; +;;; If you wish to be added to the Lisp-Utilities@cs.cmu.edu mailing list, +;;; send email to Lisp-Utilities-Request@cs.cmu.edu with your name, email +;;; address, and affiliation. This mailing list is primarily for +;;; notification about major updates, bug fixes, and additions to the lisp +;;; utilities collection. The mailing list is intended to have low traffic. +;;; + +;;; ******************************** +;;; Change Log ********************* +;;; ******************************** +;;; +;;; 27-FEB-91 mk Added insert arg to psgraph-xref to allow the postscript +;;; graphs to be inserted in Scribe documents. +;;; 21-FEB-91 mk Added warning if not compiled. +;;; 07-FEB-91 mk Fixed bug in record-callers with regard to forms at +;;; toplevel. +;;; 21-JAN-91 mk Added file xref-test.lisp to test xref. +;;; 16-JAN-91 mk Added definition WHO-CALLS to parallel the Symbolics syntax. +;;; 16-JAN-91 mk Added macroexpansion capability to record-callers. Also +;;; added parameter *handle-macro-forms*, defaulting to T. +;;; 16-JAN-91 mk Modified print-caller-tree and related functions +;;; to allow the user to specify root nodes. If the user +;;; doesn't specify them, it will default to all root +;;; nodes, as before. +;;; 16-JAN-91 mk Added parameter *default-graphing-mode* to specify +;;; the direction of the graphing. Either :call-graph, +;;; where the children of a node are those functions called +;;; by the node, or :caller-graph where the children of a +;;; node are the callers of the node. :call-graph is the +;;; default. +;;; 16-JAN-91 mk Added parameter *indent-amount* to control the indentation +;;; in print-indented-tree. +;;; 16-JUL-90 mk Functions with argument lists of () were being ignored +;;; because of a (when form) wrapped around the body of +;;; record-callers. Then intent of (when form) was as an extra +;;; safeguard against infinite looping. This wasn't really +;;; necessary, so it has been removed. +;;; 16-JUL-90 mk PSGraph-XREF now has keyword arguments, instead of +;;; optionals. +;;; 16-JUL-90 mk Added PRINT-CLASS-HIERARCHY to use psgraph to graph the +;;; CLOS class hierarchy. This really doesn't belong here, +;;; and should be moved to psgraph.lisp as an example of how +;;; to use psgraph. +;;; 16-JUL-90 mk Fixed several caller patterns. The pattern for member +;;; had an error which caused many references to be missed. +;;; 16-JUL-90 mk Added ability to save/load processed databases. +;;; 5-JUL-91 mk Fixed warning of needing compilation to occur only when the +;;; source is loaded. +;;; 20-SEP-93 mk Added fix from Peter Norvig to allow Xref to xref itself. +;;; The arg to macro-function must be a symbol. +;;; 7-APR-12 heller Break lines at 80 columns. + +;;; ******************************** +;;; To Do ************************** +;;; ******************************** +;;; +;;; Verify that: +;;; o null forms don't cause it to infinite loop. +;;; o nil matches against null argument lists. +;;; o declarations and doc are being ignored. +;;; +;;; Would be nice if in addition to showing callers of a function, it +;;; displayed the context of the calls to the function (e.g., the +;;; immediately surrounding form). This entails storing entries of +;;; the form (symbol context*) in the database and augmenting +;;; record-callers to keep the context around. The only drawbacks is +;;; that it would cons a fair bit. If we do this, we should store +;;; additional information as well in the database, such as the caller +;;; pattern type (e.g., variable vs. function). +;;; +;;; Write a translator from BNF (at least as much of BNF as is used +;;; in CLtL2), to the format used here. +;;; +;;; Should automatically add new patterns for new functions and macros +;;; based on their arglists. Probably requires much more than this +;;; simple code walker, so there isn't much we can do. +;;; +;;; Defmacro is a problem, because it often hides internal function +;;; calls within backquote and quote, which we normally ignore. If +;;; we redefine QUOTE's pattern so that it treats the arg like a FORM, +;;; we'll probably get them (though maybe the syntax will be mangled), +;;; but most likely a lot of spurious things as well. +;;; +;;; Define an operation for Defsystem which will run XREF-FILE on the +;;; files of the system. Or yet simpler, when XREF sees a LOAD form +;;; for which the argument is a string, tries to recursively call +;;; XREF-FILE on the specified file. Then one could just XREF-FILE +;;; the file which loads the system. (This should be a program +;;; parameter.) +;;; +;;; Have special keywords which the user may place in a file to have +;;; XREF-FILE ignore a region. +;;; +;;; Should we distinguish flet and labels from defun? I.e., note that +;;; flet's definitions are locally defined, instead of just lumping +;;; them in with regular definitions. +;;; +;;; Add patterns for series, loop macro. +;;; +;;; Need to integrate the variable reference database with the other +;;; databases, yet maintain separation. So we can distinguish all +;;; the different types of variable and function references, without +;;; multiplying databases. +;;; +;;; Would pay to comment record-callers and record-callers* in more +;;; depth. +;;; +;;; (&OPTIONAL &REST &KEY &AUX &BODY &WHOLE &ALLOW-OTHER-KEYS &ENVIRONMENT) + +;;; ******************************** +;;; Notes ************************** +;;; ******************************** +;;; +;;; XREF has been tested (successfully) in the following lisps: +;;; CMU Common Lisp (M2.9 15-Aug-90, Compiler M1.8 15-Aug-90) +;;; Macintosh Allegro Common Lisp (1.3.2) +;;; ExCL (Franz Allegro CL 3.1.12 [DEC 3100] 3/30/90) +;;; Lucid CL (Version 2.1 6-DEC-87) +;;; +;;; XREF has been tested (unsuccessfully) in the following lisps: +;;; Ibuki Common Lisp (01/01, October 15, 1987) +;;; - if interpreted, runs into stack overflow +;;; - does not compile (tried ibcl on Suns, PMAXes and RTs) +;;; seems to be due to a limitation in the c compiler. +;;; +;;; XREF needs to be tested in the following lisps: +;;; Symbolics Common Lisp (8.0) +;;; Lucid Common Lisp (3.0, 4.0) +;;; KCL (June 3, 1987 or later) +;;; AKCL (1.86, June 30, 1987 or later) +;;; TI (Release 4.1 or later) +;;; Golden Common Lisp (3.1 IBM-PC) +;;; VAXLisp (2.0, 3.1) +;;; HP Common Lisp (same as Lucid?) +;;; Procyon Common Lisp + + +;;; **************************************************************** +;;; Documentation ************************************************** +;;; **************************************************************** +;;; +;;; XREF analyzes a user's program, determining which functions call a +;;; given function, and the location of where variables are bound/assigned +;;; and used. The user may retrieve this information for either a single +;;; symbol, or display the call graph of portions of the program +;;; (including the entire program). This allows the programmer to debug +;;; and document the program's structure. +;;; +;;; XREF is primarily intended for analyzing large programs, where it is +;;; difficult, if not impossible, for the programmer to grasp the structure +;;; of the whole program. Nothing precludes using XREF for smaller programs, +;;; where it can be useful for inspecting the relationships between pieces +;;; of the program and for documenting the program. +;;; +;;; Two aspects of the Lisp programming language greatly simplify the +;;; analysis of Lisp programs: +;;; o Lisp programs are naturally represented as data. +;;; Successive definitions from a file are easily read in +;;; as list structure. +;;; o The basic syntax of Lisp is uniform. A list program +;;; consists of a set of nested forms, where each form is +;;; a list whose car is a tag (e.g., function name) that +;;; specifies the structure of the rest of the form. +;;; Thus Lisp programs, when represented as data, can be considered to be +;;; parse trees. Given a grammar of syntax patterns for the language, XREF +;;; recursively descends the parse tree for a given definition, computing +;;; a set of relations that hold for the definition at each node in the +;;; tree. For example, one kind of relation is that the function defined +;;; by the definition calls the functions in its body. The relations are +;;; stored in a database for later examination by the user. +;;; +;;; While XREF currently only works for programs written in Lisp, it could +;;; be extended to other programming languages by writing a function to +;;; generate parse trees for definitions in that language, and a core +;;; set of patterns for the language's syntax. +;;; +;;; Since XREF normally does a static syntactic analysis of the program, +;;; it does not detect references due to the expansion of a macro definition. +;;; To do this in full generality XREF would have to have knowledge about the +;;; semantics of the program (e.g., macros which call other functions to +;;; do the expansion). This entails either modifying the compiler to +;;; record the relationships (e.g., Symbolics Who-Calls Database) or doing +;;; a walk of loaded code and macroexpanding as needed (PCL code walker). +;;; The former is not portable, while the latter requires that the code +;;; used by macros be loaded and in working order. On the other hand, then +;;; we would need no special knowledge about macros (excluding the 24 special +;;; forms of Lisp). +;;; +;;; Parameters may be set to enable macro expansion in XREF. Then XREF +;;; will expand any macros for which it does not have predefined patterns. +;;; (For example, most Lisps will implement dolist as a macro. Since XREF +;;; has a pattern defined for dolist, it will not call macroexpand-1 on +;;; a form whose car is dolist.) For this to work properly, the code must +;;; be loaded before being processed by XREF, and XREF's parameters should +;;; be set so that it processes forms in their proper packages. +;;; +;;; If macro expansion is disabled, the default rules for handling macro +;;; references may not be sufficient for some user-defined macros, because +;;; macros allow a variety of non-standard syntactic extensions to the +;;; language. In this case, the user may specify additional templates in +;;; a manner similar to that in which the core Lisp grammar was specified. +;;; + + +;;; ******************************** +;;; User Guide ********************* +;;; ******************************** +;;; ----- +;;; The following functions are called to cross reference the source files. +;;; +;;; XREF-FILES (&rest files) [FUNCTION] +;;; Grovels over the lisp code located in source file FILES, using +;;; xref-file. +;;; +;;; XREF-FILE (filename &optional clear-tables verbose) [Function] +;;; Cross references the function and variable calls in FILENAME by +;;; walking over the source code located in the file. Defaults type of +;;; filename to ".lisp". Chomps on the code using record-callers and +;;; record-callers*. If CLEAR-TABLES is T (the default), it clears the +;;; callers database before processing the file. Specify CLEAR-TABLES as +;;; nil to append to the database. If VERBOSE is T (the default), prints +;;; out the name of the file, one progress dot for each form processed, +;;; and the total number of forms. +;;; +;;; ----- +;;; The following functions display information about the uses of the +;;; specified symbol as a function, variable, or constant. +;;; +;;; LIST-CALLERS (symbol) [FUNCTION] +;;; Lists all functions which call SYMBOL as a function (function +;;; invocation). +;;; +;;; LIST-READERS (symbol) [FUNCTION] +;;; Lists all functions which refer to SYMBOL as a variable +;;; (variable reference). +;;; +;;; LIST-SETTERS (symbol) [FUNCTION] +;;; Lists all functions which bind/set SYMBOL as a variable +;;; (variable mutation). +;;; +;;; LIST-USERS (symbol) [FUNCTION] +;;; Lists all functions which use SYMBOL as a variable or function. +;;; +;;; WHO-CALLS (symbol &optional how) [FUNCTION] +;;; Lists callers of symbol. HOW may be :function, :reader, :setter, +;;; or :variable." +;;; +;;; WHAT-FILES-CALL (symbol) [FUNCTION] +;;; Lists names of files that contain uses of SYMBOL +;;; as a function, variable, or constant. +;;; +;;; SOURCE-FILE (symbol) [FUNCTION] +;;; Lists the names of files in which SYMBOL is defined/used. +;;; +;;; LIST-CALLEES (symbol) [FUNCTION] +;;; Lists names of functions and variables called by SYMBOL. +;;; +;;; ----- +;;; The following functions may be useful for viewing the database and +;;; debugging the calling patterns. +;;; +;;; *LAST-FORM* () [VARIABLE] +;;; The last form read from the file. Useful for figuring out what went +;;; wrong when xref-file drops into the debugger. +;;; +;;; *XREF-VERBOSE* t [VARIABLE] +;;; When T, xref-file(s) prints out the names of the files it looks at, +;;; progress dots, and the number of forms read. +;;; +;;; *TYPES-TO-IGNORE* (quote (:lisp :lisp2)) [VARIABLE] +;;; Default set of caller types (as specified in the patterns) to ignore +;;; in the database handling functions. :lisp is CLtL 1st edition, +;;; :lisp2 is additional patterns from CLtL 2nd edition. +;;; +;;; *HANDLE-PACKAGE-FORMS* () [VARIABLE] +;;; When non-NIL, and XREF-FILE sees a package-setting form like +;;; IN-PACKAGE, sets the current package to the specified package by +;;; evaluating the form. When done with the file, xref-file resets the +;;; package to its original value. In some of the displaying functions, +;;; when this variable is non-NIL one may specify that all symbols from a +;;; particular set of packages be ignored. This is only useful if the +;;; files use different packages with conflicting names. +;;; +;;; *HANDLE-FUNCTION-FORMS* t [VARIABLE] +;;; When T, XREF-FILE tries to be smart about forms which occur in +;;; a function position, such as lambdas and arbitrary Lisp forms. +;;; If so, it recursively calls record-callers with pattern 'FORM. +;;; If the form is a lambda, makes the caller a caller of +;;; :unnamed-lambda. +;;; +;;; *HANDLE-MACRO-FORMS* t [VARIABLE] +;;; When T, if the file was loaded before being processed by XREF, and +;;; the car of a form is a macro, it notes that the parent calls the +;;; macro, and then calls macroexpand-1 on the form. +;;; +;;; *DEFAULT-GRAPHING-MODE* :call-graph [VARIABLE] +;;; Specifies whether we graph up or down. If :call-graph, the children +;;; of a node are the functions it calls. If :caller-graph, the +;;; children of a node are the functions that call it. +;;; +;;; *INDENT-AMOUNT* 3 [VARIABLE] +;;; Number of spaces to indent successive levels in PRINT-INDENTED-TREE. +;;; +;;; DISPLAY-DATABASE (&optional database types-to-ignore) [FUNCTION] +;;; Prints out the name of each symbol and all its callers. Specify +;;; database :callers (the default) to get function call references, +;;; :file to the get files in which the symbol is called, :readers to get +;;; variable references, and :setters to get variable binding and +;;; assignments. Ignores functions of types listed in types-to-ignore. +;;; +;;; PRINT-CALLER-TREES (&key (mode *default-graphing-mode*) [FUNCTION] +;;; (types-to-ignore *types-to-ignore*) +;;; compact root-nodes) +;;; Prints the calling trees (which may actually be a full graph and not +;;; necessarily a DAG) as indented text trees using +;;; PRINT-INDENTED-TREE. MODE is :call-graph for trees where the children +;;; of a node are the functions called by the node, or :caller-graph for +;;; trees where the children of a node are the functions the node calls. +;;; TYPES-TO-IGNORE is a list of funcall types (as specified in the +;;; patterns) to ignore in printing out the database. For example, +;;; '(:lisp) would ignore all calls to common lisp functions. COMPACT is +;;; a flag to tell the program to try to compact the trees a bit by not +;;; printing trees if they have already been seen. ROOT-NODES is a list +;;; of root nodes of trees to display. If ROOT-NODES is nil, tries to +;;; find all root nodes in the database. +;;; +;;; MAKE-CALLER-TREE (&optional (mode *default-graphing-mode*) [FUNCTION] +;;; (types-to-ignore *types-to-ignore*) +;;; compact) +;;; Outputs list structure of a tree which roughly represents the +;;; possibly cyclical structure of the caller database. +;;; If mode is :call-graph, the children of a node are the functions +;;; it calls. If mode is :caller-graph, the children of a node are the +;;; functions that call it. +;;; If compact is T, tries to eliminate the already-seen nodes, so +;;; that the graph for a node is printed at most once. Otherwise it will +;;; duplicate the node's tree (except for cycles). This is usefull +;;; because the call tree is actually a directed graph, so we can either +;;; duplicate references or display only the first one. +;;; +;;; DETERMINE-FILE-DEPENDENCIES (&optional database) [FUNCTION] +;;; Makes a hash table of file dependencies for the references listed in +;;; DATABASE. This function may be useful for automatically resolving +;;; file references for automatic creation of a system definition +;;; (defsystem). +;;; +;;; PRINT-FILE-DEPENDENCIES (&optional database) [FUNCTION] +;;; Prints a list of file dependencies for the references listed in +;;; DATABASE. This function may be useful for automatically computing +;;; file loading constraints for a system definition tool. +;;; +;;; WRITE-CALLERS-DATABASE-TO-FILE (filename) [FUNCTION] +;;; Saves the contents of the current callers database to a file. This +;;; file can be loaded to restore the previous contents of the +;;; database. (For large systems it can take a long time to crunch +;;; through the code, so this can save some time.) +;;; +;;; ----- +;;; The following macros define new function and macro call patterns. +;;; They may be used to extend the static analysis tool to handle +;;; new def forms, extensions to Common Lisp, and program defs. +;;; +;;; DEFINE-PATTERN-SUBSTITUTION (name pattern) [MACRO] +;;; Defines NAME to be equivalent to the specified pattern. Useful for +;;; making patterns more readable. For example, the LAMBDA-LIST is +;;; defined as a pattern substitution, making the definition of the +;;; DEFUN caller-pattern simpler. +;;; +;;; DEFINE-CALLER-PATTERN (name pattern &optional caller-type) [MACRO] +;;; Defines NAME as a function/macro call with argument structure +;;; described by PATTERN. CALLER-TYPE, if specified, assigns a type to +;;; the pattern, which may be used to exclude references to NAME while +;;; viewing the database. For example, all the Common Lisp definitions +;;; have a caller-type of :lisp or :lisp2, so that you can exclude +;;; references to common lisp functions from the calling tree. +;;; +;;; DEFINE-VARIABLE-PATTERN (name &optional caller-type) [MACRO] +;;; Defines NAME as a variable reference of type CALLER-TYPE. This is +;;; mainly used to establish the caller-type of the variable. +;;; +;;; DEFINE-CALLER-PATTERN-SYNONYMS (source destinations) [MACRO] +;;; For defining function caller pattern syntax synonyms. For each name +;;; in DESTINATIONS, defines its pattern as a copy of the definition +;;; of SOURCE. Allows a large number of identical patterns to be defined +;;; simultaneously. Must occur after the SOURCE has been defined. +;;; +;;; ----- +;;; This system includes pattern definitions for the latest +;;; common lisp specification, as published in Guy Steele, +;;; Common Lisp: The Language, 2nd Edition. +;;; +;;; Patterns may be either structures to match, or a predicate +;;; like symbolp/numberp/stringp. The pattern specification language +;;; is similar to the notation used in CLtL2, but in a more lisp-like +;;; form: +;;; (:eq name) The form element must be eq to the symbol NAME. +;;; (:test test) TEST must be true when applied to the form element. +;;; (:typep type) The form element must be of type TYPE. +;;; (:or pat1 pat2 ...) Tries each of the patterns in left-to-right order, +;;; until one succeeds. +;;; Equivalent to { pat1 | pat2 | ... } +;;; (:rest pattern) The remaining form elements are grouped into a +;;; list which is matched against PATTERN. +;;; (:optional pat1 ...) The patterns may optionally match against the +;;; form element. +;;; Equivalent to [ pat1 ... ]. +;;; (:star pat1 ...) The patterns may match against the patterns +;;; any number of times, including 0. +;;; Equivalent to { pat1 ... }*. +;;; (:plus pat1 ...) The patterns may match against the patterns +;;; any number of times, but at least once. +;;; Equivalent to { pat1 ... }+. +;;; &optional, &key, Similar in behavior to the corresponding +;;; &rest lambda-list keywords. +;;; FORM A random lisp form. If a cons, assumes the +;;; car is a function or macro and tries to +;;; match the args against that symbol's pattern. +;;; If a symbol, assumes it's a variable reference. +;;; :ignore Ignores the corresponding form element. +;;; NAME The corresponding form element should be +;;; the name of a new definition (e.g., the +;;; first arg in a defun pattern is NAME. +;;; FUNCTION, MACRO The corresponding form element should be +;;; a function reference not handled by FORM. +;;; Used in the definition of apply and funcall. +;;; VAR The corresponding form element should be +;;; a variable definition or mutation. Used +;;; in the definition of let, let*, etc. +;;; VARIABLE The corresponding form element should be +;;; a variable reference. +;;; +;;; In all other pattern symbols, it looks up the symbols pattern substitution +;;; and recursively matches against the pattern. Automatically destructures +;;; list structure that does not include consing dots. +;;; +;;; Among the pattern substitution names defined are: +;;; STRING, SYMBOL, NUMBER Appropriate :test patterns. +;;; LAMBDA-LIST Matches against a lambda list. +;;; BODY Matches against a function body definition. +;;; FN Matches against #'function, 'function, +;;; and lambdas. This is used in the definition +;;; of apply, funcall, and the mapping patterns. +;;; and others... +;;; +;;; Here's some sample pattern definitions: +;;; (define-caller-pattern defun +;;; (name lambda-list +;;; (:star (:or documentation-string declaration)) +;;; (:star form)) +;;; :lisp) +;;; (define-caller-pattern funcall (fn (:star form)) :lisp) +;;; +;;; In general, the system is intelligent enough to handle any sort of +;;; simple funcall. One only need specify the syntax for functions and +;;; macros which use optional arguments, keyword arguments, or some +;;; argument positions are special, such as in apply and funcall, or +;;; to indicate that the function is of the specified caller type. +;;; +;;; +;;; NOTES: +;;; +;;; XRef assumes syntactically correct lisp code. +;;; +;;; This is by no means perfect. For example, let and let* are treated +;;; identically, instead of differentiating between serial and parallel +;;; binding. But it's still a useful tool. It can be helpful in +;;; maintaining code, debugging problems with patch files, determining +;;; whether functions are multiply defined, and help you remember where +;;; a function is defined or called. +;;; +;;; XREF runs best when compiled. + +;;; ******************************** +;;; References ********************* +;;; ******************************** +;;; +;;; Xerox Interlisp Masterscope Program: +;;; Larry M Masinter, Global program analysis in an interactive environment +;;; PhD Thesis, Stanford University, 1980. +;;; +;;; Symbolics Who-Calls Database: +;;; User's Guide to Symbolics Computers, Volume 1, Cambridge, MA, July 1986 +;;; Genera 7.0, pp 183-185. +;;; + +;;; ******************************** +;;; Example ************************ +;;; ******************************** +;;; +;;; Here is an example of running XREF on a short program. +;;; [In Scribe documentation, give a simple short program and resulting +;;; XREF output, including postscript call graphs.] +#| + (xref:xref-file "/afs/cs/user/mkant/Lisp/Graph-Dag/graph-dag.lisp") +Cross-referencing file /afs/cs/user/mkant/Lisp/Graph-Dag/graph-dag.lisp. +................................................ +48 forms processed. + (xref:display-database :readers) + +*DISPLAY-CUTOFF-DEPTH* is referenced by CALCULATE-LEVEL-POSITION +CALCULATE-LEVEL-POSITION-BEFORE CALCULATE-POSITION-IN-LEVEL. +*OFFSET-FROM-EDGE-OF-PANE* is referenced by CALCULATE-LEVEL-POSITION +CALCULATE-LEVEL-POSITION-BEFORE. +*WITHIN-LEVEL-SPACING* is referenced by BREADTH CALCULATE-POSITION-INFO. +*DIRECTION* is referenced by CREATE-POSITION-INFO. +*LINK-OFFSET* is referenced by OFFSET-OF-LINK-FROM-ATTACHMENT-POINT. +*ROOT-IS-SEQUENCE* is referenced by GRAPH. +*LEVEL-SPACING* is referenced by CALCULATE-LEVEL-POSITION +CALCULATE-LEVEL-POSITION-BEFORE. +*ORIENTATION* is referenced by BREADTH CALCULATE-LEVEL-POSITION +CALCULATE-LEVEL-POSITION-BEFORE CALCULATE-POSITION-IN-LEVEL. +*DEFAULT-GRAPH-POSITION* is referenced by CREATE-POSITION-INFO. +*GRAPHING-CUTOFF-DEPTH* is referenced by CREATE-NODE-STRUCTURE. +*LIST-OF-NODES* is referenced by CALCULATE-LEVEL-POSITION +CALCULATE-LEVEL-POSITION-BEFORE CREATE-NODE FIND-NODE. +*GRAPH-TYPE* is referenced by CREATE-NODE-STRUCTURE. + (xref:print-caller-trees :root-nodes '(display-graph)) + +Rooted calling trees: + DISPLAY-GRAPH + CREATE-POSITION-INFO + CALCULATE-POSITION-INFO + CALCULATE-POSITION + NODE-POSITION-ALREADY-SET-FLAG + NODE-LEVEL-ALREADY-SET-FLAG + CALCULATE-POSITION-IN-LEVEL + NODE-CHILDREN + NODE-LEVEL + CALCULATE-POSITION + NEW-CALCULATE-BREADTH + NODE-CHILDREN + BREADTH + OPPOSITE-DIMENSION + NODE-HEIGHT + NODE-WIDTH + NEW-CALCULATE-BREADTH + NODE-PARENTS + OPPOSITE-DIMENSION + NODE-HEIGHT + NODE-WIDTH + OPPOSITE-POSITION + NODE-Y + NODE-X + NODE-LEVEL + CALCULATE-LEVEL-POSITION + NODE-LEVEL + NODE-POSITION + NODE-X + NODE-Y + DIMENSION + NODE-WIDTH + NODE-HEIGHT + CALCULATE-LEVEL-POSITION-BEFORE + NODE-LEVEL + NODE-POSITION + NODE-X + NODE-Y + NODE-WIDTH + NODE-HEIGHT + DIMENSION + NODE-WIDTH + NODE-HEIGHT +|# + +;;; **************************************************************** +;;; List Callers *************************************************** +;;; **************************************************************** + +(defpackage :pxref + (:use :common-lisp) + (:export #:list-callers + #:list-users + #:list-readers + #:list-setters + #:what-files-call + #:who-calls + #:list-callees + #:source-file + #:clear-tables + #:define-pattern-substitution + #:define-caller-pattern + #:define-variable-pattern + #:define-caller-pattern-synonyms + #:clear-patterns + #:*last-form* + #:*xref-verbose* + #:*handle-package-forms* + #:*handle-function-forms* + #:*handle-macro-forms* + #:*types-to-ignore* + #:*last-caller-tree* + #:*default-graphing-mode* + #:*indent-amount* + #:xref-file + #:xref-files + #:write-callers-database-to-file + #:display-database + #:print-caller-trees + #:make-caller-tree + #:print-indented-tree + #:determine-file-dependencies + #:print-file-dependencies + #:psgraph-xref + )) + +(in-package "PXREF") + +;;; Warn user if they're loading the source instead of compiling it first. +;(eval-when (compile load eval) +; (defvar compiled-p nil)) +;(eval-when (compile load) +; (setq compiled-p t)) +;(eval-when (load eval) +; (unless compiled-p +; (warn "This file should be compiled before loading for best results."))) +(eval-when (eval) + (warn "This file should be compiled before loading for best results.")) + + +;;; ******************************** +;;; Primitives ********************* +;;; ******************************** +(defun lookup (symbol environment) + (dolist (frame environment) + (when (member symbol frame) + (return symbol)))) + +(defun car-eq (list item) + (and (consp list) + (eq (car list) item))) + +;;; ******************************** +;;; Callers Database *************** +;;; ******************************** +(defvar *file-callers-database* (make-hash-table :test #'equal) + "Contains name and list of file callers (files which call) for that name.") +(defvar *callers-database* (make-hash-table :test #'equal) + "Contains name and list of callers (function invocation) for that name.") +(defvar *readers-database* (make-hash-table :test #'equal) + "Contains name and list of readers (variable use) for that name.") +(defvar *setters-database* (make-hash-table :test #'equal) + "Contains name and list of setters (variable mutation) for that name.") +(defvar *callees-database* (make-hash-table :test #'equal) + "Contains name and list of functions and variables it calls.") +(defun callers-list (name &optional (database :callers)) + (case database + (:file (gethash name *file-callers-database*)) + (:callees (gethash name *callees-database*)) + (:callers (gethash name *callers-database*)) + (:readers (gethash name *readers-database*)) + (:setters (gethash name *setters-database*)))) +(defsetf callers-list (name &optional (database :callers)) (caller) + `(setf (gethash ,name (case ,database + (:file *file-callers-database*) + (:callees *callees-database*) + (:callers *callers-database*) + (:readers *readers-database*) + (:setters *setters-database*))) + ,caller)) + +(defun list-callers (symbol) + "Lists all functions which call SYMBOL as a function (function invocation)." + (callers-list symbol :callers)) +(defun list-readers (symbol) + "Lists all functions which refer to SYMBOL as a variable + (variable reference)." + (callers-list symbol :readers)) +(defun list-setters (symbol) + "Lists all functions which bind/set SYMBOL as a variable + (variable mutation)." + (callers-list symbol :setters)) +(defun list-users (symbol) + "Lists all functions which use SYMBOL as a variable or function." + (values (list-callers symbol) + (list-readers symbol) + (list-setters symbol))) +(defun who-calls (symbol &optional how) + "Lists callers of symbol. HOW may be :function, :reader, :setter, + or :variable." + ;; would be nice to have :macro and distinguish variable + ;; binding from assignment. (i.e., variable binding, assignment, and use) + (case how + (:function (list-callers symbol)) + (:reader (list-readers symbol)) + (:setter (list-setters symbol)) + (:variable (append (list-readers symbol) + (list-setters symbol))) + (otherwise (append (list-callers symbol) + (list-readers symbol) + (list-setters symbol))))) +(defun what-files-call (symbol) + "Lists names of files that contain uses of SYMBOL + as a function, variable, or constant." + (callers-list symbol :file)) +(defun list-callees (symbol) + "Lists names of functions and variables called by SYMBOL." + (callers-list symbol :callees)) + +(defvar *source-file* (make-hash-table :test #'equal) + "Contains function name and source file for that name.") +(defun source-file (symbol) + "Lists the names of files in which SYMBOL is defined/used." + (gethash symbol *source-file*)) +(defsetf source-file (name) (value) + `(setf (gethash ,name *source-file*) ,value)) + +(defun clear-tables () + (clrhash *file-callers-database*) + (clrhash *callers-database*) + (clrhash *callees-database*) + (clrhash *readers-database*) + (clrhash *setters-database*) + (clrhash *source-file*)) + + +;;; ******************************** +;;; Pattern Database *************** +;;; ******************************** +;;; Pattern Types +(defvar *pattern-caller-type* (make-hash-table :test #'equal)) +(defun pattern-caller-type (name) + (gethash name *pattern-caller-type*)) +(defsetf pattern-caller-type (name) (value) + `(setf (gethash ,name *pattern-caller-type*) ,value)) + +;;; Pattern Substitutions +(defvar *pattern-substitution-table* (make-hash-table :test #'equal) + "Stores general patterns for function destructuring.") +(defun lookup-pattern-substitution (name) + (gethash name *pattern-substitution-table*)) +(defmacro define-pattern-substitution (name pattern) + "Defines NAME to be equivalent to the specified pattern. Useful for + making patterns more readable. For example, the LAMBDA-LIST is + defined as a pattern substitution, making the definition of the + DEFUN caller-pattern simpler." + `(setf (gethash ',name *pattern-substitution-table*) + ',pattern)) + +;;; Function/Macro caller patterns: +;;; The car of the form is skipped, so we don't need to specify +;;; (:eq function-name) like we would for a substitution. +;;; +;;; Patterns must be defined in the XREF package because the pattern +;;; language is tested by comparing symbols (using #'equal) and not +;;; their printreps. This is fine for the lisp grammer, because the XREF +;;; package depends on the LISP package, so a symbol like 'xref::cons is +;;; translated automatically into 'lisp::cons. However, since +;;; (equal 'foo::bar 'baz::bar) returns nil unless both 'foo::bar and +;;; 'baz::bar are inherited from the same package (e.g., LISP), +;;; if package handling is turned on the user must specify package +;;; names in the caller pattern definitions for functions that occur +;;; in packages other than LISP, otherwise the symbols will not match. +;;; +;;; Perhaps we should enforce the definition of caller patterns in the +;;; XREF package by wrapping the body of define-caller-pattern in +;;; the XREF package: +;;; (defmacro define-caller-pattern (name value &optional caller-type) +;;; (let ((old-package *package*)) +;;; (setf *package* (find-package "XREF")) +;;; (prog1 +;;; `(progn +;;; (when ',caller-type +;;; (setf (pattern-caller-type ',name) ',caller-type)) +;;; (when ',value +;;; (setf (gethash ',name *caller-pattern-table*) +;;; ',value))) +;;; (setf *package* old-package)))) +;;; Either that, or for the purpose of pattern testing we should compare +;;; printreps. [The latter makes the primitive patterns like VAR +;;; reserved words.] +(defvar *caller-pattern-table* (make-hash-table :test #'equal) + "Stores patterns for function destructuring.") +(defun lookup-caller-pattern (name) + (gethash name *caller-pattern-table*)) +(defmacro define-caller-pattern (name pattern &optional caller-type) + "Defines NAME as a function/macro call with argument structure + described by PATTERN. CALLER-TYPE, if specified, assigns a type to + the pattern, which may be used to exclude references to NAME while + viewing the database. For example, all the Common Lisp definitions + have a caller-type of :lisp or :lisp2, so that you can exclude + references to common lisp functions from the calling tree." + `(progn + (when ',caller-type + (setf (pattern-caller-type ',name) ',caller-type)) + (when ',pattern + (setf (gethash ',name *caller-pattern-table*) + ',pattern)))) + +;;; For defining variables +(defmacro define-variable-pattern (name &optional caller-type) + "Defines NAME as a variable reference of type CALLER-TYPE. This is + mainly used to establish the caller-type of the variable." + `(progn + (when ',caller-type + (setf (pattern-caller-type ',name) ',caller-type)))) + +;;; For defining synonyms. Means much less space taken up by the patterns. +(defmacro define-caller-pattern-synonyms (source destinations) + "For defining function caller pattern syntax synonyms. For each name + in DESTINATIONS, defines its pattern as a copy of the definition of SOURCE. + Allows a large number of identical patterns to be defined simultaneously. + Must occur after the SOURCE has been defined." + `(let ((source-type (pattern-caller-type ',source)) + (source-pattern (gethash ',source *caller-pattern-table*))) + (when source-type + (dolist (dest ',destinations) + (setf (pattern-caller-type dest) source-type))) + (when source-pattern + (dolist (dest ',destinations) + (setf (gethash dest *caller-pattern-table*) + source-pattern))))) + +(defun clear-patterns () + (clrhash *pattern-substitution-table*) + (clrhash *caller-pattern-table*) + (clrhash *pattern-caller-type*)) + +;;; ******************************** +;;; Cross Reference Files ********** +;;; ******************************** +(defvar *last-form* () + "The last form read from the file. Useful for figuring out what went wrong + when xref-file drops into the debugger.") + +(defvar *xref-verbose* t + "When T, xref-file(s) prints out the names of the files it looks at, + progress dots, and the number of forms read.") + +;;; This needs to first clear the tables? +(defun xref-files (&rest files) + "Grovels over the lisp code located in source file FILES, using xref-file." + ;; If the arg is a list, use it. + (when (listp (car files)) (setq files (car files))) + (dolist (file files) + (xref-file file nil)) + (values)) + +(defvar *handle-package-forms* nil ;'(lisp::in-package) + "When non-NIL, and XREF-FILE sees a package-setting form like IN-PACKAGE, + sets the current package to the specified package by evaluating the + form. When done with the file, xref-file resets the package to its + original value. In some of the displaying functions, when this variable + is non-NIL one may specify that all symbols from a particular set of + packages be ignored. This is only useful if the files use different + packages with conflicting names.") + +(defvar *normal-readtable* (copy-readtable nil) + "Normal, unadulterated CL readtable.") + +(defun xref-file (filename &optional (clear-tables t) (verbose *xref-verbose*)) + "Cross references the function and variable calls in FILENAME by + walking over the source code located in the file. Defaults type of + filename to \".lisp\". Chomps on the code using record-callers and + record-callers*. If CLEAR-TABLES is T (the default), it clears the callers + database before processing the file. Specify CLEAR-TABLES as nil to + append to the database. If VERBOSE is T (the default), prints out the + name of the file, one progress dot for each form processed, and the + total number of forms." + ;; Default type to "lisp" + (when (and (null (pathname-type filename)) + (not (probe-file filename))) + (cond ((stringp filename) + (setf filename (concatenate 'string filename ".lisp"))) + ((pathnamep filename) + (setf filename (merge-pathnames filename + (make-pathname :type "lisp")))))) + (when clear-tables (clear-tables)) + (let ((count 0) + (old-package *package*) + (*readtable* *normal-readtable*)) + (when verbose + (format t "~&Cross-referencing file ~A.~&" filename)) + (with-open-file (stream filename :direction :input) + (do ((form (read stream nil :eof) (read stream nil :eof))) + ((eq form :eof)) + (incf count) + (when verbose + (format *standard-output* ".") + (force-output *standard-output*)) + (setq *last-form* form) + (record-callers filename form) + ;; Package Magic. + (when (and *handle-package-forms* + (consp form) + (member (car form) *handle-package-forms*)) + (eval form)))) + (when verbose + (format t "~&~D forms processed." count)) + (setq *package* old-package) + (values))) + +(defvar *handle-function-forms* t + "When T, XREF-FILE tries to be smart about forms which occur in + a function position, such as lambdas and arbitrary Lisp forms. + If so, it recursively calls record-callers with pattern 'FORM. + If the form is a lambda, makes the caller a caller of :unnamed-lambda.") + +(defvar *handle-macro-forms* t + "When T, if the file was loaded before being processed by XREF, and the + car of a form is a macro, it notes that the parent calls the macro, + and then calls macroexpand-1 on the form.") + +(defvar *callees-database-includes-variables* nil) + +(defun record-callers (filename form + &optional pattern parent (environment nil) + funcall) + "RECORD-CALLERS is the main routine used to walk down the code. It matches + the PATTERN against the FORM, possibly adding statements to the database. + PARENT is the name defined by the current outermost definition; it is + the caller of the forms in the body (e.g., FORM). ENVIRONMENT is used + to keep track of the scoping of variables. FUNCALL deals with the type + of variable assignment and hence how the environment should be modified. + RECORD-CALLERS handles atomic patterns and simple list-structure patterns. + For complex list-structure pattern destructuring, it calls RECORD-CALLERS*." +; (when form) + (unless pattern (setq pattern 'FORM)) + (cond ((symbolp pattern) + (case pattern + (:IGNORE + ;; Ignores the rest of the form. + (values t parent environment)) + (NAME + ;; This is the name of a new definition. + (push filename (source-file form)) + (values t form environment)) + ((FUNCTION MACRO) + ;; This is the name of a call. + (cond ((and *handle-function-forms* (consp form)) + ;; If we're a cons and special handling is on, + (when (eq (car form) 'lambda) + (pushnew filename (callers-list :unnamed-lambda :file)) + (when parent + (pushnew parent (callers-list :unnamed-lambda + :callers)) + (pushnew :unnamed-lambda (callers-list parent + :callees)))) + (record-callers filename form 'form parent environment)) + (t + ;; If we're just a regular function name call. + (pushnew filename (callers-list form :file)) + (when parent + (pushnew parent (callers-list form :callers)) + (pushnew form (callers-list parent :callees))) + (values t parent environment)))) + (VAR + ;; This is the name of a new variable definition. + ;; Includes arglist parameters. + (when (and (symbolp form) (not (keywordp form)) + (not (member form lambda-list-keywords))) + (pushnew form (car environment)) + (pushnew filename (callers-list form :file)) + (when parent +; (pushnew form (callers-list parent :callees)) + (pushnew parent (callers-list form :setters))) + (values t parent environment))) + (VARIABLE + ;; VAR reference + (pushnew filename (callers-list form :file)) + (when (and parent (not (lookup form environment))) + (pushnew parent (callers-list form :readers)) + (when *callees-database-includes-variables* + (pushnew form (callers-list parent :callees)))) + (values t parent environment)) + (FORM + ;; A random form (var or funcall). + (cond ((consp form) + ;; Get new pattern from TAG. + (let ((new-pattern (lookup-caller-pattern (car form)))) + (pushnew filename (callers-list (car form) :file)) + (when parent + (pushnew parent (callers-list (car form) :callers)) + (pushnew (car form) (callers-list parent :callees))) + (cond ((and new-pattern (cdr form)) + ;; Special Pattern and there's stuff left + ;; to be processed. Note that we check if + ;; a pattern is defined for the form before + ;; we check to see if we can macroexpand it. + (record-callers filename (cdr form) new-pattern + parent environment :funcall)) + ((and *handle-macro-forms* + (symbolp (car form)) ; pnorvig 9/9/93 + (macro-function (car form))) + ;; The car of the form is a macro and + ;; macro processing is turned on. Macroexpand-1 + ;; the form and try again. + (record-callers filename + (macroexpand-1 form) + 'form parent environment + :funcall)) + ((null (cdr form)) + ;; No more left to be processed. Note that + ;; this must occur after the macros clause, + ;; since macros can expand into more code. + (values t parent environment)) + (t + ;; Random Form. We assume it is a function call. + (record-callers filename (cdr form) + '((:star FORM)) + parent environment :funcall))))) + (t + (when (and (not (lookup form environment)) + (not (numberp form)) + ;; the following line should probably be + ;; commented out? + (not (keywordp form)) + (not (stringp form)) + (not (eq form t)) + (not (eq form nil))) + (pushnew filename (callers-list form :file)) + ;; ??? :callers + (when parent + (pushnew parent (callers-list form :readers)) + (when *callees-database-includes-variables* + (pushnew form (callers-list parent :callees))))) + (values t parent environment)))) + (otherwise + ;; Pattern Substitution + (let ((new-pattern (lookup-pattern-substitution pattern))) + (if new-pattern + (record-callers filename form new-pattern + parent environment) + (when (eq pattern form) + (values t parent environment))))))) + ((consp pattern) + (case (car pattern) + (:eq (when (eq (second pattern) form) + (values t parent environment))) + (:test (when (funcall (eval (second pattern)) form) + (values t parent environment))) + (:typep (when (typep form (second pattern)) + (values t parent environment))) + (:or (dolist (subpat (rest pattern)) + (multiple-value-bind (processed parent environment) + (record-callers filename form subpat + parent environment) + (when processed + (return (values processed parent environment)))))) + (:rest ; (:star :plus :optional :rest) + (record-callers filename form (second pattern) + parent environment)) + (otherwise + (multiple-value-bind (d p env) + (record-callers* filename form pattern + parent (cons nil environment)) + (values d p (if funcall environment env)))))))) + +(defun record-callers* (filename form pattern parent environment + &optional continuation + in-optionals in-keywords) + "RECORD-CALLERS* handles complex list-structure patterns, such as + ordered lists of subpatterns, patterns involving :star, :plus, + &optional, &key, &rest, and so on. CONTINUATION is a stack of + unprocessed patterns, IN-OPTIONALS and IN-KEYWORDS are corresponding + stacks which determine whether &rest or &key has been seen yet in + the current pattern." + ;; form must be a cons or nil. +; (when form) + (if (null pattern) + (if (null continuation) + (values t parent environment) + (record-callers* filename form (car continuation) parent environment + (cdr continuation) + (cdr in-optionals) + (cdr in-keywords))) + (let ((pattern-elt (car pattern))) + (cond ((car-eq pattern-elt :optional) + (if (null form) + (values t parent environment) + (multiple-value-bind (processed par env) + (record-callers* filename form (cdr pattern-elt) + parent environment + (cons (cdr pattern) continuation) + (cons (car in-optionals) in-optionals) + (cons (car in-keywords) in-keywords)) + (if processed + (values processed par env) + (record-callers* filename form (cdr pattern) + parent environment continuation + in-optionals in-keywords))))) + ((car-eq pattern-elt :star) + (if (null form) + (values t parent environment) + (multiple-value-bind (processed par env) + (record-callers* filename form (cdr pattern-elt) + parent environment + (cons pattern continuation) + (cons (car in-optionals) in-optionals) + (cons (car in-keywords) in-keywords)) + (if processed + (values processed par env) + (record-callers* filename form (cdr pattern) + parent environment continuation + in-optionals in-keywords))))) + ((car-eq pattern-elt :plus) + (record-callers* filename form (cdr pattern-elt) + parent environment + (cons (cons (cons :star (cdr pattern-elt)) + (cdr pattern)) + continuation) + (cons (car in-optionals) in-optionals) + (cons (car in-keywords) in-keywords))) + ((car-eq pattern-elt :rest) + (record-callers filename form pattern-elt parent environment)) + ((eq pattern-elt '&optional) + (record-callers* filename form (cdr pattern) + parent environment continuation + (cons t in-optionals) + (cons (car in-keywords) in-keywords))) + ((eq pattern-elt '&rest) + (record-callers filename form (second pattern) + parent environment)) + ((eq pattern-elt '&key) + (record-callers* filename form (cdr pattern) + parent environment continuation + (cons (car in-optionals) in-optionals) + (cons t in-keywords))) + ((null form) + (when (or (car in-keywords) (car in-optionals)) + (values t parent environment))) + ((consp form) + (multiple-value-bind (processed parent environment) + (record-callers filename (if (car in-keywords) + (cadr form) + (car form)) + pattern-elt + parent environment) + (cond (processed + (record-callers* filename (if (car in-keywords) + (cddr form) + (cdr form)) + (cdr pattern) + parent environment + continuation + in-optionals in-keywords)) + ((or (car in-keywords) + (car in-optionals)) + (values t parent environment))))))))) + + +;;; ******************************** +;;; Misc Utilities ***************** +;;; ******************************** +(defvar *types-to-ignore* + '(:lisp ; CLtL 1st Edition + :lisp2 ; CLtL 2nd Edition additional patterns + ) + "Default set of caller types (as specified in the patterns) to ignore + in the database handling functions. :lisp is CLtL 1st edition, + :lisp2 is additional patterns from CLtL 2nd edition.") + +(defun display-database (&optional (database :callers) + (types-to-ignore *types-to-ignore*)) + "Prints out the name of each symbol and all its callers. Specify database + :callers (the default) to get function call references, :fill to the get + files in which the symbol is called, :readers to get variable references, + and :setters to get variable binding and assignments. Ignores functions + of types listed in types-to-ignore." + (maphash #'(lambda (name callers) + (unless (or (member (pattern-caller-type name) + types-to-ignore) + ;; When we're doing fancy package crap, + ;; allow us to ignore symbols based on their + ;; packages. + (when *handle-package-forms* + (member (symbol-package name) + types-to-ignore + :key #'find-package))) + (format t "~&~S is referenced by~{ ~S~}." + name callers))) + (ecase database + (:file *file-callers-database*) + (:callers *callers-database*) + (:readers *readers-database*) + (:setters *setters-database*)))) + +(defun write-callers-database-to-file (filename) + "Saves the contents of the current callers database to a file. This + file can be loaded to restore the previous contents of the + database. (For large systems it can take a long time to crunch + through the code, so this can save some time.)" + (with-open-file (stream filename :direction :output) + (format stream "~&(clear-tables)") + (maphash #'(lambda (x y) + (format stream "~&(setf (source-file '~S) '~S)" + x y)) + *source-file*) + (maphash #'(lambda (x y) + (format stream "~&(setf (callers-list '~S :file) '~S)" + x y)) + *file-callers-database*) + (maphash #'(lambda (x y) + (format stream "~&(setf (callers-list '~S :callers) '~S)" + x y)) + *callers-database*) + (maphash #'(lambda (x y) + (format stream "~&(setf (callers-list '~S :callees) '~S)" + x y)) + *callees-database*) + (maphash #'(lambda (x y) + (format stream "~&(setf (callers-list '~S :readers) '~S)" + x y)) + *readers-database*) + (maphash #'(lambda (x y) + (format stream "~&(setf (callers-list '~S :setters) '~S)" + x y)) + *setters-database*))) + + +;;; ******************************** +;;; Print Caller Trees ************* +;;; ******************************** +;;; The following function is useful for reversing a caller table into +;;; a callee table. Possibly later we'll extend xref to create two +;;; such database hash tables. Needs to include vars as well. +(defun invert-hash-table (table &optional (types-to-ignore *types-to-ignore*)) + "Makes a copy of the hash table in which (name value*) pairs + are inverted to (value name*) pairs." + (let ((target (make-hash-table :test #'equal))) + (maphash #'(lambda (key values) + (dolist (value values) + (unless (member (pattern-caller-type key) + types-to-ignore) + (pushnew key (gethash value target))))) + table) + target)) + +;;; Resolve file references for automatic creation of a defsystem file. +(defun determine-file-dependencies (&optional (database *callers-database*)) + "Makes a hash table of file dependencies for the references listed in + DATABASE. This function may be useful for automatically resolving + file references for automatic creation of a system definition (defsystem)." + (let ((file-ref-ht (make-hash-table :test #'equal))) + (maphash #'(lambda (key values) + (let ((key-file (source-file key))) + (when key + (dolist (value values) + (let ((value-file (source-file value))) + (when value-file + (dolist (s key-file) + (dolist (d value-file) + (pushnew d (gethash s file-ref-ht)))))))))) + database) + file-ref-ht)) + +(defun print-file-dependencies (&optional (database *callers-database*)) + "Prints a list of file dependencies for the references listed in DATABASE. + This function may be useful for automatically computing file loading + constraints for a system definition tool." + (maphash #'(lambda (key value) (format t "~&~S --> ~S" key value)) + (determine-file-dependencies database))) + +;;; The following functions demonstrate a possible way to interface +;;; xref to a graphical browser such as psgraph to mimic the capabilities +;;; of Masterscope's graphical browser. + +(defvar *last-caller-tree* nil) + +(defvar *default-graphing-mode* :call-graph + "Specifies whether we graph up or down. If :call-graph, the children + of a node are the functions it calls. If :caller-graph, the children + of a node are the functions that call it.") + +(defun gather-tree (parents &optional already-seen + (mode *default-graphing-mode*) + (types-to-ignore *types-to-ignore*) compact) + "Extends the tree, copying it into list structure, until it repeats + a reference (hits a cycle)." + (let ((*already-seen* nil) + (database (case mode + (:call-graph *callees-database*) + (:caller-graph *callers-database*)))) + (declare (special *already-seen*)) + (labels + ((amass-tree + (parents &optional already-seen) + (let (result this-item) + (dolist (parent parents) + (unless (member (pattern-caller-type parent) + types-to-ignore) + (pushnew parent *already-seen*) + (if (member parent already-seen) + (setq this-item nil) ; :ignore + (if compact + (multiple-value-setq (this-item already-seen) + (amass-tree (gethash parent database) + (cons parent already-seen))) + (setq this-item + (amass-tree (gethash parent database) + (cons parent already-seen))))) + (setq parent (format nil "~S" parent)) + (when (consp parent) (setq parent (cons :xref-list parent))) + (unless (eq this-item :ignore) + (push (if this-item + (list parent this-item) + parent) + result)))) + (values result ;(reverse result) + already-seen)))) + (values (amass-tree parents already-seen) + *already-seen*)))) + +(defun find-roots-and-cycles (&optional (mode *default-graphing-mode*) + (types-to-ignore *types-to-ignore*)) + "Returns a list of uncalled callers (roots) and called callers (potential + cycles)." + (let ((uncalled-callers nil) + (called-callers nil) + (database (ecase mode + (:call-graph *callers-database*) + (:caller-graph *callees-database*))) + (other-database (ecase mode + (:call-graph *callees-database*) + (:caller-graph *callers-database*)))) + (maphash #'(lambda (name value) + (declare (ignore value)) + (unless (member (pattern-caller-type name) + types-to-ignore) + (if (gethash name database) + (push name called-callers) + (push name uncalled-callers)))) + other-database) + (values uncalled-callers called-callers))) + +(defun make-caller-tree (&optional (mode *default-graphing-mode*) + (types-to-ignore *types-to-ignore*) compact) + "Outputs list structure of a tree which roughly represents the possibly + cyclical structure of the caller database. + If mode is :call-graph, the children of a node are the functions it calls. + If mode is :caller-graph, the children of a node are the functions that + call it. + If compact is T, tries to eliminate the already-seen nodes, so that + the graph for a node is printed at most once. Otherwise it will duplicate + the node's tree (except for cycles). This is usefull because the call tree + is actually a directed graph, so we can either duplicate references or + display only the first one." + ;; Would be nice to print out line numbers and whenever we skip a duplicated + ;; reference, print the line number of the full reference after the node. + (multiple-value-bind (uncalled-callers called-callers) + (find-roots-and-cycles mode types-to-ignore) + (multiple-value-bind (trees already-seen) + (gather-tree uncalled-callers nil mode types-to-ignore compact) + (setq *last-caller-tree* trees) + (let ((more-trees (gather-tree (set-difference called-callers + already-seen) + already-seen + mode types-to-ignore compact))) + (values trees more-trees))))) + +(defvar *indent-amount* 3 + "Number of spaces to indent successive levels in PRINT-INDENTED-TREE.") + +(defun print-indented-tree (trees &optional (indent 0)) + "Simple code to print out a list-structure tree (such as those created + by make-caller-tree) as indented text." + (when trees + (dolist (tree trees) + (cond ((and (listp tree) (eq (car tree) :xref-list)) + (format t "~&~VT~A" indent (cdr tree))) + ((listp tree) + (format t "~&~VT~A" indent (car tree)) + (print-indented-tree (cadr tree) (+ indent *indent-amount*))) + (t + (format t "~&~VT~A" indent tree)))))) + +(defun print-caller-trees (&key (mode *default-graphing-mode*) + (types-to-ignore *types-to-ignore*) + compact + root-nodes) + "Prints the calling trees (which may actually be a full graph and not + necessarily a DAG) as indented text trees using PRINT-INDENTED-TREE. + MODE is :call-graph for trees where the children of a node are the + functions called by the node, or :caller-graph for trees where the + children of a node are the functions the node calls. TYPES-TO-IGNORE + is a list of funcall types (as specified in the patterns) to ignore + in printing out the database. For example, '(:lisp) would ignore all + calls to common lisp functions. COMPACT is a flag to tell the program + to try to compact the trees a bit by not printing trees if they have + already been seen. ROOT-NODES is a list of root nodes of trees to + display. If ROOT-NODES is nil, tries to find all root nodes in the + database." + (multiple-value-bind (rooted cycles) + (if root-nodes + (values (gather-tree root-nodes nil mode types-to-ignore compact)) + (make-caller-tree mode types-to-ignore compact)) + (when rooted + (format t "~&Rooted calling trees:") + (print-indented-tree rooted 2)) + (when cycles + (when rooted + (format t "~2%")) + (format t "~&Cyclic calling trees:") + (print-indented-tree cycles 2)))) + + +;;; ******************************** +;;; Interface to PSGraph *********** +;;; ******************************** +#| +;;; Interface to Bates' PostScript Graphing Utility +(load "/afs/cs/user/mkant/Lisp/PSGraph/psgraph") + +(defparameter *postscript-output-directory* "") +(defun psgraph-xref (&key (mode *default-graphing-mode*) + (output-directory *postscript-output-directory*) + (types-to-ignore *types-to-ignore*) + (compact t) + (shrink t) + root-nodes + insert) + ;; If root-nodes is a non-nil list, uses that list as the starting + ;; position. Otherwise tries to find all roots in the database. + (multiple-value-bind (rooted cycles) + (if root-nodes + (values (gather-tree root-nodes nil mode types-to-ignore compact)) + (make-caller-tree mode types-to-ignore compact)) + (psgraph-output (append rooted cycles) output-directory shrink insert))) + +(defun psgraph-output (list-of-trees directory shrink &optional insert) + (let ((psgraph:*fontsize* 9) + (psgraph:*second-fontsize* 7) +; (psgraph:*boxkind* "fill") + (psgraph:*boxgray* "0") ; .8 + (psgraph:*edgewidth* "1") + (psgraph:*edgegray* "0")) + (labels ((stringify (thing) + (cond ((stringp thing) (string-downcase thing)) + ((symbolp thing) (string-downcase (symbol-name thing))) + ((and (listp thing) (eq (car thing) :xref-list)) + (stringify (cdr thing))) + ((listp thing) (stringify (car thing))) + (t (string thing))))) + (dolist (item list-of-trees) + (let* ((fname (stringify item)) + (filename (concatenate 'string directory + (string-trim '(#\: #\|) fname) + ".ps"))) + (format t "~&Creating PostScript file ~S." filename) + (with-open-file (*standard-output* filename + :direction :output + :if-does-not-exist :create + :if-exists :supersede) + ;; Note that the #'eq prints the DAG as a tree. If + ;; you replace it with #'equal, it will print it as + ;; a DAG, which I think is slightly ugly. + (psgraph:psgraph item + #'caller-tree-children #'caller-info shrink + insert #'eq))))))) + +(defun caller-tree-children (tree) + (when (and tree (listp tree) (not (eq (car tree) :xref-list))) + (cadr tree))) + +(defun caller-tree-node (tree) + (when tree + (cond ((and (listp tree) (eq (car tree) :xref-list)) + (cdr tree)) + ((listp tree) + (car tree)) + (t + tree)))) + +(defun caller-info (tree) + (let ((node (caller-tree-node tree))) + (list node))) +|# +#| +;;; Code to print out graphical trees of CLOS class hierarchies. +(defun print-class-hierarchy (&optional (start-class 'anything) + (file "classes.ps")) + (let ((start (find-class start-class))) + (when start + (with-open-file (*standard-output* file :direction :output) + (psgraph:psgraph start + #'clos::class-direct-subclasses + #'(lambda (x) + (list (format nil "~A" (clos::class-name x)))) + t nil #'eq))))) + +|# + + +;;; **************************************************************** +;;; Cross Referencing Patterns for Common Lisp ********************* +;;; **************************************************************** +(clear-patterns) + +;;; ******************************** +;;; Pattern Substitutions ********** +;;; ******************************** +(define-pattern-substitution integer (:test #'integerp)) +(define-pattern-substitution rational (:test #'rationalp)) +(define-pattern-substitution symbol (:test #'symbolp)) +(define-pattern-substitution string (:test #'stringp)) +(define-pattern-substitution number (:test #'numberp)) +(define-pattern-substitution lambda-list + ((:star var) + (:optional (:eq &optional) + (:star (:or var + (var (:optional form (:optional var)))))) + (:optional (:eq &rest) var) + (:optional (:eq &key) (:star (:or var + ((:or var + (keyword var)) + (:optional form (:optional var))))) + (:optional &allow-other-keys)) + (:optional (:eq &aux) + (:star (:or var + (var (:optional form))))))) +(define-pattern-substitution test form) +(define-pattern-substitution body + ((:star (:or declaration documentation-string)) + (:star form))) +(define-pattern-substitution documentation-string string) +(define-pattern-substitution initial-value form) +(define-pattern-substitution tag symbol) +(define-pattern-substitution declaration ((:eq declare)(:rest :ignore))) +(define-pattern-substitution destination form) +(define-pattern-substitution control-string string) +(define-pattern-substitution format-arguments + ((:star form))) +(define-pattern-substitution fn + (:or ((:eq quote) function) + ((:eq function) function) + function)) + +;;; ******************************** +;;; Caller Patterns **************** +;;; ******************************** + +;;; Types Related +(define-caller-pattern coerce (form :ignore) :lisp) +(define-caller-pattern type-of (form) :lisp) +(define-caller-pattern upgraded-array-element-type (:ignore) :lisp2) +(define-caller-pattern upgraded-complex-part-type (:ignore) :lisp2) + +;;; Lambdas and Definitions +(define-variable-pattern lambda-list-keywords :lisp) +(define-variable-pattern lambda-parameters-limit :lisp) +(define-caller-pattern lambda (lambda-list (:rest body)) :lisp) + +(define-caller-pattern defun + (name lambda-list + (:star (:or documentation-string declaration)) + (:star form)) + :lisp) + +;;; perhaps this should use VAR, instead of NAME +(define-caller-pattern defvar + (var (:optional initial-value (:optional documentation-string))) + :lisp) +(define-caller-pattern defparameter + (var initial-value (:optional documentation-string)) + :lisp) +(define-caller-pattern defconstant + (var initial-value (:optional documentation-string)) + :lisp) + +(define-caller-pattern eval-when + (:ignore ; the situations + (:star form)) + :lisp) + +;;; Logical Values +(define-variable-pattern nil :lisp) +(define-variable-pattern t :lisp) + +;;; Predicates +(define-caller-pattern typep (form form) :lisp) +(define-caller-pattern subtypep (form form) :lisp) + +(define-caller-pattern null (form) :lisp) +(define-caller-pattern symbolp (form) :lisp) +(define-caller-pattern atom (form) :lisp) +(define-caller-pattern consp (form) :lisp) +(define-caller-pattern listp (form) :lisp) +(define-caller-pattern numberp (form) :lisp) +(define-caller-pattern integerp (form) :lisp) +(define-caller-pattern rationalp (form) :lisp) +(define-caller-pattern floatp (form) :lisp) +(define-caller-pattern realp (form) :lisp2) +(define-caller-pattern complexp (form) :lisp) +(define-caller-pattern characterp (form) :lisp) +(define-caller-pattern stringp (form) :lisp) +(define-caller-pattern bit-vector-p (form) :lisp) +(define-caller-pattern vectorp (form) :lisp) +(define-caller-pattern simple-vector-p (form) :lisp) +(define-caller-pattern simple-string-p (form) :lisp) +(define-caller-pattern simple-bit-vector-p (form) :lisp) +(define-caller-pattern arrayp (form) :lisp) +(define-caller-pattern packagep (form) :lisp) +(define-caller-pattern functionp (form) :lisp) +(define-caller-pattern compiled-function-p (form) :lisp) +(define-caller-pattern commonp (form) :lisp) + +;;; Equality Predicates +(define-caller-pattern eq (form form) :lisp) +(define-caller-pattern eql (form form) :lisp) +(define-caller-pattern equal (form form) :lisp) +(define-caller-pattern equalp (form form) :lisp) + +;;; Logical Operators +(define-caller-pattern not (form) :lisp) +(define-caller-pattern or ((:star form)) :lisp) +(define-caller-pattern and ((:star form)) :lisp) + +;;; Reference + +;;; Quote is a problem. In Defmacro & friends, we'd like to actually +;;; look at the argument, 'cause it hides internal function calls +;;; of the defmacro. +(define-caller-pattern quote (:ignore) :lisp) + +(define-caller-pattern function ((:or fn form)) :lisp) +(define-caller-pattern symbol-value (form) :lisp) +(define-caller-pattern symbol-function (form) :lisp) +(define-caller-pattern fdefinition (form) :lisp2) +(define-caller-pattern boundp (form) :lisp) +(define-caller-pattern fboundp (form) :lisp) +(define-caller-pattern special-form-p (form) :lisp) + +;;; Assignment +(define-caller-pattern setq ((:star var form)) :lisp) +(define-caller-pattern psetq ((:star var form)) :lisp) +(define-caller-pattern set (form form) :lisp) +(define-caller-pattern makunbound (form) :lisp) +(define-caller-pattern fmakunbound (form) :lisp) + +;;; Generalized Variables +(define-caller-pattern setf ((:star form form)) :lisp) +(define-caller-pattern psetf ((:star form form)) :lisp) +(define-caller-pattern shiftf ((:plus form) form) :lisp) +(define-caller-pattern rotatef ((:star form)) :lisp) +(define-caller-pattern define-modify-macro + (name + lambda-list + fn + (:optional documentation-string)) + :lisp) +(define-caller-pattern defsetf + (:or (name name (:optional documentation-string)) + (name lambda-list (var) + (:star (:or declaration documentation-string)) + (:star form))) + :lisp) +(define-caller-pattern define-setf-method + (name lambda-list + (:star (:or declaration documentation-string)) + (:star form)) + :lisp) +(define-caller-pattern get-setf-method (form) :lisp) +(define-caller-pattern get-setf-method-multiple-value (form) :lisp) + + +;;; Function invocation +(define-caller-pattern apply (fn form (:star form)) :lisp) +(define-caller-pattern funcall (fn (:star form)) :lisp) + + +;;; Simple sequencing +(define-caller-pattern progn ((:star form)) :lisp) +(define-caller-pattern prog1 (form (:star form)) :lisp) +(define-caller-pattern prog2 (form form (:star form)) :lisp) + +;;; Variable bindings +(define-caller-pattern let + (((:star (:or var (var &optional form)))) + (:star declaration) + (:star form)) + :lisp) +(define-caller-pattern let* + (((:star (:or var (var &optional form)))) + (:star declaration) + (:star form)) + :lisp) +(define-caller-pattern compiler-let + (((:star (:or var (var form)))) + (:star form)) + :lisp) +(define-caller-pattern progv + (form form (:star form)) :lisp) +(define-caller-pattern flet + (((:star (name lambda-list + (:star (:or declaration + documentation-string)) + (:star form)))) + (:star form)) + :lisp) +(define-caller-pattern labels + (((:star (name lambda-list + (:star (:or declaration + documentation-string)) + (:star form)))) + (:star form)) + :lisp) +(define-caller-pattern macrolet + (((:star (name lambda-list + (:star (:or declaration + documentation-string)) + (:star form)))) + (:star form)) + :lisp) +(define-caller-pattern symbol-macrolet + (((:star (var form))) (:star declaration) (:star form)) + :lisp2) + +;;; Conditionals +(define-caller-pattern if (test form (:optional form)) :lisp) +(define-caller-pattern when (test (:star form)) :lisp) +(define-caller-pattern unless (test (:star form)) :lisp) +(define-caller-pattern cond ((:star (test (:star form)))) :lisp) +(define-caller-pattern case + (form + (:star ((:or symbol + ((:star symbol))) + (:star form)))) + :lisp) +(define-caller-pattern typecase (form (:star (symbol (:star form)))) + :lisp) + +;;; Blocks and Exits +(define-caller-pattern block (name (:star form)) :lisp) +(define-caller-pattern return-from (function (:optional form)) :lisp) +(define-caller-pattern return ((:optional form)) :lisp) + +;;; Iteration +(define-caller-pattern loop ((:star form)) :lisp) +(define-caller-pattern do + (((:star (:or var + (var (:optional form (:optional form)))))) ; init step + (form (:star form)) ; end-test result + (:star declaration) + (:star (:or tag form))) ; statement + :lisp) +(define-caller-pattern do* + (((:star (:or var + (var (:optional form (:optional form)))))) + (form (:star form)) + (:star declaration) + (:star (:or tag form))) + :lisp) +(define-caller-pattern dolist + ((var form (:optional form)) + (:star declaration) + (:star (:or tag form))) + :lisp) +(define-caller-pattern dotimes + ((var form (:optional form)) + (:star declaration) + (:star (:or tag form))) + :lisp) + +;;; Mapping +(define-caller-pattern mapcar (fn form (:star form)) :lisp) +(define-caller-pattern maplist (fn form (:star form)) :lisp) +(define-caller-pattern mapc (fn form (:star form)) :lisp) +(define-caller-pattern mapl (fn form (:star form)) :lisp) +(define-caller-pattern mapcan (fn form (:star form)) :lisp) +(define-caller-pattern mapcon (fn form (:star form)) :lisp) + +;;; The "Program Feature" +(define-caller-pattern tagbody ((:star (:or tag form))) :lisp) +(define-caller-pattern prog + (((:star (:or var (var (:optional form))))) + (:star declaration) + (:star (:or tag form))) + :lisp) +(define-caller-pattern prog* + (((:star (:or var (var (:optional form))))) + (:star declaration) + (:star (:or tag form))) + :lisp) +(define-caller-pattern go (tag) :lisp) + +;;; Multiple Values +(define-caller-pattern values ((:star form)) :lisp) +(define-variable-pattern multiple-values-limit :lisp) +(define-caller-pattern values-list (form) :lisp) +(define-caller-pattern multiple-value-list (form) :lisp) +(define-caller-pattern multiple-value-call (fn (:star form)) :lisp) +(define-caller-pattern multiple-value-prog1 (form (:star form)) :lisp) +(define-caller-pattern multiple-value-bind + (((:star var)) form + (:star declaration) + (:star form)) + :lisp) +(define-caller-pattern multiple-value-setq (((:star var)) form) :lisp) +(define-caller-pattern nth-value (form form) :lisp2) + +;;; Dynamic Non-Local Exits +(define-caller-pattern catch (tag (:star form)) :lisp) +(define-caller-pattern throw (tag form) :lisp) +(define-caller-pattern unwind-protect (form (:star form)) :lisp) + +;;; Macros +(define-caller-pattern macro-function (form) :lisp) +(define-caller-pattern defmacro + (name + lambda-list + (:star (:or declaration documentation-string)) + (:star form)) + :lisp) +(define-caller-pattern macroexpand (form (:optional :ignore)) :lisp) +(define-caller-pattern macroexpand-1 (form (:optional :ignore)) :lisp) +(define-variable-pattern *macroexpand-hook* :lisp) + +;;; Destructuring +(define-caller-pattern destructuring-bind + (lambda-list form + (:star declaration) + (:star form)) + :lisp2) + +;;; Compiler Macros +(define-caller-pattern define-compiler-macro + (name lambda-list + (:star (:or declaration documentation-string)) + (:star form)) + :lisp2) +(define-caller-pattern compiler-macro-function (form) :lisp2) +(define-caller-pattern compiler-macroexpand (form (:optional :ignore)) :lisp2) +(define-caller-pattern compiler-macroexpand-1 (form (:optional :ignore)) + :lisp2) + +;;; Environments +(define-caller-pattern variable-information (form &optional :ignore) + :lisp2) +(define-caller-pattern function-information (fn &optional :ignore) :lisp2) +(define-caller-pattern declaration-information (form &optional :ignore) :lisp2) +(define-caller-pattern augment-environment (form &key (:star :ignore)) :lisp2) +(define-caller-pattern define-declaration + (name + lambda-list + (:star form)) + :lisp2) +(define-caller-pattern parse-macro (name lambda-list form) :lisp2) +(define-caller-pattern enclose (form &optional :ignore) :lisp2) + + +;;; Declarations +(define-caller-pattern declare ((:rest :ignore)) :lisp) +(define-caller-pattern proclaim ((:rest :ignore)) :lisp) +(define-caller-pattern locally ((:star declaration) (:star form)) :lisp) +(define-caller-pattern declaim ((:rest :ignore)) :lisp2) +(define-caller-pattern the (form form) :lisp) + +;;; Symbols +(define-caller-pattern get (form form (:optional form)) :lisp) +(define-caller-pattern remprop (form form) :lisp) +(define-caller-pattern symbol-plist (form) :lisp) +(define-caller-pattern getf (form form (:optional form)) :lisp) +(define-caller-pattern remf (form form) :lisp) +(define-caller-pattern get-properties (form form) :lisp) + +(define-caller-pattern symbol-name (form) :lisp) +(define-caller-pattern make-symbol (form) :lisp) +(define-caller-pattern copy-symbol (form (:optional :ignore)) :lisp) +(define-caller-pattern gensym ((:optional :ignore)) :lisp) +(define-variable-pattern *gensym-counter* :lisp2) +(define-caller-pattern gentemp ((:optional :ignore :ignore)) :lisp) +(define-caller-pattern symbol-package (form) :lisp) +(define-caller-pattern keywordp (form) :lisp) + +;;; Packages +(define-variable-pattern *package* :lisp) +(define-caller-pattern make-package ((:rest :ignore)) :lisp) +(define-caller-pattern in-package ((:rest :ignore)) :lisp) +(define-caller-pattern find-package ((:rest :ignore)) :lisp) +(define-caller-pattern package-name ((:rest :ignore)) :lisp) +(define-caller-pattern package-nicknames ((:rest :ignore)) :lisp) +(define-caller-pattern rename-package ((:rest :ignore)) :lisp) +(define-caller-pattern package-use-list ((:rest :ignore)) :lisp) +(define-caller-pattern package-used-by-list ((:rest :ignore)) :lisp) +(define-caller-pattern package-shadowing-symbols ((:rest :ignore)) :lisp) +(define-caller-pattern list-all-packages () :lisp) +(define-caller-pattern delete-package ((:rest :ignore)) :lisp2) +(define-caller-pattern intern (form &optional :ignore) :lisp) +(define-caller-pattern find-symbol (form &optional :ignore) :lisp) +(define-caller-pattern unintern (form &optional :ignore) :lisp) + +(define-caller-pattern export ((:or symbol ((:star symbol))) + &optional :ignore) :lisp) +(define-caller-pattern unexport ((:or symbol ((:star symbol))) + &optional :ignore) :lisp) +(define-caller-pattern import ((:or symbol ((:star symbol))) + &optional :ignore) :lisp) +(define-caller-pattern shadowing-import ((:or symbol ((:star symbol))) + &optional :ignore) :lisp) +(define-caller-pattern shadow ((:or symbol ((:star symbol))) + &optional :ignore) :lisp) + +(define-caller-pattern use-package ((:rest :ignore)) :lisp) +(define-caller-pattern unuse-package ((:rest :ignore)) :lisp) +(define-caller-pattern defpackage (name (:rest :ignore)) :lisp2) +(define-caller-pattern find-all-symbols (form) :lisp) +(define-caller-pattern do-symbols + ((var (:optional form (:optional form))) + (:star declaration) + (:star (:or tag form))) + :lisp) +(define-caller-pattern do-external-symbols + ((var (:optional form (:optional form))) + (:star declaration) + (:star (:or tag form))) + :lisp) +(define-caller-pattern do-all-symbols + ((var (:optional form)) + (:star declaration) + (:star (:or tag form))) + :lisp) +(define-caller-pattern with-package-iterator + ((name form (:plus :ignore)) + (:star form)) + :lisp2) + +;;; Modules +(define-variable-pattern *modules* :lisp) +(define-caller-pattern provide (form) :lisp) +(define-caller-pattern require (form &optional :ignore) :lisp) + + +;;; Numbers +(define-caller-pattern zerop (form) :lisp) +(define-caller-pattern plusp (form) :lisp) +(define-caller-pattern minusp (form) :lisp) +(define-caller-pattern oddp (form) :lisp) +(define-caller-pattern evenp (form) :lisp) + +(define-caller-pattern = (form (:star form)) :lisp) +(define-caller-pattern /= (form (:star form)) :lisp) +(define-caller-pattern > (form (:star form)) :lisp) +(define-caller-pattern < (form (:star form)) :lisp) +(define-caller-pattern <= (form (:star form)) :lisp) +(define-caller-pattern >= (form (:star form)) :lisp) + +(define-caller-pattern max (form (:star form)) :lisp) +(define-caller-pattern min (form (:star form)) :lisp) + +(define-caller-pattern - (form (:star form)) :lisp) +(define-caller-pattern + (form (:star form)) :lisp) +(define-caller-pattern * (form (:star form)) :lisp) +(define-caller-pattern / (form (:star form)) :lisp) +(define-caller-pattern 1+ (form) :lisp) +(define-caller-pattern 1- (form) :lisp) + +(define-caller-pattern incf (form form) :lisp) +(define-caller-pattern decf (form form) :lisp) + +(define-caller-pattern conjugate (form) :lisp) + +(define-caller-pattern gcd ((:star form)) :lisp) +(define-caller-pattern lcm ((:star form)) :lisp) + +(define-caller-pattern exp (form) :lisp) +(define-caller-pattern expt (form form) :lisp) +(define-caller-pattern log (form (:optional form)) :lisp) +(define-caller-pattern sqrt (form) :lisp) +(define-caller-pattern isqrt (form) :lisp) + +(define-caller-pattern abs (form) :lisp) +(define-caller-pattern phase (form) :lisp) +(define-caller-pattern signum (form) :lisp) +(define-caller-pattern sin (form) :lisp) +(define-caller-pattern cos (form) :lisp) +(define-caller-pattern tan (form) :lisp) +(define-caller-pattern cis (form) :lisp) +(define-caller-pattern asin (form) :lisp) +(define-caller-pattern acos (form) :lisp) +(define-caller-pattern atan (form &optional form) :lisp) +(define-variable-pattern pi :lisp) + +(define-caller-pattern sinh (form) :lisp) +(define-caller-pattern cosh (form) :lisp) +(define-caller-pattern tanh (form) :lisp) +(define-caller-pattern asinh (form) :lisp) +(define-caller-pattern acosh (form) :lisp) +(define-caller-pattern atanh (form) :lisp) + +;;; Type Conversions and Extractions +(define-caller-pattern float (form (:optional form)) :lisp) +(define-caller-pattern rational (form) :lisp) +(define-caller-pattern rationalize (form) :lisp) +(define-caller-pattern numerator (form) :lisp) +(define-caller-pattern denominator (form) :lisp) + +(define-caller-pattern floor (form (:optional form)) :lisp) +(define-caller-pattern ceiling (form (:optional form)) :lisp) +(define-caller-pattern truncate (form (:optional form)) :lisp) +(define-caller-pattern round (form (:optional form)) :lisp) + +(define-caller-pattern mod (form form) :lisp) +(define-caller-pattern rem (form form) :lisp) + +(define-caller-pattern ffloor (form (:optional form)) :lisp) +(define-caller-pattern fceiling (form (:optional form)) :lisp) +(define-caller-pattern ftruncate (form (:optional form)) :lisp) +(define-caller-pattern fround (form (:optional form)) :lisp) + +(define-caller-pattern decode-float (form) :lisp) +(define-caller-pattern scale-float (form form) :lisp) +(define-caller-pattern float-radix (form) :lisp) +(define-caller-pattern float-sign (form (:optional form)) :lisp) +(define-caller-pattern float-digits (form) :lisp) +(define-caller-pattern float-precision (form) :lisp) +(define-caller-pattern integer-decode-float (form) :lisp) + +(define-caller-pattern complex (form (:optional form)) :lisp) +(define-caller-pattern realpart (form) :lisp) +(define-caller-pattern imagpart (form) :lisp) + +(define-caller-pattern logior ((:star form)) :lisp) +(define-caller-pattern logxor ((:star form)) :lisp) +(define-caller-pattern logand ((:star form)) :lisp) +(define-caller-pattern logeqv ((:star form)) :lisp) + +(define-caller-pattern lognand (form form) :lisp) +(define-caller-pattern lognor (form form) :lisp) +(define-caller-pattern logandc1 (form form) :lisp) +(define-caller-pattern logandc2 (form form) :lisp) +(define-caller-pattern logorc1 (form form) :lisp) +(define-caller-pattern logorc2 (form form) :lisp) + +(define-caller-pattern boole (form form form) :lisp) +(define-variable-pattern boole-clr :lisp) +(define-variable-pattern boole-set :lisp) +(define-variable-pattern boole-1 :lisp) +(define-variable-pattern boole-2 :lisp) +(define-variable-pattern boole-c1 :lisp) +(define-variable-pattern boole-c2 :lisp) +(define-variable-pattern boole-and :lisp) +(define-variable-pattern boole-ior :lisp) +(define-variable-pattern boole-xor :lisp) +(define-variable-pattern boole-eqv :lisp) +(define-variable-pattern boole-nand :lisp) +(define-variable-pattern boole-nor :lisp) +(define-variable-pattern boole-andc1 :lisp) +(define-variable-pattern boole-andc2 :lisp) +(define-variable-pattern boole-orc1 :lisp) +(define-variable-pattern boole-orc2 :lisp) + +(define-caller-pattern lognot (form) :lisp) +(define-caller-pattern logtest (form form) :lisp) +(define-caller-pattern logbitp (form form) :lisp) +(define-caller-pattern ash (form form) :lisp) +(define-caller-pattern logcount (form) :lisp) +(define-caller-pattern integer-length (form) :lisp) + +(define-caller-pattern byte (form form) :lisp) +(define-caller-pattern byte-size (form) :lisp) +(define-caller-pattern byte-position (form) :lisp) +(define-caller-pattern ldb (form form) :lisp) +(define-caller-pattern ldb-test (form form) :lisp) +(define-caller-pattern mask-field (form form) :lisp) +(define-caller-pattern dpb (form form form) :lisp) +(define-caller-pattern deposit-field (form form form) :lisp) + +;;; Random Numbers +(define-caller-pattern random (form (:optional form)) :lisp) +(define-variable-pattern *random-state* :lisp) +(define-caller-pattern make-random-state ((:optional form)) :lisp) +(define-caller-pattern random-state-p (form) :lisp) + +;;; Implementation Parameters +(define-variable-pattern most-positive-fixnum :lisp) +(define-variable-pattern most-negative-fixnum :lisp) +(define-variable-pattern most-positive-short-float :lisp) +(define-variable-pattern least-positive-short-float :lisp) +(define-variable-pattern least-negative-short-float :lisp) +(define-variable-pattern most-negative-short-float :lisp) +(define-variable-pattern most-positive-single-float :lisp) +(define-variable-pattern least-positive-single-float :lisp) +(define-variable-pattern least-negative-single-float :lisp) +(define-variable-pattern most-negative-single-float :lisp) +(define-variable-pattern most-positive-double-float :lisp) +(define-variable-pattern least-positive-double-float :lisp) +(define-variable-pattern least-negative-double-float :lisp) +(define-variable-pattern most-negative-double-float :lisp) +(define-variable-pattern most-positive-long-float :lisp) +(define-variable-pattern least-positive-long-float :lisp) +(define-variable-pattern least-negative-long-float :lisp) +(define-variable-pattern most-negative-long-float :lisp) +(define-variable-pattern least-positive-normalized-short-float :lisp2) +(define-variable-pattern least-negative-normalized-short-float :lisp2) +(define-variable-pattern least-positive-normalized-single-float :lisp2) +(define-variable-pattern least-negative-normalized-single-float :lisp2) +(define-variable-pattern least-positive-normalized-double-float :lisp2) +(define-variable-pattern least-negative-normalized-double-float :lisp2) +(define-variable-pattern least-positive-normalized-long-float :lisp2) +(define-variable-pattern least-negative-normalized-long-float :lisp2) +(define-variable-pattern short-float-epsilon :lisp) +(define-variable-pattern single-float-epsilon :lisp) +(define-variable-pattern double-float-epsilon :lisp) +(define-variable-pattern long-float-epsilon :lisp) +(define-variable-pattern short-float-negative-epsilon :lisp) +(define-variable-pattern single-float-negative-epsilon :lisp) +(define-variable-pattern double-float-negative-epsilon :lisp) +(define-variable-pattern long-float-negative-epsilon :lisp) + +;;; Characters +(define-variable-pattern char-code-limit :lisp) +(define-variable-pattern char-font-limit :lisp) +(define-variable-pattern char-bits-limit :lisp) +(define-caller-pattern standard-char-p (form) :lisp) +(define-caller-pattern graphic-char-p (form) :lisp) +(define-caller-pattern string-char-p (form) :lisp) +(define-caller-pattern alpha-char-p (form) :lisp) +(define-caller-pattern upper-case-p (form) :lisp) +(define-caller-pattern lower-case-p (form) :lisp) +(define-caller-pattern both-case-p (form) :lisp) +(define-caller-pattern digit-char-p (form (:optional form)) :lisp) +(define-caller-pattern alphanumericp (form) :lisp) + +(define-caller-pattern char= ((:star form)) :lisp) +(define-caller-pattern char/= ((:star form)) :lisp) +(define-caller-pattern char< ((:star form)) :lisp) +(define-caller-pattern char> ((:star form)) :lisp) +(define-caller-pattern char<= ((:star form)) :lisp) +(define-caller-pattern char>= ((:star form)) :lisp) + +(define-caller-pattern char-equal ((:star form)) :lisp) +(define-caller-pattern char-not-equal ((:star form)) :lisp) +(define-caller-pattern char-lessp ((:star form)) :lisp) +(define-caller-pattern char-greaterp ((:star form)) :lisp) +(define-caller-pattern char-not-greaterp ((:star form)) :lisp) +(define-caller-pattern char-not-lessp ((:star form)) :lisp) + +(define-caller-pattern char-code (form) :lisp) +(define-caller-pattern char-bits (form) :lisp) +(define-caller-pattern char-font (form) :lisp) +(define-caller-pattern code-char (form (:optional form form)) :lisp) +(define-caller-pattern make-char (form (:optional form form)) :lisp) +(define-caller-pattern characterp (form) :lisp) +(define-caller-pattern char-upcase (form) :lisp) +(define-caller-pattern char-downcase (form) :lisp) +(define-caller-pattern digit-char (form (:optional form form)) :lisp) +(define-caller-pattern char-int (form) :lisp) +(define-caller-pattern int-char (form) :lisp) +(define-caller-pattern char-name (form) :lisp) +(define-caller-pattern name-char (form) :lisp) +(define-variable-pattern char-control-bit :lisp) +(define-variable-pattern char-meta-bit :lisp) +(define-variable-pattern char-super-bit :lisp) +(define-variable-pattern char-hyper-bit :lisp) +(define-caller-pattern char-bit (form form) :lisp) +(define-caller-pattern set-char-bit (form form form) :lisp) + +;;; Sequences +(define-caller-pattern complement (fn) :lisp2) +(define-caller-pattern elt (form form) :lisp) +(define-caller-pattern subseq (form form &optional form) :lisp) +(define-caller-pattern copy-seq (form) :lisp) +(define-caller-pattern length (form) :lisp) +(define-caller-pattern reverse (form) :lisp) +(define-caller-pattern nreverse (form) :lisp) +(define-caller-pattern make-sequence (form form &key form) :lisp) + +(define-caller-pattern concatenate (form (:star form)) :lisp) +(define-caller-pattern map (form fn form (:star form)) :lisp) +(define-caller-pattern map-into (form fn (:star form)) :lisp2) + +(define-caller-pattern some (fn form (:star form)) :lisp) +(define-caller-pattern every (fn form (:star form)) :lisp) +(define-caller-pattern notany (fn form (:star form)) :lisp) +(define-caller-pattern notevery (fn form (:star form)) :lisp) + +(define-caller-pattern reduce (fn form &key (:star form)) :lisp) +(define-caller-pattern fill (form form &key (:star form)) :lisp) +(define-caller-pattern replace (form form &key (:star form)) :lisp) +(define-caller-pattern remove (form form &key (:star form)) :lisp) +(define-caller-pattern remove-if (fn form &key (:star form)) :lisp) +(define-caller-pattern remove-if-not (fn form &key (:star form)) :lisp) +(define-caller-pattern delete (form form &key (:star form)) :lisp) +(define-caller-pattern delete-if (fn form &key (:star form)) :lisp) +(define-caller-pattern delete-if-not (fn form &key (:star form)) :lisp) +(define-caller-pattern remove-duplicates (form &key (:star form)) :lisp) +(define-caller-pattern delete-duplicates (form &key (:star form)) :lisp) +(define-caller-pattern substitute (form form form &key (:star form)) :lisp) +(define-caller-pattern substitute-if (form fn form &key (:star form)) :lisp) +(define-caller-pattern substitute-if-not (form fn form &key (:star form)) + :lisp) +(define-caller-pattern nsubstitute (form form form &key (:star form)) :lisp) +(define-caller-pattern nsubstitute-if (form fn form &key (:star form)) :lisp) +(define-caller-pattern nsubstitute-if-not (form fn form &key (:star form)) + :lisp) +(define-caller-pattern find (form form &key (:star form)) :lisp) +(define-caller-pattern find-if (fn form &key (:star form)) :lisp) +(define-caller-pattern find-if-not (fn form &key (:star form)) :lisp) +(define-caller-pattern position (form form &key (:star form)) :lisp) +(define-caller-pattern position-if (fn form &key (:star form)) :lisp) +(define-caller-pattern position-if-not (fn form &key (:star form)) :lisp) +(define-caller-pattern count (form form &key (:star form)) :lisp) +(define-caller-pattern count-if (fn form &key (:star form)) :lisp) +(define-caller-pattern count-if-not (fn form &key (:star form)) :lisp) +(define-caller-pattern mismatch (form form &key (:star form)) :lisp) +(define-caller-pattern search (form form &key (:star form)) :lisp) +(define-caller-pattern sort (form fn &key (:star form)) :lisp) +(define-caller-pattern stable-sort (form fn &key (:star form)) :lisp) +(define-caller-pattern merge (form form form fn &key (:star form)) :lisp) + +;;; Lists +(define-caller-pattern car (form) :lisp) +(define-caller-pattern cdr (form) :lisp) +(define-caller-pattern caar (form) :lisp) +(define-caller-pattern cadr (form) :lisp) +(define-caller-pattern cdar (form) :lisp) +(define-caller-pattern cddr (form) :lisp) +(define-caller-pattern caaar (form) :lisp) +(define-caller-pattern caadr (form) :lisp) +(define-caller-pattern cadar (form) :lisp) +(define-caller-pattern caddr (form) :lisp) +(define-caller-pattern cdaar (form) :lisp) +(define-caller-pattern cdadr (form) :lisp) +(define-caller-pattern cddar (form) :lisp) +(define-caller-pattern cdddr (form) :lisp) +(define-caller-pattern caaaar (form) :lisp) +(define-caller-pattern caaadr (form) :lisp) +(define-caller-pattern caadar (form) :lisp) +(define-caller-pattern caaddr (form) :lisp) +(define-caller-pattern cadaar (form) :lisp) +(define-caller-pattern cadadr (form) :lisp) +(define-caller-pattern caddar (form) :lisp) +(define-caller-pattern cadddr (form) :lisp) +(define-caller-pattern cdaaar (form) :lisp) +(define-caller-pattern cdaadr (form) :lisp) +(define-caller-pattern cdadar (form) :lisp) +(define-caller-pattern cdaddr (form) :lisp) +(define-caller-pattern cddaar (form) :lisp) +(define-caller-pattern cddadr (form) :lisp) +(define-caller-pattern cdddar (form) :lisp) +(define-caller-pattern cddddr (form) :lisp) + +(define-caller-pattern cons (form form) :lisp) +(define-caller-pattern tree-equal (form form &key (:star fn)) :lisp) +(define-caller-pattern endp (form) :lisp) +(define-caller-pattern list-length (form) :lisp) +(define-caller-pattern nth (form form) :lisp) + +(define-caller-pattern first (form) :lisp) +(define-caller-pattern second (form) :lisp) +(define-caller-pattern third (form) :lisp) +(define-caller-pattern fourth (form) :lisp) +(define-caller-pattern fifth (form) :lisp) +(define-caller-pattern sixth (form) :lisp) +(define-caller-pattern seventh (form) :lisp) +(define-caller-pattern eighth (form) :lisp) +(define-caller-pattern ninth (form) :lisp) +(define-caller-pattern tenth (form) :lisp) + +(define-caller-pattern rest (form) :lisp) +(define-caller-pattern nthcdr (form form) :lisp) +(define-caller-pattern last (form (:optional form)) :lisp) +(define-caller-pattern list ((:star form)) :lisp) +(define-caller-pattern list* ((:star form)) :lisp) +(define-caller-pattern make-list (form &key (:star form)) :lisp) +(define-caller-pattern append ((:star form)) :lisp) +(define-caller-pattern copy-list (form) :lisp) +(define-caller-pattern copy-alist (form) :lisp) +(define-caller-pattern copy-tree (form) :lisp) +(define-caller-pattern revappend (form form) :lisp) +(define-caller-pattern nconc ((:star form)) :lisp) +(define-caller-pattern nreconc (form form) :lisp) +(define-caller-pattern push (form form) :lisp) +(define-caller-pattern pushnew (form form &key (:star form)) :lisp) +(define-caller-pattern pop (form) :lisp) +(define-caller-pattern butlast (form (:optional form)) :lisp) +(define-caller-pattern nbutlast (form (:optional form)) :lisp) +(define-caller-pattern ldiff (form form) :lisp) +(define-caller-pattern rplaca (form form) :lisp) +(define-caller-pattern rplacd (form form) :lisp) + +(define-caller-pattern subst (form form form &key (:star form)) :lisp) +(define-caller-pattern subst-if (form fn form &key (:star form)) :lisp) +(define-caller-pattern subst-if-not (form fn form &key (:star form)) :lisp) +(define-caller-pattern nsubst (form form form &key (:star form)) :lisp) +(define-caller-pattern nsubst-if (form fn form &key (:star form)) :lisp) +(define-caller-pattern nsubst-if-not (form fn form &key (:star form)) :lisp) +(define-caller-pattern sublis (form form &key (:star form)) :lisp) +(define-caller-pattern nsublis (form form &key (:star form)) :lisp) +(define-caller-pattern member (form form &key (:star form)) :lisp) +(define-caller-pattern member-if (fn form &key (:star form)) :lisp) +(define-caller-pattern member-if-not (fn form &key (:star form)) :lisp) + +(define-caller-pattern tailp (form form) :lisp) +(define-caller-pattern adjoin (form form &key (:star form)) :lisp) +(define-caller-pattern union (form form &key (:star form)) :lisp) +(define-caller-pattern nunion (form form &key (:star form)) :lisp) +(define-caller-pattern intersection (form form &key (:star form)) :lisp) +(define-caller-pattern nintersection (form form &key (:star form)) :lisp) +(define-caller-pattern set-difference (form form &key (:star form)) :lisp) +(define-caller-pattern nset-difference (form form &key (:star form)) :lisp) +(define-caller-pattern set-exclusive-or (form form &key (:star form)) :lisp) +(define-caller-pattern nset-exclusive-or (form form &key (:star form)) :lisp) +(define-caller-pattern subsetp (form form &key (:star form)) :lisp) + +(define-caller-pattern acons (form form form) :lisp) +(define-caller-pattern pairlis (form form (:optional form)) :lisp) +(define-caller-pattern assoc (form form &key (:star form)) :lisp) +(define-caller-pattern assoc-if (fn form) :lisp) +(define-caller-pattern assoc-if-not (fn form) :lisp) +(define-caller-pattern rassoc (form form &key (:star form)) :lisp) +(define-caller-pattern rassoc-if (fn form &key (:star form)) :lisp) +(define-caller-pattern rassoc-if-not (fn form &key (:star form)) :lisp) + +;;; Hash Tables +(define-caller-pattern make-hash-table (&key (:star form)) :lisp) +(define-caller-pattern hash-table-p (form) :lisp) +(define-caller-pattern gethash (form form (:optional form)) :lisp) +(define-caller-pattern remhash (form form) :lisp) +(define-caller-pattern maphash (fn form) :lisp) +(define-caller-pattern clrhash (form) :lisp) +(define-caller-pattern hash-table-count (form) :lisp) +(define-caller-pattern with-hash-table-iterator + ((name form) (:star form)) :lisp2) +(define-caller-pattern hash-table-rehash-size (form) :lisp2) +(define-caller-pattern hash-table-rehash-threshold (form) :lisp2) +(define-caller-pattern hash-table-size (form) :lisp2) +(define-caller-pattern hash-table-test (form) :lisp2) +(define-caller-pattern sxhash (form) :lisp) + +;;; Arrays +(define-caller-pattern make-array (form &key (:star form)) :lisp) +(define-variable-pattern array-rank-limit :lisp) +(define-variable-pattern array-dimension-limit :lisp) +(define-variable-pattern array-total-size-limit :lisp) +(define-caller-pattern vector ((:star form)) :lisp) +(define-caller-pattern aref (form (:star form)) :lisp) +(define-caller-pattern svref (form form) :lisp) +(define-caller-pattern array-element-type (form) :lisp) +(define-caller-pattern array-rank (form) :lisp) +(define-caller-pattern array-dimension (form form) :lisp) +(define-caller-pattern array-dimensions (form) :lisp) +(define-caller-pattern array-total-size (form) :lisp) +(define-caller-pattern array-in-bounds-p (form (:star form)) :lisp) +(define-caller-pattern array-row-major-index (form (:star form)) :lisp) +(define-caller-pattern row-major-aref (form form) :lisp2) +(define-caller-pattern adjustable-array-p (form) :lisp) + +(define-caller-pattern bit (form (:star form)) :lisp) +(define-caller-pattern sbit (form (:star form)) :lisp) + +(define-caller-pattern bit-and (form form (:optional form)) :lisp) +(define-caller-pattern bit-ior (form form (:optional form)) :lisp) +(define-caller-pattern bit-xor (form form (:optional form)) :lisp) +(define-caller-pattern bit-eqv (form form (:optional form)) :lisp) +(define-caller-pattern bit-nand (form form (:optional form)) :lisp) +(define-caller-pattern bit-nor (form form (:optional form)) :lisp) +(define-caller-pattern bit-andc1 (form form (:optional form)) :lisp) +(define-caller-pattern bit-andc2 (form form (:optional form)) :lisp) +(define-caller-pattern bit-orc1 (form form (:optional form)) :lisp) +(define-caller-pattern bit-orc2 (form form (:optional form)) :lisp) +(define-caller-pattern bit-not (form (:optional form)) :lisp) + +(define-caller-pattern array-has-fill-pointer-p (form) :lisp) +(define-caller-pattern fill-pointer (form) :lisp) +(define-caller-pattern vector-push (form form) :lisp) +(define-caller-pattern vector-push-extend (form form (:optional form)) :lisp) +(define-caller-pattern vector-pop (form) :lisp) +(define-caller-pattern adjust-array (form form &key (:star form)) :lisp) + +;;; Strings +(define-caller-pattern char (form form) :lisp) +(define-caller-pattern schar (form form) :lisp) +(define-caller-pattern string= (form form &key (:star form)) :lisp) +(define-caller-pattern string-equal (form form &key (:star form)) :lisp) +(define-caller-pattern string< (form form &key (:star form)) :lisp) +(define-caller-pattern string> (form form &key (:star form)) :lisp) +(define-caller-pattern string<= (form form &key (:star form)) :lisp) +(define-caller-pattern string>= (form form &key (:star form)) :lisp) +(define-caller-pattern string/= (form form &key (:star form)) :lisp) +(define-caller-pattern string-lessp (form form &key (:star form)) :lisp) +(define-caller-pattern string-greaterp (form form &key (:star form)) :lisp) +(define-caller-pattern string-not-greaterp (form form &key (:star form)) :lisp) +(define-caller-pattern string-not-lessp (form form &key (:star form)) :lisp) +(define-caller-pattern string-not-equal (form form &key (:star form)) :lisp) + +(define-caller-pattern make-string (form &key (:star form)) :lisp) +(define-caller-pattern string-trim (form form) :lisp) +(define-caller-pattern string-left-trim (form form) :lisp) +(define-caller-pattern string-right-trim (form form) :lisp) +(define-caller-pattern string-upcase (form &key (:star form)) :lisp) +(define-caller-pattern string-downcase (form &key (:star form)) :lisp) +(define-caller-pattern string-capitalize (form &key (:star form)) :lisp) +(define-caller-pattern nstring-upcase (form &key (:star form)) :lisp) +(define-caller-pattern nstring-downcase (form &key (:star form)) :lisp) +(define-caller-pattern nstring-capitalize (form &key (:star form)) :lisp) +(define-caller-pattern string (form) :lisp) + +;;; Structures +(define-caller-pattern defstruct + ((:or name (name (:rest :ignore))) + (:optional documentation-string) + (:plus :ignore)) + :lisp) + +;;; The Evaluator +(define-caller-pattern eval (form) :lisp) +(define-variable-pattern *evalhook* :lisp) +(define-variable-pattern *applyhook* :lisp) +(define-caller-pattern evalhook (form fn fn &optional :ignore) :lisp) +(define-caller-pattern applyhook (fn form fn fn &optional :ignore) :lisp) +(define-caller-pattern constantp (form) :lisp) + +;;; Streams +(define-variable-pattern *standard-input* :lisp) +(define-variable-pattern *standard-output* :lisp) +(define-variable-pattern *error-output* :lisp) +(define-variable-pattern *query-io* :lisp) +(define-variable-pattern *debug-io* :lisp) +(define-variable-pattern *terminal-io* :lisp) +(define-variable-pattern *trace-output* :lisp) +(define-caller-pattern make-synonym-stream (symbol) :lisp) +(define-caller-pattern make-broadcast-stream ((:star form)) :lisp) +(define-caller-pattern make-concatenated-stream ((:star form)) :lisp) +(define-caller-pattern make-two-way-stream (form form) :lisp) +(define-caller-pattern make-echo-stream (form form) :lisp) +(define-caller-pattern make-string-input-stream (form &optional form form) + :lisp) +(define-caller-pattern make-string-output-stream (&key (:star form)) :lisp) +(define-caller-pattern get-output-stream-string (form) :lisp) + +(define-caller-pattern with-open-stream + ((var form) + (:star declaration) + (:star form)) + :lisp) + +(define-caller-pattern with-input-from-string + ((var form &key (:star form)) + (:star declaration) + (:star form)) + :lisp) + +(define-caller-pattern with-output-to-string + ((var (:optional form)) + (:star declaration) + (:star form)) + :lisp) +(define-caller-pattern streamp (form) :lisp) +(define-caller-pattern open-stream-p (form) :lisp2) +(define-caller-pattern input-stream-p (form) :lisp) +(define-caller-pattern output-stream-p (form) :lisp) +(define-caller-pattern stream-element-type (form) :lisp) +(define-caller-pattern close (form (:rest :ignore)) :lisp) +(define-caller-pattern broadcast-stream-streams (form) :lisp2) +(define-caller-pattern concatenated-stream-streams (form) :lisp2) +(define-caller-pattern echo-stream-input-stream (form) :lisp2) +(define-caller-pattern echo-stream-output-stream (form) :lisp2) +(define-caller-pattern synonym-stream-symbol (form) :lisp2) +(define-caller-pattern two-way-stream-input-stream (form) :lisp2) +(define-caller-pattern two-way-stream-output-stream (form) :lisp2) +(define-caller-pattern interactive-stream-p (form) :lisp2) +(define-caller-pattern stream-external-format (form) :lisp2) + +;;; Reader +(define-variable-pattern *read-base* :lisp) +(define-variable-pattern *read-suppress* :lisp) +(define-variable-pattern *read-eval* :lisp2) +(define-variable-pattern *readtable* :lisp) +(define-caller-pattern copy-readtable (&optional form form) :lisp) +(define-caller-pattern readtablep (form) :lisp) +(define-caller-pattern set-syntax-from-char (form form &optional form form) + :lisp) +(define-caller-pattern set-macro-character (form fn &optional form) :lisp) +(define-caller-pattern get-macro-character (form (:optional form)) :lisp) +(define-caller-pattern make-dispatch-macro-character (form &optional form form) + :lisp) +(define-caller-pattern set-dispatch-macro-character + (form form fn (:optional form)) :lisp) +(define-caller-pattern get-dispatch-macro-character + (form form (:optional form)) :lisp) +(define-caller-pattern readtable-case (form) :lisp2) +(define-variable-pattern *print-readably* :lisp2) +(define-variable-pattern *print-escape* :lisp) +(define-variable-pattern *print-pretty* :lisp) +(define-variable-pattern *print-circle* :lisp) +(define-variable-pattern *print-base* :lisp) +(define-variable-pattern *print-radix* :lisp) +(define-variable-pattern *print-case* :lisp) +(define-variable-pattern *print-gensym* :lisp) +(define-variable-pattern *print-level* :lisp) +(define-variable-pattern *print-length* :lisp) +(define-variable-pattern *print-array* :lisp) +(define-caller-pattern with-standard-io-syntax + ((:star declaration) + (:star form)) + :lisp2) + +(define-caller-pattern read (&optional form form form form) :lisp) +(define-variable-pattern *read-default-float-format* :lisp) +(define-caller-pattern read-preserving-whitespace + (&optional form form form form) :lisp) +(define-caller-pattern read-delimited-list (form &optional form form) :lisp) +(define-caller-pattern read-line (&optional form form form form) :lisp) +(define-caller-pattern read-char (&optional form form form form) :lisp) +(define-caller-pattern unread-char (form (:optional form)) :lisp) +(define-caller-pattern peek-char (&optional form form form form) :lisp) +(define-caller-pattern listen ((:optional form)) :lisp) +(define-caller-pattern read-char-no-hang ((:star form)) :lisp) +(define-caller-pattern clear-input ((:optional form)) :lisp) +(define-caller-pattern read-from-string (form (:star form)) :lisp) +(define-caller-pattern parse-integer (form &rest :ignore) :lisp) +(define-caller-pattern read-byte ((:star form)) :lisp) + +(define-caller-pattern write (form &key (:star form)) :lisp) +(define-caller-pattern prin1 (form (:optional form)) :lisp) +(define-caller-pattern print (form (:optional form)) :lisp) +(define-caller-pattern pprint (form (:optional form)) :lisp) +(define-caller-pattern princ (form (:optional form)) :lisp) +(define-caller-pattern write-to-string (form &key (:star form)) :lisp) +(define-caller-pattern prin1-to-string (form) :lisp) +(define-caller-pattern princ-to-string (form) :lisp) +(define-caller-pattern write-char (form (:optional form)) :lisp) +(define-caller-pattern write-string (form &optional form &key (:star form)) + :lisp) +(define-caller-pattern write-line (form &optional form &key (:star form)) + :lisp) +(define-caller-pattern terpri ((:optional form)) :lisp) +(define-caller-pattern fresh-line ((:optional form)) :lisp) +(define-caller-pattern finish-output ((:optional form)) :lisp) +(define-caller-pattern force-output ((:optional form)) :lisp) +(define-caller-pattern clear-output ((:optional form)) :lisp) +(define-caller-pattern print-unreadable-object + ((form form &key (:star form)) + (:star declaration) + (:star form)) + :lisp2) +(define-caller-pattern write-byte (form form) :lisp) +(define-caller-pattern format + (destination + control-string + (:rest format-arguments)) + :lisp) + +(define-caller-pattern y-or-n-p (control-string (:star form)) :lisp) +(define-caller-pattern yes-or-no-p (control-string (:star form)) :lisp) + +;;; Pathnames +(define-caller-pattern wild-pathname-p (form &optional form) :lisp2) +(define-caller-pattern pathname-match-p (form form) :lisp2) +(define-caller-pattern translate-pathname (form form form &key (:star form)) + :lisp2) + +(define-caller-pattern logical-pathname (form) :lisp2) +(define-caller-pattern translate-logical-pathname (form &key (:star form)) + :lisp2) +(define-caller-pattern logical-pathname-translations (form) :lisp2) +(define-caller-pattern load-logical-pathname-translations (form) :lisp2) +(define-caller-pattern compile-file-pathname (form &key form) :lisp2) + +(define-caller-pattern pathname (form) :lisp) +(define-caller-pattern truename (form) :lisp) +(define-caller-pattern parse-namestring ((:star form)) :lisp) +(define-caller-pattern merge-pathnames ((:star form)) :lisp) +(define-variable-pattern *default-pathname-defaults* :lisp) +(define-caller-pattern make-pathname ((:star form)) :lisp) +(define-caller-pattern pathnamep (form) :lisp) +(define-caller-pattern pathname-host (form) :lisp) +(define-caller-pattern pathname-device (form) :lisp) +(define-caller-pattern pathname-directory (form) :lisp) +(define-caller-pattern pathname-name (form) :lisp) +(define-caller-pattern pathname-type (form) :lisp) +(define-caller-pattern pathname-version (form) :lisp) +(define-caller-pattern namestring (form) :lisp) +(define-caller-pattern file-namestring (form) :lisp) +(define-caller-pattern directory-namestring (form) :lisp) +(define-caller-pattern host-namestring (form) :lisp) +(define-caller-pattern enough-namestring (form (:optional form)) :lisp) +(define-caller-pattern user-homedir-pathname (&optional form) :lisp) +(define-caller-pattern open (form &key (:star form)) :lisp) +(define-caller-pattern with-open-file + ((var form (:rest :ignore)) + (:star declaration) + (:star form)) + :lisp) + +(define-caller-pattern rename-file (form form) :lisp) +(define-caller-pattern delete-file (form) :lisp) +(define-caller-pattern probe-file (form) :lisp) +(define-caller-pattern file-write-date (form) :lisp) +(define-caller-pattern file-author (form) :lisp) +(define-caller-pattern file-position (form (:optional form)) :lisp) +(define-caller-pattern file-length (form) :lisp) +(define-caller-pattern file-string-length (form form) :lisp2) +(define-caller-pattern load (form &key (:star form)) :lisp) +(define-variable-pattern *load-verbose* :lisp) +(define-variable-pattern *load-print* :lisp2) +(define-variable-pattern *load-pathname* :lisp2) +(define-variable-pattern *load-truename* :lisp2) +(define-caller-pattern make-load-form (form) :lisp2) +(define-caller-pattern make-load-form-saving-slots (form &optional form) + :lisp2) +(define-caller-pattern directory (form &key (:star form)) :lisp) + +;;; Errors +(define-caller-pattern error (form (:star form)) :lisp) +(define-caller-pattern cerror (form form (:star form)) :lisp) +(define-caller-pattern warn (form (:star form)) :lisp) +(define-variable-pattern *break-on-warnings* :lisp) +(define-caller-pattern break (&optional form (:star form)) :lisp) +(define-caller-pattern check-type (form form (:optional form)) :lisp) +(define-caller-pattern assert + (form + (:optional ((:star var)) + (:optional form (:star form)))) + :lisp) +(define-caller-pattern etypecase (form (:star (symbol (:star form)))) :lisp) +(define-caller-pattern ctypecase (form (:star (symbol (:star form)))) :lisp) +(define-caller-pattern ecase + (form + (:star ((:or symbol ((:star symbol))) + (:star form)))) + :lisp) +(define-caller-pattern ccase + (form + (:star ((:or symbol ((:star symbol))) + (:star form)))) + :lisp) + +;;; The Compiler +(define-caller-pattern compile (form (:optional form)) :lisp) +(define-caller-pattern compile-file (form &key (:star form)) :lisp) +(define-variable-pattern *compile-verbose* :lisp2) +(define-variable-pattern *compile-print* :lisp2) +(define-variable-pattern *compile-file-pathname* :lisp2) +(define-variable-pattern *compile-file-truename* :lisp2) +(define-caller-pattern load-time-value (form (:optional form)) :lisp2) +(define-caller-pattern disassemble (form) :lisp) +(define-caller-pattern function-lambda-expression (fn) :lisp2) +(define-caller-pattern with-compilation-unit (((:star :ignore)) (:star form)) + :lisp2) + +;;; Documentation +(define-caller-pattern documentation (form form) :lisp) +(define-caller-pattern trace ((:star form)) :lisp) +(define-caller-pattern untrace ((:star form)) :lisp) +(define-caller-pattern step (form) :lisp) +(define-caller-pattern time (form) :lisp) +(define-caller-pattern describe (form &optional form) :lisp) +(define-caller-pattern describe-object (form &optional form) :lisp2) +(define-caller-pattern inspect (form) :lisp) +(define-caller-pattern room ((:optional form)) :lisp) +(define-caller-pattern ed ((:optional form)) :lisp) +(define-caller-pattern dribble ((:optional form)) :lisp) +(define-caller-pattern apropos (form (:optional form)) :lisp) +(define-caller-pattern apropos-list (form (:optional form)) :lisp) +(define-caller-pattern get-decoded-time () :lisp) +(define-caller-pattern get-universal-time () :lisp) +(define-caller-pattern decode-universal-time (form &optional form) :lisp) +(define-caller-pattern encode-universal-time + (form form form form form form &optional form) :lisp) +(define-caller-pattern get-internal-run-time () :lisp) +(define-caller-pattern get-internal-real-time () :lisp) +(define-caller-pattern sleep (form) :lisp) + +(define-caller-pattern lisp-implementation-type () :lisp) +(define-caller-pattern lisp-implementation-version () :lisp) +(define-caller-pattern machine-type () :lisp) +(define-caller-pattern machine-version () :lisp) +(define-caller-pattern machine-instance () :lisp) +(define-caller-pattern software-type () :lisp) +(define-caller-pattern software-version () :lisp) +(define-caller-pattern short-site-name () :lisp) +(define-caller-pattern long-site-name () :lisp) +(define-variable-pattern *features* :lisp) + +(define-caller-pattern identity (form) :lisp) + +;;; Pretty Printing +(define-variable-pattern *print-pprint-dispatch* :lisp2) +(define-variable-pattern *print-right-margin* :lisp2) +(define-variable-pattern *print-miser-width* :lisp2) +(define-variable-pattern *print-lines* :lisp2) +(define-caller-pattern pprint-newline (form &optional form) :lisp2) +(define-caller-pattern pprint-logical-block + ((var form &key (:star form)) + (:star form)) + :lisp2) +(define-caller-pattern pprint-exit-if-list-exhausted () :lisp2) +(define-caller-pattern pprint-pop () :lisp2) +(define-caller-pattern pprint-indent (form form &optional form) :lisp2) +(define-caller-pattern pprint-tab (form form form &optional form) :lisp2) +(define-caller-pattern pprint-fill (form form &optional form form) :lisp2) +(define-caller-pattern pprint-linear (form form &optional form form) :lisp2) +(define-caller-pattern pprint-tabular (form form &optional form form form) + :lisp2) +(define-caller-pattern formatter (control-string) :lisp2) +(define-caller-pattern copy-pprint-dispatch (&optional form) :lisp2) +(define-caller-pattern pprint-dispatch (form &optional form) :lisp2) +(define-caller-pattern set-pprint-dispatch (form form &optional form form) + :lisp2) + +;;; CLOS +(define-caller-pattern add-method (fn form) :lisp2) +(define-caller-pattern call-method (form form) :lisp2) +(define-caller-pattern call-next-method ((:star form)) :lisp2) +(define-caller-pattern change-class (form form) :lisp2) +(define-caller-pattern class-name (form) :lisp2) +(define-caller-pattern class-of (form) :lisp2) +(define-caller-pattern compute-applicable-methods (fn (:star form)) :lisp2) +(define-caller-pattern defclass (name &rest :ignore) :lisp2) +(define-caller-pattern defgeneric (name lambda-list &rest :ignore) :lisp2) +(define-caller-pattern define-method-combination + (name lambda-list ((:star :ignore)) + (:optional ((:eq :arguments) :ignore)) + (:optional ((:eq :generic-function) :ignore)) + (:star (:or declaration documentation-string)) + (:star form)) + :lisp2) +(define-caller-pattern defmethod + (name (:star symbol) lambda-list + (:star (:or declaration documentation-string)) + (:star form)) + :lisp2) +(define-caller-pattern ensure-generic-function (name &key (:star form)) :lisp2) +(define-caller-pattern find-class (form &optional form form) :lisp2) +(define-caller-pattern find-method (fn &rest :ignore) :lisp2) +(define-caller-pattern function-keywords (&rest :ignore) :lisp2) +(define-caller-pattern generic-flet (((:star (name lambda-list))) (:star form)) + :lisp2) +(define-caller-pattern generic-labels + (((:star (name lambda-list))) (:star form)) + :lisp2) +(define-caller-pattern generic-function (lambda-list) :lisp2) +(define-caller-pattern initialize-instance (form &key (:star form)) :lisp2) +(define-caller-pattern invalid-method-error (fn form (:star form)) :lisp2) +(define-caller-pattern make-instance (fn (:star form)) :lisp2) +(define-caller-pattern make-instances-obsolete (fn) :lisp2) +(define-caller-pattern method-combination-error (form (:star form)) :lisp2) +(define-caller-pattern method-qualifiers (fn) :lisp2) +(define-caller-pattern next-method-p () :lisp2) +(define-caller-pattern no-applicable-method (fn (:star form)) :lisp2) +(define-caller-pattern no-next-method (fn (:star form)) :lisp2) +(define-caller-pattern print-object (form form) :lisp2) +(define-caller-pattern reinitialize-instance (form (:star form)) :lisp2) +(define-caller-pattern remove-method (fn form) :lisp2) +(define-caller-pattern shared-initialize (form form (:star form)) :lisp2) +(define-caller-pattern slot-boundp (form form) :lisp2) +(define-caller-pattern slot-exists-p (form form) :lisp2) +(define-caller-pattern slot-makeunbound (form form) :lisp2) +(define-caller-pattern slot-missing (fn form form form &optional form) :lisp2) +(define-caller-pattern slot-unbound (fn form form) :lisp2) +(define-caller-pattern slot-value (form form) :lisp2) +(define-caller-pattern update-instance-for-different-class + (form form (:star form)) :lisp2) +(define-caller-pattern update-instance-for-redefined-class + (form form (:star form)) :lisp2) +(define-caller-pattern with-accessors + (((:star :ignore)) form + (:star declaration) + (:star form)) + :lisp2) +(define-caller-pattern with-added-methods + ((name lambda-list) form + (:star form)) + :lisp2) +(define-caller-pattern with-slots + (((:star :ignore)) form + (:star declaration) + (:star form)) + :lisp2) + +;;; Conditions +(define-caller-pattern signal (form (:star form)) :lisp2) +(define-variable-pattern *break-on-signals* :lisp2) +(define-caller-pattern handler-case (form (:star (form ((:optional var)) + (:star form)))) + :lisp2) +(define-caller-pattern ignore-errors ((:star form)) :lisp2) +(define-caller-pattern handler-bind (((:star (form form))) + (:star form)) + :lisp2) +(define-caller-pattern define-condition (name &rest :ignore) :lisp2) +(define-caller-pattern make-condition (form &rest :ignore) :lisp2) +(define-caller-pattern with-simple-restart + ((name form (:star form)) (:star form)) :lisp2) +(define-caller-pattern restart-case + (form + (:star (form form (:star form)))) + :lisp2) +(define-caller-pattern restart-bind + (((:star (name fn &key (:star form)))) + (:star form)) + :lisp2) +(define-caller-pattern with-condition-restarts + (form form + (:star declaration) + (:star form)) + :lisp2) +(define-caller-pattern compute-restarts (&optional form) :lisp2) +(define-caller-pattern restart-name (form) :lisp2) +(define-caller-pattern find-restart (form &optional form) :lisp2) +(define-caller-pattern invoke-restart (form (:star form)) :lisp2) +(define-caller-pattern invoke-restart-interactively (form) :lisp2) +(define-caller-pattern abort (&optional form) :lisp2) +(define-caller-pattern continue (&optional form) :lisp2) +(define-caller-pattern muffle-warning (&optional form) :lisp2) +(define-caller-pattern store-value (form &optional form) :lisp2) +(define-caller-pattern use-value (form &optional form) :lisp2) +(define-caller-pattern invoke-debugger (form) :lisp2) +(define-variable-pattern *debugger-hook* :lisp2) +(define-caller-pattern simple-condition-format-string (form) :lisp2) +(define-caller-pattern simple-condition-format-arguments (form) :lisp2) +(define-caller-pattern type-error-datum (form) :lisp2) +(define-caller-pattern type-error-expected-type (form) :lisp2) +(define-caller-pattern package-error-package (form) :lisp2) +(define-caller-pattern stream-error-stream (form) :lisp2) +(define-caller-pattern file-error-pathname (form) :lisp2) +(define-caller-pattern cell-error-name (form) :lisp2) +(define-caller-pattern arithmetic-error-operation (form) :lisp2) +(define-caller-pattern arithmetic-error-operands (form) :lisp2) + +;;; For ZetaLisp Flavors +(define-caller-pattern send (form fn (:star form)) :flavors) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/LICENSE b/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/LICENSE new file mode 100644 index 0000000..5ea30c8 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/LICENSE @@ -0,0 +1,21 @@ +Copyright (C) 2001-2018, Arthur Lemmens et al. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/README.md b/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/README.md new file mode 100644 index 0000000..47dc29b --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/README.md @@ -0,0 +1,109 @@ +SPLIT-SEQUENCE +============== + +[SPLIT-SEQUENCE](http://cliki.net/split-sequence) is a member of the +[Common Lisp Utilities](http://cliki.net/Common%20Lisp%20Utilities) +family of programs, designed by community consensus. + + +_Function_ __SPLIT-SEQUENCE, SPLIT-SEQUENCE-IF, SPLIT-SEQUENCE-IF-NOT__ + + +__Syntax:__ + +__split-sequence__ _delimiter sequence `&key` count +remove-empty-subseqs from-end start end test test-not key ⇒ list, +index_ + +__split-sequence-if__ _predicate sequence `&key` count +remove-empty-subseqs from-end start end key ⇒ list, index_ + +__split-sequence-if-not__ _predicate sequence `&key` count +remove-empty-subseqs from-end start end key ⇒ list, index_ + + +__Arguments and Values:__ + +_delimiter_—an _object_. + +_predicate_—a designator for a _function_ of one _argument_ that +returns a _generalized boolean_. + +_sequence_—a _proper sequence_. + +_count_—an _integer_ or __nil__. The default is __nil__. + +_remove-empty-subseqs_—a _generalized boolean_. The default is +_false_. + +_from-end_—a _generalized boolean_. The default is _false_. + +_start, end_—_bounding index designators_ of _sequence_. The +defaults for _start_ and _end_ are __0__ and __nil__, respectively. + +_test_—a _designator_ for a _function_ of two _arguments_ that +returns a _generalized boolean_. + +_test-not_—a _designator_ for a _function_ of two _arguments_ +that returns a _generalized boolean_. + +_key_—a _designator_ for a _function_ of one _argument_, or +__nil__. + +_list_—a _proper sequence_. + +_index_—an _integer_ greater than or equal to zero, and less +than or equal to the _length_ of the _sequence_. + + +__Description:__ + +Splits _sequence_ into a list of subsequences delimited by objects +_satisfying the test_. + +_List_ is a list of sequences of the same kind as _sequence_ that has +elements consisting of subsequences of _sequence_ that were delimited +in the argument by elements _satisfying the test_. Index is an index +into _sequence_ indicating the unprocessed region, suitable as an +argument to +[subseq](http://www.lispworks.com/documentation/HyperSpec/Body/f_subseq.htm) +to continue processing in the same manner if desired. + +The _count_ argument, if supplied, limits the number of subsequences +in the first return value; if more than _count_ delimited subsequences +exist in _sequence_, the _count_ leftmost delimited subsequences will +be in order in the first return value, and the second return value +will be the index into _sequence_ at which processing stopped. + +If _from-end_ is non-null, _sequence_ is conceptually processed from +right to left, accumulating the subsequences in reverse order; +_from-end_ only makes a difference in the case of a non-null _count_ +argument. In the presence of _from-end_, the _count_ rightmost +delimited subsequences will be in the order that they are in +_sequence_ in the first return value, and the second is the index +indicating the end of the unprocessed region. + +The _start_ and _end_ keyword arguments permit a certain subsequence +of the _sequence_ to be processed without the need for a copying +stage; their use is conceptually equivalent to partitioning the +subsequence delimited by _start_ and _end_, only without the need for +copying. + +If _remove-empty-subseqs_ is null (the default), then empty +subsequences will be included in the result. + +In all cases, the subsequences in the first return value will be in +the order that they appeared in _sequence_. + + +__Examples:__ + +
+SPLIT-SEQUENCE> (split-sequence #\Space "A stitch in time saves nine.")
+⇒ ("A" "stitch" "in" "time" "saves" "nine.")
+⇒ 28
+
+SPLIT-SEQUENCE> (split-sequence #\, "foo,bar ,baz, foobar , barbaz,")
+⇒ ("foo" "bar " "baz" " foobar " " barbaz" "")
+⇒ 30
+
diff --git a/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/api.lisp b/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/api.lisp new file mode 100644 index 0000000..fad0af7 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/api.lisp @@ -0,0 +1,79 @@ +;;;; -*- Mode: Lisp; indent-tabs-mode: nil -*- + +(in-package :split-sequence) + +(defun list-long-enough-p (list length) + (or (zerop length) + (not (null (nthcdr (1- length) list))))) + +(defun check-bounds (sequence start end) + (progn + (check-type start unsigned-byte "a non-negative integer") + (check-type end (or null unsigned-byte) "a non-negative integer or NIL") + (typecase sequence + (list + (when end + (unless (list-long-enough-p sequence end) + (error "The list is too short: END was ~S but the list is ~S elements long." + end (length sequence))))) + (t + (let ((length (length sequence))) + (unless end (setf end length)) + (unless (<= start end length) + (error "Wrong sequence bounds. START: ~S END: ~S" start end))))))) + +(define-condition simple-program-error (program-error simple-condition) ()) + +(defmacro check-tests (test test-p test-not test-not-p) + `(progn + (when (and ,test-p ,test-not-p) + (error (make-condition 'simple-program-error + :format-control "Cannot specify both TEST and TEST-NOT."))) + (when (and ,test-not-p (not ,test-p)) + (check-type ,test-not (or function (and symbol (not null))))) + (when (and ,test-p (not ,test-not-p)) + (check-type ,test (or function (and symbol (not null))))))) + +(declaim (ftype (function (&rest t) (values list unsigned-byte)) + split-sequence split-sequence-if split-sequence-if-not)) + +(defun split-sequence (delimiter sequence &key (start 0) (end nil) (from-end nil) + (count nil) (remove-empty-subseqs nil) + (test #'eql test-p) (test-not nil test-not-p) + (key #'identity)) + (check-bounds sequence start end) + (check-tests test test-p test-not test-not-p) + (etypecase sequence + (list (split-list delimiter sequence start end from-end count + remove-empty-subseqs test test-not key)) + (vector (split-vector delimiter sequence start end from-end count + remove-empty-subseqs test test-not key)) + #+(or abcl sbcl) + (extended-sequence (split-extended-sequence delimiter sequence start end from-end count + remove-empty-subseqs test test-not key)))) + +(defun split-sequence-if (predicate sequence &key (start 0) (end nil) (from-end nil) + (count nil) (remove-empty-subseqs nil) (key #'identity)) + (check-bounds sequence start end) + (etypecase sequence + (list (split-list-if predicate sequence start end from-end count + remove-empty-subseqs key)) + (vector (split-vector-if predicate sequence start end from-end count + remove-empty-subseqs key)) + #+(or abcl sbcl) + (extended-sequence (split-extended-sequence-if predicate sequence start end from-end count + remove-empty-subseqs key)))) + +(defun split-sequence-if-not (predicate sequence &key (start 0) (end nil) (from-end nil) + (count nil) (remove-empty-subseqs nil) (key #'identity)) + (check-bounds sequence start end) + (etypecase sequence + (list (split-list-if-not predicate sequence start end from-end count + remove-empty-subseqs key)) + (vector (split-vector-if-not predicate sequence start end from-end count + remove-empty-subseqs key)) + #+(or abcl sbcl) + (extended-sequence (split-extended-sequence-if-not predicate sequence start end from-end count + remove-empty-subseqs key)))) + +(pushnew :split-sequence *features*) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/documentation.lisp b/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/documentation.lisp new file mode 100644 index 0000000..f05c4eb --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/documentation.lisp @@ -0,0 +1,41 @@ +;;;; -*- Mode: Lisp; indent-tabs-mode: nil -*- + +(in-package :split-sequence) + +(setf (documentation 'split-sequence 'function) + "Return a list of subsequences in seq delimited by delimiter. +If :remove-empty-subseqs is NIL, empty subsequences will be included +in the result; otherwise they will be discarded. All other keywords +work analogously to those for CL:SUBSTITUTE. In particular, the +behaviour of :from-end is possibly different from other versions of +this function; :from-end values of NIL and T are equivalent unless +:count is supplied. :count limits the number of subseqs in the main +resulting list. The second return value is an index suitable as an +argument to CL:SUBSEQ into the sequence indicating where processing +stopped.") + +(setf (documentation 'split-sequence-if 'function) + "Return a list of subsequences in seq delimited by items satisfying +predicate. +If :remove-empty-subseqs is NIL, empty subsequences will be included +in the result; otherwise they will be discarded. All other keywords +work analogously to those for CL:SUBSTITUTE-IF. In particular, the +behaviour of :from-end is possibly different from other versions of +this function; :from-end values of NIL and T are equivalent unless +:count is supplied. :count limits the number of subseqs in the main +resulting list. The second return value is an index suitable as an +argument to CL:SUBSEQ into the sequence indicating where processing +stopped.") + +(setf (documentation 'split-sequence-if-not 'function) + "Return a list of subsequences in seq delimited by items satisfying +\(CL:COMPLEMENT predicate). +If :remove-empty-subseqs is NIL, empty subsequences will be included +in the result; otherwise they will be discarded. All other keywords +work analogously to those for CL:SUBSTITUTE-IF-NOT. In particular, +the behaviour of :from-end is possibly different from other versions +of this function; :from-end values of NIL and T are equivalent unless +:count is supplied. :count limits the number of subseqs in the main +resulting list. The second return value is an index suitable as an +argument to CL:SUBSEQ into the sequence indicating where processing +stopped.") diff --git a/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/extended-sequence.lisp b/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/extended-sequence.lisp new file mode 100644 index 0000000..8341d5f --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/extended-sequence.lisp @@ -0,0 +1,100 @@ +;;;; -*- Mode: Lisp; indent-tabs-mode: nil -*- + +(in-package :split-sequence) + +;;; For extended sequences, we make the assumption that all extended sequences +;;; can be at most ARRAY-DIMENSION-LIMIT long. This seems to match what SBCL +;;; assumes about them. + +;;; TODO test this code. This will require creating such an extended sequence. + +(deftype extended-sequence () + '(and sequence (not list) (not vector))) + +(declaim (inline + split-extended-sequence split-extended-sequence-if split-extended-sequence-if-not + split-extended-sequence-from-end split-extended-sequence-from-start)) + +(declaim (ftype (function (&rest t) (values list unsigned-byte)) + split-extended-sequence split-extended-sequence-if split-extended-sequence-if-not)) + +(declaim (ftype (function (function extended-sequence array-index + (or null fixnum) (or null fixnum) boolean) + (values list fixnum)) + split-extended-sequence-from-start split-extended-sequence-from-end)) + +(defun split-extended-sequence + (delimiter sequence start end from-end count remove-empty-subseqs test test-not key) + (cond + ((and (not from-end) (null test-not)) + (split-extended-sequence-from-start (lambda (sequence start) + (position delimiter sequence :start start :key key :test test)) + sequence start end count remove-empty-subseqs)) + ((and (not from-end) test-not) + (split-extended-sequence-from-start (lambda (sequence start) + (position delimiter sequence :start start :key key :test-not test-not)) + sequence start end count remove-empty-subseqs)) + ((and from-end (null test-not)) + (split-extended-sequence-from-end (lambda (sequence end) + (position delimiter sequence :end end :from-end t :key key :test test)) + sequence start end count remove-empty-subseqs)) + (t + (split-extended-sequence-from-end (lambda (sequence end) + (position delimiter sequence :end end :from-end t :key key :test-not test-not)) + sequence start end count remove-empty-subseqs)))) + +(defun split-extended-sequence-if + (predicate sequence start end from-end count remove-empty-subseqs key) + (if from-end + (split-extended-sequence-from-end (lambda (sequence end) + (position-if predicate sequence :end end :from-end t :key key)) + sequence start end count remove-empty-subseqs) + (split-extended-sequence-from-start (lambda (sequence start) + (position-if predicate sequence :start start :key key)) + sequence start end count remove-empty-subseqs))) + +(defun split-extended-sequence-if-not + (predicate sequence start end from-end count remove-empty-subseqs key) + (if from-end + (split-extended-sequence-from-end (lambda (sequence end) + (position-if-not predicate sequence :end end :from-end t :key key)) + sequence start end count remove-empty-subseqs) + (split-extended-sequence-from-start (lambda (sequence start) + (position-if-not predicate sequence :start start :key key)) + sequence start end count remove-empty-subseqs))) + +(defun split-extended-sequence-from-end (position-fn sequence start end count remove-empty-subseqs) + (declare (optimize (speed 3) (debug 0)) + (type (function (extended-sequence fixnum) (or null fixnum)) position-fn)) + (loop + :with length = (length sequence) + :with end = (or end length) + :for right := end :then left + :for left := (max (or (funcall position-fn sequence right) -1) + (1- start)) + :unless (and (= right (1+ left)) remove-empty-subseqs) + :if (and count (>= nr-elts count)) + :return (values (nreverse subseqs) right) + :else + :collect (subseq sequence (1+ left) right) into subseqs + :and :sum 1 :into nr-elts :of-type fixnum + :until (< left start) + :finally (return (values (nreverse subseqs) (1+ left))))) + +(defun split-extended-sequence-from-start (position-fn sequence start end count remove-empty-subseqs) + (declare (optimize (speed 3) (debug 0)) + (type (function (extended-sequence fixnum) (or null fixnum)) position-fn)) + (loop + :with length = (length sequence) + :with end = (or end length) + :for left := start :then (1+ right) + :for right := (min (or (funcall position-fn sequence left) length) + end) + :unless (and (= right left) remove-empty-subseqs) + :if (and count (>= nr-elts count)) + :return (values subseqs left) + :else + :collect (subseq sequence left right) :into subseqs + :and :sum 1 :into nr-elts :of-type fixnum + :until (>= right end) + :finally (return (values subseqs right)))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/list.lisp b/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/list.lisp new file mode 100644 index 0000000..7907d10 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/list.lisp @@ -0,0 +1,116 @@ +;;;; -*- Mode: Lisp; indent-tabs-mode: nil -*- + +(in-package :split-sequence) + +(declaim (inline + collect-until count-while + split-list split-list-if split-list-if-not + split-list-from-end split-list-from-start split-list-internal)) + +(declaim (ftype (function (&rest t) (values list unsigned-byte)) + split-list split-list-if split-list-if-not)) + +(declaim (ftype (function (function list unsigned-byte (or null unsigned-byte) (or null unsigned-byte) + boolean) + (values list unsigned-byte)) + split-list-from-start split-list-from-end split-list-internal)) + +(defun collect-until (predicate list end) + "Collect elements from LIST until one that satisfies PREDICATE is found. + + At most END elements will be examined. If END is null, all elements will be examined. + + Returns four values: + + * The collected items. + * The remaining items. + * The number of elements examined. + * Whether the search ended by running off the end, instead of by finding a delimiter." + (let ((examined 0) + (found nil)) + (flet ((examine (value) + (incf examined) + (setf found (funcall predicate value)))) + (loop :for (value . remaining) :on list + :until (eql examined end) + :until (examine value) + :collect value :into result + :finally (return (values result + remaining + examined + (and (not found) + (or (null end) + (= end examined))))))))) + +(defun count-while (predicate list end) + "Count the number of elements satisfying PREDICATE at the beginning of LIST. + + At most END elements will be counted. If END is null, all elements will be examined." + (if end + (loop :for value :in list + :for i :below end + :while (funcall predicate value) + :summing 1) + (loop :for value :in list + :while (funcall predicate value) + :summing 1))) + +(defun split-list-internal (predicate list start end count remove-empty-subseqs) + (let ((count count) + (done nil) + (index start) + (end (when end (- end start))) + (list (nthcdr start list))) + (flet ((should-collect-p (chunk) + (unless (and remove-empty-subseqs (null chunk)) + (when (numberp count) (decf count)) + t)) + (gather-chunk () + (multiple-value-bind (chunk remaining examined ran-off-end) + (collect-until predicate list end) + (incf index examined) + (when end (decf end examined)) + (setf list remaining + done ran-off-end) + chunk))) + (values (loop :with chunk + :until (or done (eql 0 count)) + :do (setf chunk (gather-chunk)) + :when (should-collect-p chunk) + :collect chunk) + (+ index + (if remove-empty-subseqs + (count-while predicate list end) ; chew off remaining empty seqs + 0)))))) + +(defun split-list-from-end (predicate list start end count remove-empty-subseqs) + (let ((length (length list))) + (multiple-value-bind (result index) + (split-list-internal predicate (reverse list) + (if end (- length end) 0) + (- length start) count remove-empty-subseqs) + (loop :for cons on result + :for car := (car cons) + :do (setf (car cons) (nreverse car))) + (values (nreverse result) (- length index))))) + +(defun split-list-from-start (predicate list start end count remove-empty-subseqs) + (split-list-internal predicate list start end count remove-empty-subseqs)) + +(defun split-list-if (predicate list start end from-end count remove-empty-subseqs key) + (let ((predicate (lambda (x) (funcall predicate (funcall key x))))) + (if from-end + (split-list-from-end predicate list start end count remove-empty-subseqs) + (split-list-from-start predicate list start end count remove-empty-subseqs)))) + +(defun split-list-if-not (predicate list start end from-end count remove-empty-subseqs key) + (split-list-if (complement predicate) list start end from-end count remove-empty-subseqs key)) + +(defun split-list + (delimiter list start end from-end count remove-empty-subseqs test test-not key) + (let ((predicate (if test-not + (lambda (x) (not (funcall test-not delimiter (funcall key x)))) + (lambda (x) (funcall test delimiter (funcall key x)))))) + (if from-end + (split-list-from-end predicate list start end count remove-empty-subseqs) + (split-list-from-start predicate list start end count remove-empty-subseqs)))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/original-message.txt b/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/original-message.txt new file mode 100644 index 0000000..fe4873c --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/original-message.txt @@ -0,0 +1,150 @@ +From ... +Path: supernews.google.com!sn-xit-02!sn-xit-03!supernews.com!news.tele.dk!193.190.198.17!newsfeeds.belnet.be! +news.belnet.be!skynet.be!newsfeed2.news.nl.uu.net!sun4nl!not-for-mail +From: Arthur Lemmens +Newsgroups: comp.lang.lisp +Subject: Re: Q: on hashes and counting +Date: Mon, 23 Oct 2000 00:50:02 +0200 +Organization: Kikashi Software +Lines: 129 +Message-ID: <39F36F1A.B8F19D20@simplex.nl> +References: <8sl58e$ivq$1@nnrp1.deja.com> <878zrlp1cr.fsf@orion.bln.pmsf.de> +Mime-Version: 1.0 +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: 7bit +X-Trace: porthos.nl.uu.net 972255051 2606 193.78.46.221 (22 Oct 2000 22:50:51 GMT) +X-Complaints-To: abuse@nl.uu.net +NNTP-Posting-Date: 22 Oct 2000 22:50:51 GMT +X-Mailer: Mozilla 4.5 [en] (Win98; I) +X-Accept-Language: en +Xref: supernews.google.com comp.lang.lisp:2515 + + +Pierre R. Mai wrote: + +> ;;; The following functions are based on the versions by Arthur +> ;;; Lemmens of the original code by Bernard Pfahringer posted to +> ;;; comp.lang.lisp. I only renamed and diddled them a bit. +> +> (defun partition + +[snip] + +> ;; DO: Find a more efficient way to take care of :from-end T. +> (when from-end +> (setf seq (reverse seq)) +> (psetf start (- len end) +> end (- len start))) + +I've written a different version now for dealing with :FROM-END T. +It doesn't call REVERSE anymore, which makes it more efficient. +Also, I prefer the new semantics. Stuff like + (split #\space "one two three " :from-end t) +now returns + ("three" "two" "one") +which I find a lot more useful than + ("eerht" "owt" "eno") +If you prefer the latter, it's easy enough to use + (split #\space (reverse "one two three ")) + + +Here it is (feel free to use this code any way you like): + +(defun SPLIT (delimiter seq + &key (maximum nil) + (keep-empty-subseqs nil) + (from-end nil) + (start 0) + (end nil) + (test nil test-supplied) + (test-not nil test-not-supplied) + (key nil key-supplied)) + +"Return a list of subsequences in delimited by . +If :keep-empty-subseqs is true, empty subsequences will be included +in the result; otherwise they will be discarded. +If :maximum is supplied, the result will contain no more than :maximum +(possibly empty) subsequences. The second result value contains the +unsplit rest of the sequence. +All other keywords work analogously to those for CL:POSITION." + +;; DO: Make ":keep-delimiters t" include the delimiters in the result (?). + + (let ((len (length seq)) + (other-keys (nconc (when test-supplied + (list :test test)) + (when test-not-supplied + (list :test-not test-not)) + (when key-supplied + (list :key key))))) + +(unless end (setq end len)) +(if from-end + (loop for right = end then left + for left = (max (or (apply #'position delimiter seq + :end right + :from-end t + other-keys) + -1) + (1- start)) + unless (and (= right (1+ left) ) + (not keep-empty-subseqs)) ; empty subseq we don't want + if (and maximum (>= nr-elts maximum)) + ;; We can't take any more. Return now. + return (values subseqs (subseq seq start right)) + else + collect (subseq seq (1+ left) right) into subseqs + and sum 1 into nr-elts + until (<= left start) + finally return (values subseqs (subseq seq start (1+ left)))) + (loop for left = start then (+ right 1) + for right = (min (or (apply #'position delimiter seq + :start left + other-keys) + len) + end) + unless (and (= right left) + (not keep-empty-subseqs)) ; empty subseq we don't want + if (and maximum (>= nr-elts maximum)) + ;; We can't take any more. Return now. + return (values subseqs (subseq seq left end)) + else + collect (subseq seq left right) into subseqs + and sum 1 into nr-elts + until (= right end) + finally return (values subseqs (subseq seq right end)))))) + + + +Here are some examples of how you can use this: + + +CL-USER 2 > (split #\space "word1 word2 word3") +("word1" "word2" "word3") +"" + +CL-USER 3 > (split #\space "word1 word2 word3" :from-end t) +("word3" "word2" "word1") +"" + +CL-USER 4 > (split nil '(a b nil c d e nil nil nil nil f) :maximum 2) +((A B) (C D E)) +(F) + +CL-USER 5 > (split #\space "Nospaceshere.") +("Nospaceshere.") +"" + +CL-USER 6 > (split #\; "12;13;;14" :keep-empty-subseqs t) + +("12" "13" "" "14") +"" + +CL-USER 7 > (split #\; "12;13;;14" :keep-empty-subseqs t :from-end t) + +("14" "" "13" "12") +"" + +CL-USER 8 > (split #\space "Nospaceshere. ") +("Nospaceshere.") +"" diff --git a/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/package.lisp b/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/package.lisp new file mode 100644 index 0000000..71f5001 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/package.lisp @@ -0,0 +1,37 @@ +;;;; -*- Mode: Lisp; indent-tabs-mode: nil -*- +;;; +;;; SPLIT-SEQUENCE +;;; +;;; This code was based on Arthur Lemmens' in +;;; ; +;;; +;;; changes include: +;;; +;;; * altering the behaviour of the :from-end keyword argument to +;;; return the subsequences in original order, for consistency with +;;; CL:REMOVE, CL:SUBSTITUTE et al. (:from-end being non-NIL only +;;; affects the answer if :count is less than the number of +;;; subsequences, by analogy with the above-referenced functions). +;;; +;;; * changing the :maximum keyword argument to :count, by analogy +;;; with CL:REMOVE, CL:SUBSTITUTE, and so on. +;;; +;;; * naming the function SPLIT-SEQUENCE rather than PARTITION rather +;;; than SPLIT. +;;; +;;; * adding SPLIT-SEQUENCE-IF and SPLIT-SEQUENCE-IF-NOT. +;;; +;;; * The second return value is now an index rather than a copy of a +;;; portion of the sequence; this index is the `right' one to feed to +;;; CL:SUBSEQ for continued processing. + +;;; There's a certain amount of code duplication in the vector and +;;; extended sequence modules, which is kept to illustrate the +;;; relationship between the SPLIT-SEQUENCE functions and the +;;; CL:POSITION functions. + +(defpackage #:split-sequence + (:use #:common-lisp) + (:export #:split-sequence + #:split-sequence-if + #:split-sequence-if-not)) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/split-sequence.asd b/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/split-sequence.asd new file mode 100644 index 0000000..868d840 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/split-sequence.asd @@ -0,0 +1,28 @@ +;;; -*- Lisp -*- + +(defsystem :split-sequence + :author "Arthur Lemmens " + :maintainer "Sharp Lispers " + :description "Splits a sequence into a list of subsequences + delimited by objects satisfying a test." + :license "MIT" + :version (:read-file-form "version.sexp") + :components ((:static-file "version.sexp") + (:file "package") + (:file "vector") + (:file "list") + (:file "extended-sequence" :if-feature (:or :sbcl :abcl)) + (:file "api") + (:file "documentation"))) + +(defsystem :split-sequence/tests + :author "Arthur Lemmens " + :maintainer "Sharp Lispers " + :description "Split-Sequence test suite" + :license "MIT" + :depends-on (:split-sequence :fiveam) + :components ((:file "tests"))) + +(defmethod perform ((o test-op) (c (eql (find-system :split-sequence)))) + (load-system :split-sequence/tests) + (symbol-call :5am :run! :split-sequence)) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/tests.lisp b/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/tests.lisp new file mode 100644 index 0000000..691c546 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/tests.lisp @@ -0,0 +1,268 @@ +;;;; -*- Mode: Lisp; indent-tabs-mode: nil -*- + +(defpackage :split-sequence/tests + (:use :common-lisp :split-sequence :fiveam)) + +(in-package :split-sequence/tests) + +(in-suite* :split-sequence) + +;;; UNIT TESTS + +(defmacro define-test (name (&key input output index) &body forms) + ;; This macro automatically generates test code for testing vector and list input. + ;; Vector input and output is automatically coerced into list form for the list tests. + ;; (DEFINE-TEST FOO ...) generates FIVEAM tests FOO.VECTOR and FOO.LIST. + (check-type name symbol) + (check-type input (cons symbol (cons vector null))) + (check-type output (cons symbol (cons list null))) + (check-type index (cons symbol (cons unsigned-byte null))) + (let* ((input-symbol (first input)) (vector-input (second input)) + (output-symbol (first output)) (vector-output (second output)) + (index-symbol (first index)) (index-value (second index)) + (list-input (coerce vector-input 'list)) + (list-output (mapcar (lambda (x) (coerce x 'list)) vector-output)) + (vector-name (intern (concatenate 'string (symbol-name name) ".VECTOR"))) + (list-name (intern (concatenate 'string (symbol-name name) ".LIST")))) + `(progn + (test (,vector-name :compile-at :definition-time) + (let ((,input-symbol ',vector-input) + (,output-symbol ',vector-output) + (,index-symbol ,index-value)) + ,@forms)) + (test (,list-name :compile-at :definition-time) + (let ((,input-symbol ',list-input) + (,output-symbol ',list-output) + (,index-symbol ,index-value)) + ,@forms))))) + +(define-test split-sequence.0 (:input (input "") + :output (output ("")) + :index (index 0)) + (is (equalp (split-sequence #\; input) + (values output index)))) + +(define-test split-sequence.1 (:input (input "a;;b;c") + :output (output ("a" "" "b" "c")) + :index (index 6)) + (is (equalp (split-sequence #\; input) + (values output index)))) + +(define-test split-sequence.2 (:input (input "a;;b;c") + :output (output ("a" "" "b" "c")) + :index (index 0)) + (is (equalp (split-sequence #\; input :from-end t) + (values output index)))) + +(define-test split-sequence.3 (:input (input "a;;b;c") + :output (output ("c")) + :index (index 4)) + (is (equalp (split-sequence #\; input :from-end t :count 1) + (values output index)))) + +(define-test split-sequence.4 (:input (input "a;;b;c") + :output (output ("a" "b" "c")) + :index (index 6)) + (is (equalp (split-sequence #\; input :remove-empty-subseqs t) + (values output index)))) + +(define-test split-sequence.5 (:input (input ";oo;bar;ba;") + :output (output ("oo" "bar" "b")) + :index (index 9)) + (is (equalp (split-sequence #\; input :start 1 :end 9) + (values output index)))) + +(define-test split-sequence.6 (:input (input "abracadabra") + :output (output ("" "br" "c" "d" "br" "")) + :index (index 11)) + (is (equalp (split-sequence #\A input :key #'char-upcase) + (values output index)))) + +(define-test split-sequence.7 (:input (input "abracadabra") + :output (output ("r" "c" "d")) + :index (index 7)) + (is (equalp (split-sequence #\A input :key #'char-upcase :start 2 :end 7) + (values output index)))) + +(define-test split-sequence.8 (:input (input "abracadabra") + :output (output ("r" "c" "d")) + :index (index 2)) + (is (equalp (split-sequence #\A input :key #'char-upcase :start 2 :end 7 :from-end t) + (values output index)))) + +(define-test split-sequence.9 (:input (input #(1 2 0)) + :output (output (#(1 2) #())) + :index (index 0)) + (is (equalp (split-sequence 0 input :from-end t) + (values output index)))) + +(define-test split-sequence.10 (:input (input #(2 0 0 2 3 2 0 1 0 3)) + :output (output ()) + :index (index 8)) + (is (equalp (split-sequence 0 input :start 8 :end 9 :from-end t :count 0 :remove-empty-subseqs t) + (values output index)))) + +(define-test split-sequence.11 (:input (input #(0 1 3 0 3 1 2 2 1 0)) + :output (output ()) + :index (index 0)) + (is (equalp (split-sequence 0 input :start 0 :end 0 :remove-empty-subseqs t) + (values output index)))) + +(define-test split-sequence.12 (:input (input #(3 0 0 0 3 3 0 3 1 0)) + :output (output ()) + :index (index 10)) + (is (equalp (split-sequence 0 input :start 9 :end 10 :from-end t :count 0) + (values output index)))) + +(define-test split-sequence.13 (:input (input #(3 3 3 3 0 2 0 0 1 2)) + :output (output (#(1))) + :index (index 6)) + (is (equalp (split-sequence 0 input :start 6 :end 9 :from-end t :count 1 :remove-empty-subseqs t) + (values output index)))) + +(define-test split-sequence.14 (:input (input #(1 0)) + :output (output (#(1))) + :index (index 0)) + (is (equalp (split-sequence 0 input :from-end t :count 1 :remove-empty-subseqs t) + (values output index)))) + +(define-test split-sequence.15 (:input (input #(0 0)) + :output (output ()) + :index (index 1)) + (is (equalp (split-sequence 0 input :start 0 :end 1 :count 0 :remove-empty-subseqs t) + (values output index)))) + +(define-test split-sequence.16 (:input (input "a;;b;c") + :output (output ("" ";;" ";" "")) + :index (index 6)) + (is (equalp (split-sequence #\; input :test-not #'eql) + (values output index)))) + +(define-test split-sequence.17 (:input (input "a;;b;c") + :output (output ("" ";;" ";" "")) + :index (index 0)) + (is (equalp (split-sequence #\; input :from-end t :test-not #'eql) + (values output index)))) + +(define-test split-sequence.18 (:input (input #(1 0 2 0 3 0 4)) + :output (output (#(1) #(2) #(3))) + :index (index 6)) + (is (equalp (split-sequence 0 input :count 3) + (values output index)))) + +(define-test split-sequence-if.1 (:input (input "abracadabra") + :output (output ("" "" "r" "c" "d" "" "r" "")) + :index (index 11)) + (is (equalp (split-sequence-if (lambda (x) (member x '(#\a #\b))) input) + (values output index)))) + +(define-test split-sequence-if.2 (:input (input "123456") + :output (output ("1" "3" "5")) + :index (index 6)) + (is (equalp (split-sequence-if (lambda (x) (evenp (parse-integer (string x)))) input + :remove-empty-subseqs t) + (values output index)))) + +(define-test split-sequence-if.3 (:input (input "123456") + :output (output ("1" "3" "5" "")) + :index (index 6)) + (is (equalp (split-sequence-if (lambda (x) (evenp (parse-integer (string x)))) input) + (values output index)))) + +(define-test split-sequence-if-not.1 (:input (input "abracadabra") + :output (output ("ab" "a" "a" "ab" "a")) + :index (index 11)) + (is (equalp (split-sequence-if-not (lambda (x) (member x '(#\a #\b))) input) + (values output index)))) + +(test split-sequence.start-end-error + (signals error (split-sequence 0 #(0 1 2 3) :start nil)) + (signals error (split-sequence 0 #(0 1 2 3) :end '#:end)) + (signals error (split-sequence 0 #(0 1 2 3) :start 0 :end 8)) + (signals error (split-sequence 0 #(0 1 2 3) :start 2 :end 0))) + +(test split-sequence.test-provided + ;; Neither provided + (is (equal '((1) (3)) (split-sequence 2 '(1 2 3)))) + ;; Either provided + (is (equal '((1) (3)) (split-sequence 2 '(1 2 3) :test #'eql))) + (is (equal '(() (2) ()) (split-sequence 2 '(1 2 3) :test-not #'eql))) + (signals type-error (split-sequence 2 '(1 2 3) :test nil)) + (signals type-error (split-sequence 2 '(1 2 3) :test-not nil)) + ;; Both provided + (signals program-error (split-sequence 2 '(1 2 3) :test #'eql :test-not nil)) + (signals program-error (split-sequence 2 '(1 2 3) :test nil :test-not #'eql)) + (signals program-error (split-sequence 2 '(1 2 3) :test #'eql :test-not #'eql)) + (signals program-error (split-sequence 2 '(1 2 3) :test nil :test-not nil))) + +;;; FUZZ TEST + +(test split-sequence.fuzz + (fuzz :verbose nil :fiveamp t)) + +(defun fuzz (&key (max-length 100) (repetitions 1000000) (verbose t) (print-every 10000) (fiveamp nil)) + (flet ((random-vector (n) + (let ((vector (make-array n :element-type '(unsigned-byte 2)))) + (dotimes (i n) (setf (aref vector i) (random 4))) + vector)) + (random-boolean () (if (= 0 (random 2)) t nil)) + (fuzz-failure (vector start end from-end count remove-empty-subseqs + expected-splits expected-index actual-splits actual-index) + (format nil "Fuzz failure: +\(MULTIPLE-VALUE-CALL #'VALUES + (SPLIT-SEQUENCE 0 ~S + :START ~S :END ~S :FROM-END ~S :COUNT ~S :REMOVE-EMPTY-SUBSEQS ~S) + (SPLIT-SEQUENCE 0 (COERCE ~S 'LIST) + :START ~S :END ~S :FROM-END ~S :COUNT ~S :REMOVE-EMPTY-SUBSEQS ~S)) +~S~%~S~%~S~%~S" + vector start end from-end count remove-empty-subseqs + vector start end from-end count remove-empty-subseqs + expected-splits expected-index actual-splits actual-index))) + (let ((failure-string nil) + (predicate (lambda (x) (= x 0))) + (predicate-not (lambda (x) (/= x 0)))) + (dotimes (i repetitions) + (when (and verbose (= 0 (mod (1+ i) print-every))) + (format t "Fuzz: Pass ~D passed.~%" (1+ i))) + (let* ((length (1+ (random max-length))) + (vector (random-vector length)) + (list (coerce vector 'list)) + (remove-empty-subseqs (random-boolean)) + (start 0) end from-end count) + (case (random 5) + (0) + (1 (setf start (random length))) + (2 (setf start (random length) + end (+ start (random (1+ (- length start)))))) + (3 (setf start (random length) + end (+ start (random (1+ (- length start)))) + from-end t)) + (4 (setf start (random length) + end (+ start (random (1+ (- length start)))) + from-end t + count (random (1+ (- end start)))))) + (let ((args (list :start start :end end :from-end from-end :count count + :remove-empty-subseqs remove-empty-subseqs))) + (multiple-value-bind (expected-splits expected-index) + (case (random 3) + (0 (apply #'split-sequence 0 vector args)) + (1 (apply #'split-sequence-if predicate vector args)) + (2 (apply #'split-sequence-if-not predicate-not vector args))) + (multiple-value-bind (actual-splits actual-index) + (case (random 3) + (0 (apply #'split-sequence 0 list args)) + (1 (apply #'split-sequence-if predicate list args)) + (2 (apply #'split-sequence-if-not predicate-not list args))) + (let* ((expected-splits (mapcar (lambda (x) (coerce x 'list)) expected-splits)) + (result (and (equal actual-splits expected-splits) + (= expected-index actual-index)))) + (unless result + (let ((string (fuzz-failure + vector start end from-end count remove-empty-subseqs + expected-splits expected-index actual-splits actual-index))) + (cond (fiveamp + (setf failure-string string) + (return)) + (t (assert result () string))))))))))) + (when fiveamp + (is (not failure-string) failure-string))))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/vector.lisp b/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/vector.lisp new file mode 100644 index 0000000..247a337 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/vector.lisp @@ -0,0 +1,94 @@ +;;;; -*- Mode: Lisp; indent-tabs-mode: nil -*- + +(in-package :split-sequence) + +(declaim (inline + split-vector split-vector-if split-vector-if-not + split-vector-from-end split-vector-from-start)) + +(deftype array-index (&optional (length array-dimension-limit)) + `(integer 0 (,length))) + +(declaim (ftype (function (&rest t) (values list unsigned-byte)) + split-vector split-vector-if split-vector-if-not)) + +(declaim (ftype (function (function vector array-index + (or null array-index) (or null array-index) boolean) + (values list unsigned-byte)) + split-vector-from-start split-vector-from-end)) + +(defun split-vector + (delimiter vector start end from-end count remove-empty-subseqs test test-not key) + (cond + ((and (not from-end) (null test-not)) + (split-vector-from-start (lambda (vector start) + (position delimiter vector :start start :key key :test test)) + vector start end count remove-empty-subseqs)) + ((and (not from-end) test-not) + (split-vector-from-start (lambda (vector start) + (position delimiter vector :start start :key key :test-not test-not)) + vector start end count remove-empty-subseqs)) + ((and from-end (null test-not)) + (split-vector-from-end (lambda (vector end) + (position delimiter vector :end end :from-end t :key key :test test)) + vector start end count remove-empty-subseqs)) + (t + (split-vector-from-end (lambda (vector end) + (position delimiter vector :end end :from-end t :key key :test-not test-not)) + vector start end count remove-empty-subseqs)))) + +(defun split-vector-if + (predicate vector start end from-end count remove-empty-subseqs key) + (if from-end + (split-vector-from-end (lambda (vector end) + (position-if predicate vector :end end :from-end t :key key)) + vector start end count remove-empty-subseqs) + (split-vector-from-start (lambda (vector start) + (position-if predicate vector :start start :key key)) + vector start end count remove-empty-subseqs))) + +(defun split-vector-if-not + (predicate vector start end from-end count remove-empty-subseqs key) + (if from-end + (split-vector-from-end (lambda (vector end) + (position-if-not predicate vector :end end :from-end t :key key)) + vector start end count remove-empty-subseqs) + (split-vector-from-start (lambda (vector start) + (position-if-not predicate vector :start start :key key)) + vector start end count remove-empty-subseqs))) + +(defun split-vector-from-end (position-fn vector start end count remove-empty-subseqs) + (declare (optimize (speed 3) (debug 0)) + (type (function (vector fixnum) (or null fixnum)) position-fn)) + (loop + :with end = (or end (length vector)) + :for right := end :then left + :for left := (max (or (funcall position-fn vector right) -1) + (1- start)) + :unless (and (= right (1+ left)) remove-empty-subseqs) + :if (and count (>= nr-elts count)) + :return (values (nreverse subseqs) right) + :else + :collect (subseq vector (1+ left) right) into subseqs + :and :sum 1 :into nr-elts :of-type fixnum + :until (< left start) + :finally (return (values (nreverse subseqs) (1+ left))))) + +(defun split-vector-from-start (position-fn vector start end count remove-empty-subseqs) + (declare (optimize (speed 3) (debug 0)) + (type vector vector) + (type (function (vector fixnum) (or null fixnum)) position-fn)) + (let ((length (length vector))) + (loop + :with end = (or end (length vector)) + :for left := start :then (1+ right) + :for right := (min (or (funcall position-fn vector left) length) + end) + :unless (and (= right left) remove-empty-subseqs) + :if (and count (>= nr-elts count)) + :return (values subseqs left) + :else + :collect (subseq vector left right) :into subseqs + :and :sum 1 :into nr-elts :of-type fixnum + :until (>= right end) + :finally (return (values subseqs right))))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/version.sexp b/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/version.sexp new file mode 100644 index 0000000..925cb56 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/split-sequence-v2.0.0/version.sexp @@ -0,0 +1,2 @@ +;; -*- lisp -*- +"2.0.0" diff --git a/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/COPYING b/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/COPYING new file mode 100644 index 0000000..fcb4fe7 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/COPYING @@ -0,0 +1,22 @@ + Copyright (c) 2005 David Lichteblau + Copyright (c) 2013 Anton Vodonosov + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. diff --git a/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/Makefile b/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/Makefile new file mode 100644 index 0000000..f6d297c --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/Makefile @@ -0,0 +1,3 @@ +.PHONY: clean +clean: + rm -f *.fasl *.x86f *.fas *.ufsl *.lib *.pfsl diff --git a/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/README b/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/README new file mode 100644 index 0000000..4e49ce1 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/README @@ -0,0 +1,40 @@ +trivial-gray-streams +==================== + +Gray streams is an interface proposed for inclusion with ANSI CL +by David N. Gray in Issue STREAM-DEFINITION-BY-USER +(http://www.nhplace.com/kent/CL/Issues/stream-definition-by-user.html). +The proposal did not make it into ANSI CL, but most popular +CL implementations implement this facility anyway. + +This system provides an extremely thin compatibility layer for gray +streams. + +How to use it +============= + +Use the package TRIVIAL-GRAY-STREAMS to refer Gray stream +classes to inherit from, generic functions to implement. + +Extensions +========== + +The Gray proposal was made before the ANCI CL standard was finalized, +and was based on the Common Lisp The Language book. + +The book does not have cl:file-position, cl:read-sequence, cl:write-sequence +functions. That's why (we think) the Gray proposal does not specify +their counterparts: stream-file-position, stream-read-sequence, stream-write-sequence. + +trivial-gray-streams supports these functions: + +Generic function STREAM-READ-SEQUENCE (stream sequence start end &key) +Generic function STREAM-WRITE-SEQUENCE (stream sequence start end &key) + + Notice that we use two required arguments and allow additional + keyword arguments. Your methods on these function should have + compliant lambda lists: + (stream sequence start end &key) + +Generic function STREAM-FILE-POSITION (stream) => file position +Generic function (SETF STREAM-FILE-POSITION) (position-spec stream) => successp diff --git a/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/build.xcvb b/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/build.xcvb new file mode 100644 index 0000000..abd5622 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/build.xcvb @@ -0,0 +1,7 @@ +#+xcvb +(module + (:fullname "trivial-gray-streams" + :depends-on + ("package" + "streams") + :supersedes-asdf ("trivial-gray-streams"))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/package.lisp b/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/package.lisp new file mode 100644 index 0000000..c5fac85 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/package.lisp @@ -0,0 +1,77 @@ +#+xcvb (module ()) + +(in-package :cl-user) + +#+:abcl +(eval-when (:compile-toplevel :load-toplevel :execute) + (require :gray-streams)) + +#+(or cmu genera) +(eval-when (:compile-toplevel :load-toplevel :execute) + (require :gray-streams)) + +#+allegro +(eval-when (:compile-toplevel :load-toplevel :execute) + (unless (fboundp 'excl:stream-write-string) + (require "streamc.fasl"))) + +#+(or ecl clasp) +(eval-when (:compile-toplevel :load-toplevel :execute) + (gray::redefine-cl-functions)) + +(macrolet + ((frob () + (let ((gray-class-symbols + '(#:fundamental-stream + #:fundamental-input-stream #:fundamental-output-stream + #:fundamental-character-stream #:fundamental-binary-stream + #:fundamental-character-input-stream #:fundamental-character-output-stream + #:fundamental-binary-input-stream #:fundamental-binary-output-stream)) + (gray-function-symbols + '(#:stream-read-char + #:stream-unread-char #:stream-read-char-no-hang + #:stream-peek-char #:stream-listen #:stream-read-line + #:stream-clear-input #:stream-write-char #:stream-line-column + #:stream-start-line-p #:stream-write-string #:stream-terpri + #:stream-fresh-line #:stream-finish-output #:stream-force-output + #:stream-clear-output #:stream-advance-to-column + #:stream-read-byte #:stream-write-byte))) + `(progn + + (defpackage impl-specific-gray + (:use :cl) + (:import-from + #+sbcl :sb-gray + #+allegro :excl + #+cmu :ext + #+(or clisp ecl mocl clasp) :gray + #+openmcl :ccl + #+lispworks :stream + #+(or abcl genera) :gray-streams + #-(or sbcl allegro cmu clisp openmcl lispworks ecl clasp abcl mocl genera) ... + ,@gray-class-symbols + ,@gray-function-symbols) + (:export + ,@gray-class-symbols + ,@gray-function-symbols)) + + (defpackage :trivial-gray-streams + (:use :cl) + (:import-from #:impl-specific-gray + ;; We import and re-export only + ;; function symbols; + ;; But we define our own classes + ;; mirroring the gray class hierarchy + ;; of the lisp implementation (this + ;; is necessary to define our methods + ;; for particular generic functions) + ,@gray-function-symbols) + (:export ,@gray-class-symbols + ,@gray-function-symbols + ;; extension functions + #:stream-read-sequence + #:stream-write-sequence + #:stream-file-position + ;; deprecated + #:trivial-gray-stream-mixin)))))) + (frob)) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/streams.lisp b/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/streams.lisp new file mode 100644 index 0000000..c4101d0 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/streams.lisp @@ -0,0 +1,292 @@ +#+xcvb (module (:depends-on ("package"))) + +(in-package :trivial-gray-streams) + +(defclass fundamental-stream (impl-specific-gray:fundamental-stream) ()) +(defclass fundamental-input-stream + (fundamental-stream impl-specific-gray:fundamental-input-stream) ()) +(defclass fundamental-output-stream + (fundamental-stream impl-specific-gray:fundamental-output-stream) ()) +(defclass fundamental-character-stream + (fundamental-stream impl-specific-gray:fundamental-character-stream) ()) +(defclass fundamental-binary-stream + (fundamental-stream impl-specific-gray:fundamental-binary-stream) ()) +(defclass fundamental-character-input-stream + (fundamental-input-stream fundamental-character-stream + impl-specific-gray:fundamental-character-input-stream) ()) +(defclass fundamental-character-output-stream + (fundamental-output-stream fundamental-character-stream + impl-specific-gray:fundamental-character-output-stream) ()) +(defclass fundamental-binary-input-stream + (fundamental-input-stream fundamental-binary-stream + impl-specific-gray:fundamental-binary-input-stream) ()) +(defclass fundamental-binary-output-stream + (fundamental-output-stream fundamental-binary-stream + impl-specific-gray:fundamental-binary-output-stream) ()) + +(defgeneric stream-read-sequence + (stream sequence start end &key &allow-other-keys)) +(defgeneric stream-write-sequence + (stream sequence start end &key &allow-other-keys)) + +(defgeneric stream-file-position (stream)) +(defgeneric (setf stream-file-position) (newval stream)) + +;;; Default methods for stream-read/write-sequence. +;;; +;;; It would be nice to implement default methods +;;; in trivial gray streams, maybe borrowing the code +;;; from some of CL implementations. But now, for +;;; simplicity we will fallback to default implementation +;;; of the implementation-specific analogue function which calls us. + +(defmethod stream-read-sequence ((stream fundamental-input-stream) seq start end &key) + (declare (ignore seq start end)) + 'fallback) + +(defmethod stream-write-sequence ((stream fundamental-output-stream) seq start end &key) + (declare (ignore seq start end)) + 'fallback) + +(defmacro or-fallback (&body body) + `(let ((result ,@body)) + (if (eq result (quote fallback)) + (call-next-method) + result))) + +;; Implementations should provide this default method, I believe, but +;; at least sbcl and allegro don't. +(defmethod stream-terpri ((stream fundamental-output-stream)) + (write-char #\newline stream)) + +;; stream-file-position could be specialized to +;; fundamental-stream, but to support backward +;; compatibility with flexi-streams, we specialize +;; it on T. The reason: flexi-streams calls stream-file-position +;; for non-gray stream: +;; https://github.com/edicl/flexi-streams/issues/4 +(defmethod stream-file-position ((stream t)) + nil) + +(defmethod (setf stream-file-position) (newval (stream t)) + (declare (ignore newval)) + nil) + +#+abcl +(progn + (defmethod gray-streams:stream-read-sequence + ((s fundamental-input-stream) seq &optional start end) + (or-fallback (stream-read-sequence s seq (or start 0) (or end (length seq))))) + + (defmethod gray-streams:stream-write-sequence + ((s fundamental-output-stream) seq &optional start end) + (or-fallback (stream-write-sequence s seq (or start 0) (or end (length seq))))) + + (defmethod gray-streams:stream-write-string + ((stream xp::xp-structure) string &optional (start 0) (end (length string))) + (xp::write-string+ string stream start end)) + + #+#.(cl:if (cl:and (cl:find-package :gray-streams) + (cl:find-symbol "STREAM-FILE-POSITION" :gray-streams)) + '(:and) + '(:or)) + (defmethod gray-streams:stream-file-position + ((s fundamental-stream) &optional position) + (if position + (setf (stream-file-position s) position) + (stream-file-position s)))) + +#+allegro +(progn + (defmethod excl:stream-read-sequence + ((s fundamental-input-stream) seq &optional start end) + (or-fallback (stream-read-sequence s seq (or start 0) (or end (length seq))))) + + (defmethod excl:stream-write-sequence + ((s fundamental-output-stream) seq &optional start end) + (or-fallback (stream-write-sequence s seq (or start 0) (or end (length seq))))) + + (defmethod excl::stream-file-position + ((stream fundamental-stream) &optional position) + (if position + (setf (stream-file-position stream) position) + (stream-file-position stream)))) + +;; Untill 2014-08-09 CMUCL did not have stream-file-position: +;; http://trac.common-lisp.net/cmucl/ticket/100 +#+cmu +(eval-when (:compile-toplevel :load-toplevel :execute) + (when (find-symbol (string '#:stream-file-position) '#:ext) + (pushnew :cmu-has-stream-file-position *features*))) + +#+cmu +(progn + (defmethod ext:stream-read-sequence + ((s fundamental-input-stream) seq &optional start end) + (or-fallback (stream-read-sequence s seq (or start 0) (or end (length seq))))) + (defmethod ext:stream-write-sequence + ((s fundamental-output-stream) seq &optional start end) + (or-fallback (stream-write-sequence s seq (or start 0) (or end (length seq))))) + + #+cmu-has-stream-file-position + (defmethod ext:stream-file-position ((stream fundamental-stream)) + (stream-file-position stream)) + + #+cmu-has-stream-file-position + (defmethod (setf ext:stream-file-position) (position (stream fundamental-stream)) + (setf (stream-file-position stream) position))) + +#+lispworks +(progn + (defmethod stream:stream-read-sequence + ((s fundamental-input-stream) seq start end) + (or-fallback (stream-read-sequence s seq start end))) + (defmethod stream:stream-write-sequence + ((s fundamental-output-stream) seq start end) + (or-fallback (stream-write-sequence s seq start end))) + + (defmethod stream:stream-file-position ((stream fundamental-stream)) + (stream-file-position stream)) + (defmethod (setf stream:stream-file-position) + (newval (stream fundamental-stream)) + (setf (stream-file-position stream) newval))) + +#+openmcl +(progn + (defmethod ccl:stream-read-vector + ((s fundamental-input-stream) seq start end) + (or-fallback (stream-read-sequence s seq start end))) + (defmethod ccl:stream-write-vector + ((s fundamental-output-stream) seq start end) + (or-fallback (stream-write-sequence s seq start end))) + + (defmethod ccl:stream-read-list ((s fundamental-input-stream) list count) + (or-fallback (stream-read-sequence s list 0 count))) + (defmethod ccl:stream-write-list ((s fundamental-output-stream) list count) + (or-fallback (stream-write-sequence s list 0 count))) + + (defmethod ccl::stream-position ((stream fundamental-stream) &optional new-position) + (if new-position + (setf (stream-file-position stream) new-position) + (stream-file-position stream)))) + +;; up to version 2.43 there were no +;; stream-read-sequence, stream-write-sequence +;; functions in CLISP +#+clisp +(eval-when (:compile-toplevel :load-toplevel :execute) + (when (find-symbol (string '#:stream-read-sequence) '#:gray) + (pushnew :clisp-has-stream-read/write-sequence *features*))) + +#+clisp +(progn + + #+clisp-has-stream-read/write-sequence + (defmethod gray:stream-read-sequence + (seq (s fundamental-input-stream) &key start end) + (or-fallback (stream-read-sequence s seq (or start 0) (or end (length seq))))) + + #+clisp-has-stream-read/write-sequence + (defmethod gray:stream-write-sequence + (seq (s fundamental-output-stream) &key start end) + (or-fallback (stream-write-sequence s seq (or start 0) (or end (length seq))))) + + ;;; for old CLISP + (defmethod gray:stream-read-byte-sequence + ((s fundamental-input-stream) + seq + &optional start end no-hang interactive) + (when no-hang + (error "this stream does not support the NO-HANG argument")) + (when interactive + (error "this stream does not support the INTERACTIVE argument")) + (or-fallback (stream-read-sequence s seq start end))) + + (defmethod gray:stream-write-byte-sequence + ((s fundamental-output-stream) + seq + &optional start end no-hang interactive) + (when no-hang + (error "this stream does not support the NO-HANG argument")) + (when interactive + (error "this stream does not support the INTERACTIVE argument")) + (or-fallback (stream-write-sequence s seq start end))) + + (defmethod gray:stream-read-char-sequence + ((s fundamental-input-stream) seq &optional start end) + (or-fallback (stream-read-sequence s seq start end))) + + (defmethod gray:stream-write-char-sequence + ((s fundamental-output-stream) seq &optional start end) + (or-fallback (stream-write-sequence s seq start end))) + + ;;; end of old CLISP read/write-sequence support + + (defmethod gray:stream-position ((stream fundamental-stream) position) + (if position + (setf (stream-file-position stream) position) + (stream-file-position stream)))) + +#+sbcl +(progn + (defmethod sb-gray:stream-read-sequence + ((s fundamental-input-stream) seq &optional start end) + (or-fallback (stream-read-sequence s seq (or start 0) (or end (length seq))))) + (defmethod sb-gray:stream-write-sequence + ((s fundamental-output-stream) seq &optional start end) + (or-fallback (stream-write-sequence s seq (or start 0) (or end (length seq))))) + (defmethod sb-gray:stream-file-position + ((stream fundamental-stream) &optional position) + (if position + (setf (stream-file-position stream) position) + (stream-file-position stream))) + ;; SBCL extension: + (defmethod sb-gray:stream-line-length ((stream fundamental-stream)) + 80)) + +#+(or ecl clasp) +(progn + (defmethod gray::stream-file-position + ((stream fundamental-stream) &optional position) + (if position + (setf (stream-file-position stream) position) + (stream-file-position stream))) + (defmethod gray:stream-read-sequence + ((s fundamental-input-stream) seq &optional start end) + (or-fallback (stream-read-sequence s seq (or start 0) (or end (length seq))))) + (defmethod gray:stream-write-sequence + ((s fundamental-output-stream) seq &optional start end) + (or-fallback (stream-write-sequence s seq (or start 0) (or end (length seq)))))) + +#+mocl +(progn + (defmethod gray:stream-read-sequence + ((s fundamental-input-stream) seq &optional start end) + (or-fallback (stream-read-sequence s seq (or start 0) (or end (length seq))))) + (defmethod gray:stream-write-sequence + ((s fundamental-output-stream) seq &optional start end) + (or-fallback (stream-write-sequence s seq (or start 0) (or end (length seq))))) + (defmethod gray:stream-file-position + ((stream fundamental-stream) &optional position) + (if position + (setf (stream-file-position stream) position) + (stream-file-position stream)))) + +#+genera +(progn + (defmethod gray-streams:stream-read-sequence + ((s fundamental-input-stream) seq &optional start end) + (or-fallback (stream-read-sequence s seq (or start 0) (or end (length seq))))) + (defmethod gray-streams:stream-write-sequence + ((s fundamental-output-stream) seq &optional start end) + (or-fallback (stream-write-sequence s seq (or start 0) (or end (length seq))))) + (defmethod gray-streams:stream-file-position + ((stream fundamental-stream)) + (stream-file-position stream)) + (defmethod (setf gray-streams:stream-file-position) + (position (stream fundamental-stream)) + (setf (stream-file-position stream) position))) + +;; deprecated +(defclass trivial-gray-stream-mixin () ()) + diff --git a/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/test/package.lisp b/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/test/package.lisp new file mode 100644 index 0000000..e836637 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/test/package.lisp @@ -0,0 +1,6 @@ +(defpackage trivial-gray-streams-test + (:use :cl #:trivial-gray-streams) + (:shadow #:method) + (:export #:run-tests + #:failed-test-names)) + diff --git a/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/test/run-on-many-lisps.lisp b/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/test/run-on-many-lisps.lisp new file mode 100644 index 0000000..9a2a9a3 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/test/run-on-many-lisps.lisp @@ -0,0 +1,66 @@ +(ql:quickload :trivial-gray-streams) +(ql:quickload :test-grid-agent) +(ql:quickload :cl-fad) +(in-package :cl-user) + +(defparameter *abcl* (make-instance 'lisp-exe:abcl + :java-exe-path "C:\\Program Files\\Java\\jdk1.6.0_26\\bin\\java" + :abcl-jar-path "C:\\Users\\anton\\unpacked\\abcl\\abcl-bin-1.1.0\\abcl.jar")) +(defparameter *clisp* (make-instance 'lisp-exe:clisp :exe-path "clisp")) +(defparameter *ccl-1.8-x86* (make-instance 'lisp-exe:ccl + :exe-path "C:\\Users\\anton\\unpacked\\ccl\\ccl-1.8-windows\\wx86cl.exe")) +(defparameter *ccl-1.8-x86-64* (make-instance 'lisp-exe:ccl + :exe-path "C:\\Users\\anton\\unpacked\\ccl\\ccl-1.8-windows\\wx86cl64.exe")) +(defparameter *sbcl-1.1.0.45* (make-instance 'lisp-exe:sbcl :exe-path "C:\\Program Files (x86)\\Steel Bank Common Lisp\\1.1.0.45\\run.bat")) +(defparameter *sbcl-win-branch-64* (make-instance 'lisp-exe:sbcl :exe-path "C:\\Program Files\\Steel Bank Common Lisp\\1.1.0.36.mswinmt.1201-284e340\\run.bat")) +(defparameter *sbcl-win-branch-32* (make-instance 'lisp-exe:sbcl :exe-path "C:\\Program Files (x86)\\Steel Bank Common Lisp\\1.1.0.36.mswinmt.1201-284e340\\run.bat")) +(defparameter *ecl-bytecode* (make-instance 'lisp-exe:ecl + :exe-path "C:\\Users\\anton\\projects\\ecl\\bin\\ecl.exe" + :compiler :bytecode)) +(defparameter *ecl-lisp-to-c* (make-instance 'lisp-exe:ecl + :exe-path "C:\\Users\\anton\\projects\\ecl\\bin\\ecl.exe" + :compiler :lisp-to-c)) +(defparameter *acl* (make-instance 'lisp-exe:acl :exe-path "C:\\Program Files (x86)\\acl90express\\alisp.exe")) + +(defun run-on-many-lisps (run-description test-run-dir quicklisp-dir lisps) + (ensure-directories-exist test-run-dir) + (let ((fasl-root (merge-pathnames "fasl/" test-run-dir))) + (labels ((log-name (lisp) + (substitute #\- #\. + ;; Substitute dots by hypens if our main process is CCL, it + ;; prepends the > symbol before dots; + ;; for example: 1.1.0.36.mswinmt.1201-284e340 => 1>.1>.0>.36>.mswinmt.1201-284e340 + ;; When we pass such a pathname to another lisps, they can't handle it. + (string-downcase (tg-agent::implementation-identifier lisp)))) + (fasl-dir (lisp) + (merge-pathnames (format nil "~A/" (log-name lisp)) + fasl-root)) + (run (lisp) + (let* ((lib-result (tg-agent::proc-run-libtest lisp + :trivial-gray-streams + run-description + (merge-pathnames (log-name lisp) test-run-dir) + quicklisp-dir + (fasl-dir lisp))) + (status (getf lib-result :status))) + (if (listp status) + (getf status :failed-tests) + status)))) + (let ((results (mapcar (lambda (lisp) + (list (tg-agent::implementation-identifier lisp) + (run lisp))) + lisps))) + (tg-utils::write-to-file results (merge-pathnames "resutls.lisp" test-run-dir)) + (cl-fad:delete-directory-and-files fasl-root) + results)))) + +(run-on-many-lisps '(:lib-world "quicklisp 2013-02-17 + trivial-gray-streams.head" + :contact-email "avodonosov@yandex.ru") + "C:\\Users\\anton\\projects\\trivial-gray-streams\\test\\" + (merge-pathnames "quicklisp/" (user-homedir-pathname)) + (list *sbcl-1.1.0.45* *sbcl-win-branch-64* *sbcl-win-branch-32* + *abcl* + *clisp* + *ccl-1.8-x86* *ccl-1.8-x86-64* + *ecl-bytecode* *ecl-lisp-to-c* + *acl*)) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/test/test-framework.lisp b/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/test/test-framework.lisp new file mode 100644 index 0000000..8f9717a --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/test/test-framework.lisp @@ -0,0 +1,60 @@ +(in-package :trivial-gray-streams-test) + +;;; test framework + +#| + Used like this: + + (list (test (add) (assert (= 5 (+ 2 2)))) + (test (mul) (assert (= 4 (* 2 2)))) + (test (subst) (assert (= 3 (- 4 2))))) + + => ;; list of test results, 2 failed 1 passed + (# + # + #) + +|# + +(defclass test-result () + ((name :type symbol + :initarg :name + :initform (error ":name is requierd") + :accessor name) + (status :type (or (eql :ok) (eql :fail)) + :initform :ok + :initarg :status + :accessor status) + (cause :type (or null condition) + :initform nil + :initarg :cause + :accessor cause))) + +(defun failed-p (test-result) + (eq (status test-result) :fail)) + +(defmethod print-object ((r test-result) stream) + (print-unreadable-object (r stream :type t) + (format stream "~S ~S~@[ ~A~]" (name r) (status r) (cause r)))) + +(defparameter *allow-debugger* nil) + +(defun test-impl (name body-fn) + (flet ((make-result (status &optional cause) + (make-instance 'test-result :name name :status status :cause cause))) + (handler-bind ((serious-condition + (lambda (c) + (unless *allow-debugger* + (format t "FAIL: ~A~%" c) + (let ((result (make-result :fail c))) + (return-from test-impl result)))))) + (format t "Running test ~S... " name) + (funcall body-fn) + (format t "OK~%") + (make-result :ok)))) + +(defmacro test ((name) &body body) + "If the BODY signals a SERIOUS-CONDITION +this macro returns a failed TEST-RESULT; otherwise +returns a successfull TEST-RESULT." + `(test-impl (quote ,name) (lambda () ,@body))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/test/test.lisp b/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/test/test.lisp new file mode 100644 index 0000000..0baed1b --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/test/test.lisp @@ -0,0 +1,213 @@ +(in-package :trivial-gray-streams-test) + +;;; assert-invoked - a tool to check that specified method with parameters has +;;; been invoked during execution of a code body + +(define-condition invoked () + ((method :type (or symbol cons) ;; cons is for (setf method) + :accessor method + :initarg :method + :initform (error ":method is required")) + (args :type list + :accessor args + :initarg :args + :initform nil))) + +(defun assert-invoked-impl (method args body-fn) + (let ((expected-invocation (cons method args)) + (actual-invocations nil)) + (handler-bind ((invoked (lambda (i) + (let ((invocation (cons (method i) (args i)))) + (when (equalp invocation expected-invocation) + (return-from assert-invoked-impl nil)) + (push invocation actual-invocations))))) + (funcall body-fn)) + (let ((*package* (find-package :keyword))) ; ensures package prefixes are printed + (error "expected invocation: ~(~S~) actual: ~{~(~S~)~^, ~}" + expected-invocation (reverse actual-invocations))))) + +(defmacro assert-invoked ((method &rest args) &body body) + "If during execution of the BODY the specified METHOD with ARGS +hasn't been invoked, signals an ERROR." + `(assert-invoked-impl (quote ,method) (list ,@args) (lambda () ,@body))) + +(defun invoked (method &rest args) + (signal 'invoked :method method :args args)) + +;;; The tests. + +#| + We will define a gray stream class, specialise + the gray generic function methods on it and test that the methods + are invoked when we call functions from common-lisp package + on that stream. + + Some of the gray generic functions are only invoked by default + methods of other generic functions: + + cl:format ~t or cl:pprint -> stream-advance-to-column -> stream-line-column + stream-write-char + cl:fresh-line -> stream-fresh-line -> stream-start-line-p -> stream-line-column + stream-terpri + + + If we define our methods for stream-advance-to-column and stream-fresh-line, + then stream-start-line-p, stream-terpri, stram-line-column are not invoked. + + Therefore we define another gray stream class. The first class is used + for all lower level functions (stream-terpri). The second class + is used to test methods for higher level functions (stream-fresh-line). +|# + +(defclass test-stream (fundamental-binary-input-stream + fundamental-binary-output-stream + fundamental-character-input-stream + fundamental-character-output-stream) + ()) + +(defclass test-stream2 (test-stream) ()) + +(defmethod stream-read-char ((stream test-stream)) + (invoked 'stream-read-char stream)) + +(defmethod stream-unread-char ((stream test-stream) char) + (invoked 'stream-unread-char stream char)) + +(defmethod stream-read-char-no-hang ((stream test-stream)) + (invoked 'stream-read-char-no-hang stream)) + +(defmethod stream-peek-char ((stream test-stream)) + (invoked 'stream-peek-char stream)) + +(defmethod stream-listen ((stream test-stream)) + (invoked 'stream-listen stream)) + +(defmethod stream-read-line ((stream test-stream)) + (invoked 'stream-read-line stream)) + +(defmethod stream-clear-input ((stream test-stream)) + (invoked 'stream-clear-input stream)) + +(defmethod stream-write-char ((stream test-stream) char) + (invoked 'stream-write-char stream char)) + +(defmethod stream-line-column ((stream test-stream)) + (invoked 'stream-line-column stream)) + +(defmethod stream-start-line-p ((stream test-stream)) + (invoked 'stream-start-line-p stream)) + +(defmethod stream-write-string ((stream test-stream) string &optional start end) + (invoked 'stream-write-string stream string start end)) + +(defmethod stream-terpri ((stream test-stream)) + (invoked 'stream-terpri stream)) + +(defmethod stream-fresh-line ((stream test-stream2)) + (invoked 'stream-fresh-line stream)) + +(defmethod stream-finish-output ((stream test-stream)) + (invoked 'stream-finish-output stream)) + +(defmethod stream-force-output ((stream test-stream)) + (invoked 'stream-force-output stream)) + +(defmethod stream-clear-output ((stream test-stream)) + (invoked 'stream-clear-output stream)) + +(defmethod stream-advance-to-column ((stream test-stream2) column) + (invoked 'stream-advance-to-column stream column)) + +(defmethod stream-read-byte ((stream test-stream)) + (invoked 'stream-read-byte stream)) + +(defmethod stream-write-byte ((stream test-stream) byte) + (invoked 'stream-write-byte stream byte)) + +(defmethod stream-read-sequence ((s test-stream) seq start end &key) + (invoked 'stream-read-sequence s seq :start start :end end)) + +(defmethod stream-write-sequence ((s test-stream) seq start end &key) + (invoked 'stream-write-sequence s seq :start start :end end)) + +(defmethod stream-file-position ((s test-stream)) + (invoked 'stream-file-position s)) + +(defmethod (setf stream-file-position) (newval (s test-stream)) + (invoked '(setf stream-file-position) newval s)) + +;; Convinience macro, used when we want to name +;; the test case with the same name as of the gray streams method we test. +(defmacro test-invoked ((method &rest args) &body body) + `(test (,method) + (assert-invoked (,method ,@args) + ,@body))) + +(defun run-tests () + (let ((s (make-instance 'test-stream)) + (s2 (make-instance 'test-stream2))) + (list + (test-invoked (stream-read-char s) + (read-char s)) + (test-invoked (stream-unread-char s #\a) + (unread-char #\a s)) + (test-invoked (stream-read-char-no-hang s) + (read-char-no-hang s)) + (test-invoked (stream-peek-char s) + (peek-char nil s)) + (test-invoked (stream-listen s) + (listen s)) + (test-invoked (stream-read-line s) + (read-line s)) + (test-invoked (stream-clear-input s) + (clear-input s)) + (test-invoked (stream-write-char s #\b) + (write-char #\b s)) + (test-invoked (stream-line-column s) + (format s "~10,t")) + (test-invoked (stream-start-line-p s) + (fresh-line s)) + (test-invoked (stream-write-string s "hello" 1 4) + (write-string "hello" s :start 1 :end 4)) + (test-invoked (stream-terpri s) + (fresh-line s)) + (test-invoked (stream-fresh-line s2) + (fresh-line s2)) + (test-invoked (stream-finish-output s) + (finish-output s)) + (test-invoked (stream-force-output s) + (force-output s)) + (test-invoked (stream-clear-output s) + (clear-output s)) + (test-invoked (stream-advance-to-column s2 10) + (format s2 "~10,t")) + (test-invoked (stream-read-byte s) + (read-byte s)) + (test-invoked (stream-write-byte s 1) + (write-byte 1 s)) + ;;; extensions + (let ((seq (vector 1 2))) + (test-invoked (stream-read-sequence s seq :start 0 :end 1) + (read-sequence seq s :start 0 :end 1)) + (test-invoked (stream-write-sequence s seq :start 0 :end 1) + (write-sequence seq s :start 0 :end 1))) + (test-invoked (stream-file-position s) + (file-position s)) + (test (setf-stream-file-position) + (assert-invoked ((setf stream-file-position) 9 s) + (file-position s 9)))))) + +(defun failed-tests (results) + (remove-if-not #'failed-p results)) + +(defun failed-test-names (results) + (mapcar (lambda (result) + (string-downcase (name result))) + (failed-tests results))) + +#| +(failed-test-names (run-tests)) + +(setf *allow-debugger* nil)) + +|# diff --git a/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/trivial-gray-streams-test.asd b/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/trivial-gray-streams-test.asd new file mode 100644 index 0000000..9eb6b74 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/trivial-gray-streams-test.asd @@ -0,0 +1,10 @@ +;;; -*- mode: lisp -*- + +(defsystem :trivial-gray-streams-test + :version "2.0" + :depends-on (:trivial-gray-streams) + :pathname #P"test/" + :serial t + :components ((:file "package") + (:file "test-framework") + (:file "test"))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/trivial-gray-streams.asd b/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/trivial-gray-streams.asd new file mode 100644 index 0000000..d57afff --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/trivial-gray-streams-20181018-git/trivial-gray-streams.asd @@ -0,0 +1,10 @@ +;;; -*- mode: lisp -*- + +(defsystem :trivial-gray-streams + :description "Compatibility layer for Gray Streams (see http://www.cliki.net/Gray%20streams)." + :license "MIT" + :author "David Lichteblau" + :maintainer "Anton Vodonosov " + :version "2.0" + :serial t + :components ((:file "package") (:file "streams"))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/.gitignore b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/.gitignore new file mode 100644 index 0000000..b25c15b --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/.gitignore @@ -0,0 +1 @@ +*~ diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/CHANGES b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/CHANGES new file mode 100644 index 0000000..00eadb5 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/CHANGES @@ -0,0 +1,211 @@ +0.8.3: + + * New experimental backend: Mezzano (contributed by Bruno Cichon, #51) + * Bugfix: WAIT-FOR-INPUT fails to honor :ready-only t (#57, thanks to @Reepca for reporting this issue) + * Bugfix: [ECL] Fix read-select in backend/sbcl.lisp to loop if interrupted (#54, #55, thanks to @thijs) + * [CCL] Fix compiling with (readtable-case readtable-case) of :invert. (#56, patch from @genworks) + * [Genera] added file attibutes (to all USOCKET lisp files) for Genera. + +0.8.2: (June 11, 2019) + + * General: now the HOST-OR-IP slot of NS-CONDITION has been exported. (#46) + * Bugfix: NS-HOST-NOT-FOUND-ERROR condition has unbound HOST-OR-IP slot (#46) + * Bugfix: [SBCL/LW] WAIT-FOR-INPUT waits only in the first call (when W-F-I is called with a single usocket, introduced in 0.8.0) (#50, thanks to @Hamayama for reporting/hints/testing this issue) + +0.8.1: (Feb 27, 2019) + +* New backend: clasp (patch from Christian Schafmeister, #45) +* Bugfix: [SBCL] fixed loading usocket.asd in SBCL 1.5.0 + +0.8.0: (Feb 4, 2019) + +* New backend (experimental): IOlib. (Push :USOCKET-IOLIB to *FEATURES* to enable this feature) +* New feature: Optimized WAIT-FOR-INPUT for single-socket case (one-time consing) +* New feature: Exported host-to-hostname (#42) +* Bugfix: [SBCL] more robust/thread-safe WAIT-FOR-INPUT-INTERNAL + +0.7.1: (Aug 31, 2018) + +* New feature: GET-(RANDOM)-HOST-BY-NAME (now exported) prefer IPv4 on mixed IPv4/IPv6 (suggested by Mark H. David) +* New backend: Symbolics Open Genera (Lisp machine) (patch from @Symbolics, #33) +* Bugfix: [CLISP] fixed issues in server sockets and error handling. (patch from @vibs29, #28, #29) +* Bugfix: [SBCL, ECL] Fix wait-for-input on Windows SBCL and ECL. (patch from Stas Boukarev, #30) +* Bugfix: [LW] fixed non-existing system calls in LW 5.0 (comm::socket-set-tcp-nodelay) + +0.7.0: (Oct 25, 2016) + +* General: Separated USOCKET and USOCKET-SERVER systems (only the server part depends on Portable-threads) +* General: USOCKET now depends on SPLIT-SEQUENCE (the exactly same vendor code is removed from usocket code base) +* New feature: [LW] (SOCKET-OPTION :TCP-NODELAY) and its SETF version now works on LispWorks 4/5/6/7. +* New feature: [LW] SOCKET-CONNECT now supports setting "tcp_nodelay" in version 4.x and 5.0. +* Bugfix: [CCL] fixed issues in SOCKET-SHUTDOWN +* Bugfix: [CLISP] fixed issues in WAIT-FOR-INPUT (Thanks to a patch by @vibs29, #27) +* Bugfix: [LW] fixed loading in version <= 6.0 (actually 0.6.5 only fixed loading in LW 6.1) +* Bugfix: [ECL] all compilation warnings were checked and fixed. + +0.6.5: (Oct 19, 2016) + +* New feature: SOCKET-OPTION and (setf SOCKET-OPTION) for :SEND-TIMEOUT (thanks to John Pallister) +* Bugfix: Let (WAIT-FOR-INPUT NIL &TIMEOUT) return NIL with respect to TIMEOUT. +* Bugfix: [LW] fixed loading in LispWorks 5.x & 6.x. +* Bugfix: [LW] fixed SOCKET-SHUTDOWN in all versions. +* Bugfix: [ABCL] Fixed incorrect IPv6 addresses (#26), patch from Elias Mårtenson (lokedhs) + +0.6.4: (Mar 17, 2016) + +* New feature: [SBCL] IPv6 support (patch from Guillaume LE VAILLANT, #15) +* New feature: [API] SOCKET-SHUTDOWN added (patch from Thayne McCombs #9) +* New feature: [Corman] minimal initial support of this platform +* Bugfix: [SBCL/win32] wait-for-input nil-timeout bug (patch from Michal Herda, #13) +* Bugfix: [ECL] included unistd.h for gethostname() (patch from Daniel Kochmanski, #7) +* Bugfix: [LispWorks] SOCKET-RECEIVE now updates %READ-P (patch from Frank James) + +0.6.3: (May 23, 2015) + +* Bugfix: [CCL] Further fixed CCL-1.11 compatibility and a typo in SOCKET-CONNECT for CCL-1.10. +* Bugfix: [ECL] Fixed build in some versions. +* Bugfix: [LispWorks] SOCKET-SEND and SOCKET-RECEIVE now throw conditions if something goes wrong. + +0.6.2: (Apr 20, 2015) + +* Bugfix: [CCL] Fixed CCL-1.11 compatibility. +* Bugfix: [ECL] Fixed compatibility on recent versions. +* Bugfix: [LispWorks] Added support address-in-use-error condition on LW/Win32. (patch from Sergey Katrevich). + +0.6.1: (Jun 21, 2013) + +* New feature: [MOCL] Initial MOCL support (TCP only, no W-F-I, patch from github.com/Wukix/usocket). +* New feature: [MCL] Initial UDP support for Macintosh Common Lisp (MCL/RMCL). +* New feature: Added TCP-NO-DELAY (TCP_NODELAY) support in SOCKET-OPTION, for TCP client +* Bugfix: [CCL] Added (:external-format ccl:*default-external-format*) to SOCKET-CONNECT, to prevent it fallback to ISO-8859-1 on NIL. (Patch from Vsevolod Dyomkin) +* Bugfix: [CCL] Performance improved WAIT-FOR-INPUT and other fixes. (patch from Faré ) + +0.6.0: (Dec 26, 2012) + +* New feature: SOCKET-OPTION and (setf SOCKET-OPTION) for seting and geting various socket options. +* New feature: SOCKET-SEND now support an CCL-like OFFSET keyword for sending only parts of the whole buffer. +* New feature: [ECL] Added support for ECL DFFI mode on Windows. (no need for C compilers now) +* Bugfix: [ECL] ECL now list sb-bsd-sockets as a dependency but relies on REQUIRE. (patched by Juanjo) +* Bugfix: [ABCL] Make USOCKET compile warning-free on ABCL again: MAKE-IMMEDIATE-OBJECT was deprecated a while ago in favor of 2 predefined constants. +* Bugfix: [LispWorks] remove redundant call to hcl:flag-special-free-action. (reported by Kamil Shakirov) +* Bugfix: [CLISP] improved HANDLE-CONDITION for more CLISP environments. + +0.5.5: (Feb 27, 2012) + +* Enhancement: SOCKET-CONNECT argument :nodelay can now set to :if-supported (patch from Anton Vodonosov). +* Enhancement: [Server] adding *remote-host* *remote-port* to socket-server stream handler functions (suggested by Matthew Curry) +* Bugfix: [LispWorks] Fixed UDP support for LispWorks 6.1 (patch from Camille Troillard by Martin Simmons). +* Bugfix: [LispWorks] Stop using hcl:add-special-free-action for reclaiming unused UDP socket fds to improve multi-threading stablity (suggested by Camille Troillard). +* Bugfix: [LispWorks] Fixed SOCKET-CONNECT on Windows, now LOCAL-PORT never have *auto-port* (0) as default value. + +0.5.4: (Oct 1, 2011) + +* Bugfix: [ECL] Fixed for ECL's MAKE-BUILD by removing some unecessary code (reported by Juan Jose Garcia-Ripoll, the ECL maintainer) +* Bugfix: [ACL] Fixed for Allegro CL modern mode. +* Bugfix: [SBCL] SOCKET-CONNECT on TCP won't call bind() when keyword arguments LOCAL-HOST or LOCAL-PORT is not set. (reported by Robert Brown) + +0.5.3: (Aug 13, 2011) + +* Bugfix: [MCL] Fixed SOCKET-LISTEN on vector addresses like #(0 0 0 0) +* Bugfix: [MCL] Fixed WAIT-FOR-INPUT on passive sockets (stream-server-usocket) +* Bugfix: [LispWorks] Fixed using OPEN-UDP-SOCKET in delivered applications (thanks to Camille Troillard and Martin Simmons, this fix is from LispWorks-UDP project). +* Bugfix: [SBCL] Fixed for "SBCL data flush problem", reported by Robert Brown and confirmed by Nikodemus Siivola. + +0.5.2: (May 11, 2011) + +* General: [SBCL] SOCKET-CONNECT's TIMEOUT argument was limited on non-Windows platforms. +* Bugfix: [CLISP] WAIT-FOR-INPUT now functions right (with/without READY-ONLY), this made Hunchentoot working on CLISP. (Thanks to Anton Vodonosov ) +* Bugfix: [ABCL] Fix SOCKET-ACCEPT to follow the documented API so that when called without an :ELEMENT-TYPE argument. (Thanks to Mark Evenson, the ABCL developer) +* Bugfix: [LispWorks] Fixed SOCKET-ACCEPT (Windows only) on WAIT-FOR-INPUTed sockets. +* Bugfix: [SBCL, ECL] Fixed wrongly STATE set/unset for WAIT-FOR-INPUT on Windows (report by Elliott Slaughter) +* Enhancement: Additional NAME keyword argument for SOCKET-SERVER for setting the server thread name. +* Enhancement: [ABCL] GET-ADDRESS now works with underlying IPv6 addresses. +* Enhancement: [CLISP] missing GET-LOCAL-* methods for STREAM-SERVER-USOCKET was now added. + +0.5.1: (Apr 2, 2011) + +* New feature: [CLISP] UDP (Datagram) support based on FFI (Win/Mac/Linux), no RAWSOCK needed. +* Enhancement: SOCKET-SERVER return a second value (socket) when calling in new-thread mode. +* Enhancement: [CLISP] Full support of DNS helper functions (GET-HOST-BY-NAME, ...) added. +* Enhancement: [CLISP] Better network error type detection based on OS error code. +* Enhancement: [LispWorks] Better network error type detection based on OS error code. +* Bugfix: Fixed wrong macro expansions of {IP|PORT}-{FROM|TO}-OCTET-BUFFER functions (since 0.4.0) +* Bugfix: SOCKET-CONNECT didn't set CONNECTED-P for datagram usockets on most backends. +* Bugfix: [SBCL] Fixes for "SBCL/Win32: finalizer problem, etc", by Anton Kovalenko +* Bugfix: [SBCL] Fixed SOCKET-SERVER (UDP) on SBCL due to a issue in SOCKET-CONNECT when HOST is NIL. +* Bugfix: [SBCL] SOCKET-CONNECT's TIMEOUT argument now works as a "connection timeout". +* Bugfix: [CMUCL] Fixed SOCKET-SEND on unconnected usockets under Unicode version of CMUCL. +* Bugfix: [CLISP] Fixed and confirmed UDP (Datagram) support (RAWSOCK version). + +0.5.0: (Mar 12, 2011) + +* New supported platform: Macintosh Common Lisp (5.0 and up, plus RMCL) +* Support for UDP (datagram-usocket) was added (for all supported platform except MCL) +* Add WAIT-FOR-INPUT support for SBCL and ECL on win32. +* Simple TCP and UDP server API: SOCKET-SERVER +* Completely rewritten full-feature ABCL backends using latest Java interfaces +* Lots of bug fixed since 0.4.1 + +0.4.1: (Dec 27, 2008) + +* fixes for ECL, LispWorks, SBCL, SCL + +0.4.0: (Oct 28, 2008) + +* select()-like api: make a single thread wait for multiple sockets. +* various socket options for socket-creation with SOCKET-CONNECT. + +0.3.6: (Jun 21, 2008) + +* Code fixups based on advice from the ECL and OpenMCL maintainers. +* New exported symbols: WITH-MAPPED-CONDITIONS, NS-CONDITION, NS-ERROR, NS-UNKNOWN-ERROR and NS-UNKNOWN-CONDITION. + +0.3.4: (Jul 25, 2007) + +* Fix clisp get-host-name, multiple ECL fixes. + +0.3.3: (Jun 05, 2007) + +* Fix where host resolution routine was unable to resolve would return NIL instead of erroring. + +0.3.2: (Mar 04, 2007) + +* Fixes for many backends related to closing sockets. +* LispWorks fix for broken server sockets. +* API guarantee adjustments in preparation of porting Drakma. + +0.3.1: (Feb 28, 2007) + +* fixed with-server-socket; prevent creation of invalid sockets; 2 more convenience macros. + +0.3.0: (Jan 21, 2007) + +* Server sockets + +0.2.5: (Jan 19, 2007) + +* Allegro compilation fix. + +0.2.4: (Jan 17, 2007) + +* Various fixes for CMUCL, OpenMCL, Allegro and LispWorks. + +0.2.3: (Jan 04, 2007) + +* Add :element-type support to support stacking flexi-streams on socket streams for portable :external-format support. + +0.2.2: (Jan 03, 2007) + +* Add ECL support and a small SBCL bugfix. + +0.2.1: (Dec 21, 2006) + +* Remove 'open-stream' interface which is supposed to be provided by the 'trivial-usocket' package. + +0.2.0: (Dec 18, 2006) + +* Add support for Scieneer Common Lisp, fix issue #6 and API preparation for server side sockets (not in this release) + +0.1.0: (Feb 13, 2006) + +* Initial release diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/CONTRIBUTORS b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/CONTRIBUTORS new file mode 100644 index 0000000..fd761cd --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/CONTRIBUTORS @@ -0,0 +1,47 @@ +-*- Mode: outline -*- + +List of major USOCKET contributors: + +* Erik Enge +* Erik Huelsmann + - original authors + +* Chun Tian +* Hans Huebner + - current maintainers + +* Attila Lendvai + - better handling of unsupported Lisps + +* Vladimir Sekissov + - fixes for CMUCL implementation + +* Pierre Thierry + - added license information + +* Stelian Ionescu + - finished conversion from generic functions + - enabled running thread-safe code in unthreaded lisps + +* Douglas Crosher + - added Scieneer Common Lisp support + +* Frank James + - UDP fixes and test cases + +* Mark H. David + - UDP test cases + - Suggestions on fixing GET-HOST-BY-NAME and HOST-TO-HBO + +* Elliott Slaughter + - Advanced WAIT-FOR-INPUT test case + +* Anton Vodonosov + - CLISP fixes + +* Terje Norderhaug + - MCL vendor code + +* @Hamayama + + - Reporting/hints/testing of issue #50 (regression in 0.8.0, 0.8.1) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/LICENSE b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/LICENSE new file mode 100644 index 0000000..1b94618 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/LICENSE @@ -0,0 +1,25 @@ +(This is the MIT / X Consortium license as taken from + http://www.opensource.org/licenses/mit-license.html) + +Copyright (c) 2003 Erik Enge +Copyright (c) 2006-2007 Erik Huelsmann +Copyright (c) 2008-2019 Hans Hueber and Chun Tian + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/README.md b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/README.md new file mode 100644 index 0000000..b121c4a --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/README.md @@ -0,0 +1,148 @@ +## USOCKET - Universal socket library for Common Lisp + +https://common-lisp.net/project/usocket/ + +This is the usocket Common Lisp sockets library: a library to bring +sockets access to the broadest of common lisp implementations as possible. + +## The library currently supports: + +1. Allegro CL +2. ABCL (ArmedBear) +3. Clasp +4. Clozure CL +5. Corman Lisp +6. GNU CLISP +7. CMUCL +8. ECL +9. LispWorks (4.3 and up) +10. Digitool MCL and RMCL (5.0 and up) +11. Mezzano +12. MOCL +13. SBCL +14. Scieneer CL +15. Symbolics Lisp Machine (Genera) + +If your favorite common lisp misses in the list above, please contact +usocket-devel@common-lisp.net and submit a request. Please include +references to available sockets functions in your lisp implementation. + +The library has been ASDF (http://cliki.net/ASDF) enabled, meaning +that you can tar up a checkout and use that to ASDF-INSTALL:INSTALL +the package in your system package site. (Or use your usual ASDF +tricks to use the checkout directly.) + +## Remarks on licensing + +Even though the source code has an MIT style license attached to it, +when compiling this code with some of the supported lisp implementations +you may not end up with an MIT style binary version due to the licensing +of the implementations themselves. ECL is such an example and - when +it will become supported - GCL is like that too. + +## Non-support of :external-format + +Because of its definition in the hyperspec, there's no common +external-format between lisp implementations: every vendor has chosen +a different way to solve the problem of newline translation or +character set recoding. + +Because there's no way to avoid platform specific code in the application +when using external-format, the purpose of a portability layer gets +defeated. So, for now, usocket doesn't support external-format. + +The workaround to get reasonably portable external-format support is to +layer a flexi-stream (from flexi-streams) on top of a usocket stream. + +## API definition + + - usocket (class) + - stream-usocket (class; usocket derivative) + - stream-server-usocket (class; usocket derivative) + - socket-connect (function) [ to create an active/connected socket ] + socket-connect host port &key element-type + where `host' is a vectorized ip + or a string representation of a dotted ip address + or a hostname for lookup in the DNS system + - socket-listen (function) [ to create a passive/listening socket ] + socket-listen host port &key reuseaddress backlog element-type + where `host' has the same definition as above + - socket-accept (method) [ to create an active/connected socket ] + socket-accept socket &key element-type + returns (server side) a connected socket derived from a + listening/passive socket. + - socket-close (method) + socket-close socket + where socket a previously returned socket + - socket (usocket slot accessor), + the internal/implementation defined socket representation + - socket-stream (usocket slot accessor), + socket-stream socket + the return value of which satisfies the normal stream interface + - socket-shutdown + +### Errors: + - address-in-use-error + - address-not-available-error + - bad-file-descriptor-error + - connection-refused-error + - connection-aborted-error + - connection-reset-error + - invalid-argument-error + - no-buffers-error + - operation-not-supported-error + - operation-not-permitted-error + - protocol-not-supported-error + - socket-type-not-supported-error + - network-unreachable-error + - network-down-error + - network-reset-error + - host-down-error + - host-unreachable-error + - shutdown-error + - timeout-error + - unkown-error + +### Non-fatal conditions: + - interrupted-condition + - unkown-condition + +(for a description of the API methods and functions see + https://common-lisp.net/project/usocket/api-docs.shtml) + +## Test suite + +The test suite unfortunately isn't mature enough yet to run without +some manual configuration. Several elements are required which are +hard to programatically detect. Please adjust the test file before +running the tests, for these variables: + +- +non-existing-host+: The stringified IP address of a host on the + same subnet. No physical host may be present. +- +unused-local-port+: A port number of a port not in use on the + machine the tests run on. +- +common-lisp-net+: A vector with 4 integer elements which make up + an IP address. This must be the IP "common-lisp.net" resolves to. + +## Known problems + +- CMUCL error reporting wrt sockets raises only simple-errors + meaning there's no way to tell different error conditions apart. + All errors are mapped to unknown-error on CMUCL. + +- The ArmedBear backend doesn't do any error mapping (yet). Java + defines exceptions at the wrong level (IMO), since the exception + reported bares a relation to the function failing, not the actual + error that occurred: for example 'Address already in use' (when + creating a passive socket) is reported as a BindException with + an error text of 'Address already in use'. There's no way to sanely + map 'BindException' to a meaningfull error in usocket. [This does not + mean the backend should not at least map to 'unknown-error'!] + +- When using the library with ECL, you need the C compiler installed + to be able to compile and load the Foreign Function Interface. + Not all ECL targets support DFFI yet, so on some targets this would + be the case anyway. By depending on this technique, usocket can + reuse the FFI code on all platforms (including Windows). This benefit + currently outweighs the additional requirement. (hey, it's *Embeddable* + Common Lisp, so, you probably wanted to embed it all along, right?) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/TODO b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/TODO new file mode 100644 index 0000000..e631798 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/TODO @@ -0,0 +1,5 @@ +- Fix condition systems (making all implementation generate same error) +- Add INET6 support. +- IOlib backend + +For more TODO items, see http://trac.common-lisp.net/usocket/report. diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/.gitignore b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/.gitignore new file mode 100644 index 0000000..b25c15b --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/.gitignore @@ -0,0 +1 @@ +*~ diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/abcl.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/abcl.lisp new file mode 100644 index 0000000..d73c552 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/abcl.lisp @@ -0,0 +1,436 @@ +;;;; New ABCL networking support (replacement to old armedbear.lisp) +;;;; Author: Chun Tian (binghe) + +;;;; See LICENSE for licensing information. + +(in-package :usocket) + +;;; Java Classes ($*...) +(defvar $*boolean (jclass "boolean")) +(defvar $*byte (jclass "byte")) +(defvar $*byte[] (jclass "[B")) +(defvar $*int (jclass "int")) +(defvar $*long (jclass "long")) +(defvar $*|Byte| (jclass "java.lang.Byte")) +(defvar $*DatagramChannel (jclass "java.nio.channels.DatagramChannel")) +(defvar $*DatagramPacket (jclass "java.net.DatagramPacket")) +(defvar $*DatagramSocket (jclass "java.net.DatagramSocket")) +(defvar $*Inet4Address (jclass "java.net.Inet4Address")) +(defvar $*InetAddress (jclass "java.net.InetAddress")) +(defvar $*InetSocketAddress (jclass "java.net.InetSocketAddress")) +(defvar $*Iterator (jclass "java.util.Iterator")) +(defvar $*SelectableChannel (jclass "java.nio.channels.SelectableChannel")) +(defvar $*SelectionKey (jclass "java.nio.channels.SelectionKey")) +(defvar $*Selector (jclass "java.nio.channels.Selector")) +(defvar $*ServerSocket (jclass "java.net.ServerSocket")) +(defvar $*ServerSocketChannel (jclass "java.nio.channels.ServerSocketChannel")) +(defvar $*Set (jclass "java.util.Set")) +(defvar $*Socket (jclass "java.net.Socket")) +(defvar $*SocketAddress (jclass "java.net.SocketAddress")) +(defvar $*SocketChannel (jclass "java.nio.channels.SocketChannel")) +(defvar $*String (jclass "java.lang.String")) + +;;; Java Constructor ($%.../n) +(defvar $%Byte/0 (jconstructor $*|Byte| $*byte)) +(defvar $%DatagramPacket/3 (jconstructor $*DatagramPacket $*byte[] $*int $*int)) +(defvar $%DatagramPacket/5 (jconstructor $*DatagramPacket $*byte[] $*int $*int $*InetAddress $*int)) +(defvar $%DatagramSocket/0 (jconstructor $*DatagramSocket)) +(defvar $%DatagramSocket/1 (jconstructor $*DatagramSocket $*int)) +(defvar $%DatagramSocket/2 (jconstructor $*DatagramSocket $*int $*InetAddress)) +(defvar $%InetSocketAddress/1 (jconstructor $*InetSocketAddress $*int)) +(defvar $%InetSocketAddress/2 (jconstructor $*InetSocketAddress $*InetAddress $*int)) +(defvar $%ServerSocket/0 (jconstructor $*ServerSocket)) +(defvar $%ServerSocket/1 (jconstructor $*ServerSocket $*int)) +(defvar $%ServerSocket/2 (jconstructor $*ServerSocket $*int $*int)) +(defvar $%ServerSocket/3 (jconstructor $*ServerSocket $*int $*int $*InetAddress)) +(defvar $%Socket/0 (jconstructor $*Socket)) +(defvar $%Socket/2 (jconstructor $*Socket $*InetAddress $*int)) +(defvar $%Socket/4 (jconstructor $*Socket $*InetAddress $*int $*InetAddress $*int)) + +;;; Java Methods ($@...[/Class]/n) +(defvar $@accept/0 (jmethod $*ServerSocket "accept")) +(defvar $@bind/DatagramSocket/1 (jmethod $*DatagramSocket "bind" $*SocketAddress)) +(defvar $@bind/ServerSocket/1 (jmethod $*ServerSocket "bind" $*SocketAddress)) +(defvar $@bind/ServerSocket/2 (jmethod $*ServerSocket "bind" $*SocketAddress $*int)) +(defvar $@bind/Socket/1 (jmethod $*Socket "bind" $*SocketAddress)) +(defvar $@byteValue/0 (jmethod $*|Byte| "byteValue")) +(defvar $@channel/0 (jmethod $*SelectionKey "channel")) +(defvar $@close/DatagramSocket/0 (jmethod $*DatagramSocket "close")) +(defvar $@close/Selector/0 (jmethod $*Selector "close")) +(defvar $@close/ServerSocket/0 (jmethod $*ServerSocket "close")) +(defvar $@close/Socket/0 (jmethod $*Socket "close")) +(defvar $@shutdownInput/Socket/0 (jmethod $*Socket "shutdownInput")) +(defvar $@shutdownOutput/Socket/0 (jmethod $*Socket "shutdownOutput")) +(defvar $@configureBlocking/1 (jmethod $*SelectableChannel "configureBlocking" $*boolean)) +(defvar $@connect/DatagramChannel/1 (jmethod $*DatagramChannel "connect" $*SocketAddress)) +(defvar $@connect/Socket/1 (jmethod $*Socket "connect" $*SocketAddress)) +(defvar $@connect/Socket/2 (jmethod $*Socket "connect" $*SocketAddress $*int)) +(defvar $@connect/SocketChannel/1 (jmethod $*SocketChannel "connect" $*SocketAddress)) +(defvar $@getAddress/0 (jmethod $*InetAddress "getAddress")) +(defvar $@getAllByName/1 (jmethod $*InetAddress "getAllByName" $*String)) +(defvar $@getByName/1 (jmethod $*InetAddress "getByName" $*String)) +(defvar $@getChannel/DatagramSocket/0 (jmethod $*DatagramSocket "getChannel")) +(defvar $@getChannel/ServerSocket/0 (jmethod $*ServerSocket "getChannel")) +(defvar $@getChannel/Socket/0 (jmethod $*Socket "getChannel")) +(defvar $@getAddress/DatagramPacket/0 (jmethod $*DatagramPacket "getAddress")) +(defvar $@getHostName/0 (jmethod $*InetAddress "getHostName")) +(defvar $@getInetAddress/DatagramSocket/0 (jmethod $*DatagramSocket "getInetAddress")) +(defvar $@getInetAddress/ServerSocket/0 (jmethod $*ServerSocket "getInetAddress")) +(defvar $@getInetAddress/Socket/0 (jmethod $*Socket "getInetAddress")) +(defvar $@getLength/DatagramPacket/0 (jmethod $*DatagramPacket "getLength")) +(defvar $@getLocalAddress/DatagramSocket/0 (jmethod $*DatagramSocket "getLocalAddress")) +(defvar $@getLocalAddress/Socket/0 (jmethod $*Socket "getLocalAddress")) +(defvar $@getLocalPort/DatagramSocket/0 (jmethod $*DatagramSocket "getLocalPort")) +(defvar $@getLocalPort/ServerSocket/0 (jmethod $*ServerSocket "getLocalPort")) +(defvar $@getLocalPort/Socket/0 (jmethod $*Socket "getLocalPort")) +(defvar $@getOffset/DatagramPacket/0 (jmethod $*DatagramPacket "getOffset")) +(defvar $@getPort/DatagramPacket/0 (jmethod $*DatagramPacket "getPort")) +(defvar $@getPort/DatagramSocket/0 (jmethod $*DatagramSocket "getPort")) +(defvar $@getPort/Socket/0 (jmethod $*Socket "getPort")) +(defvar $@hasNext/0 (jmethod $*Iterator "hasNext")) +(defvar $@iterator/0 (jmethod $*Set "iterator")) +(defvar $@next/0 (jmethod $*Iterator "next")) +(defvar $@open/DatagramChannel/0 (jmethod $*DatagramChannel "open")) +(defvar $@open/Selector/0 (jmethod $*Selector "open")) +(defvar $@open/ServerSocketChannel/0 (jmethod $*ServerSocketChannel "open")) +(defvar $@open/SocketChannel/0 (jmethod $*SocketChannel "open")) +(defvar $@receive/1 (jmethod $*DatagramSocket "receive" $*DatagramPacket)) +(defvar $@register/2 (jmethod $*SelectableChannel "register" $*Selector $*int)) +(defvar $@select/0 (jmethod $*Selector "select")) +(defvar $@select/1 (jmethod $*Selector "select" $*long)) +(defvar $@selectedKeys/0 (jmethod $*Selector "selectedKeys")) +(defvar $@send/1 (jmethod $*DatagramSocket "send" $*DatagramPacket)) +(defvar $@setReuseAddress/1 (jmethod $*ServerSocket "setReuseAddress" $*boolean)) +(defvar $@setSoTimeout/DatagramSocket/1 (jmethod $*DatagramSocket "setSoTimeout" $*int)) +(defvar $@setSoTimeout/Socket/1 (jmethod $*Socket "setSoTimeout" $*int)) +(defvar $@setTcpNoDelay/1 (jmethod $*Socket "setTcpNoDelay" $*boolean)) +(defvar $@socket/DatagramChannel/0 (jmethod $*DatagramChannel "socket")) +(defvar $@socket/ServerSocketChannel/0 (jmethod $*ServerSocketChannel "socket")) +(defvar $@socket/SocketChannel/0 (jmethod $*SocketChannel "socket")) +(defvar $@validOps/0 (jmethod $*SelectableChannel "validOps")) + +;;; Java Field Variables ($+...) +(defvar $+op-accept (jfield $*SelectionKey "OP_ACCEPT")) +(defvar $+op-connect (jfield $*SelectionKey "OP_CONNECT")) +(defvar $+op-read (jfield $*SelectionKey "OP_READ")) +(defvar $+op-write (jfield $*SelectionKey "OP_WRITE")) + + +;;; Wrapper functions (return-type: java-object) +(defun %get-address (address) + (jcall $@getAddress/0 address)) +(defun %get-all-by-name (string) ; return a simple vector + (jstatic $@getAllByName/1 $*InetAddress string)) +(defun %get-by-name (string) + (jstatic $@getByName/1 $*InetAddress string)) + +(defun host-to-inet4 (host) + "USOCKET host formats to Java Inet4Address, used internally." + (%get-by-name (host-to-hostname host))) + +;;; HANDLE-CONTITION + +(defparameter +abcl-error-map+ + `(("java.net.BindException" . operation-not-permitted-error) + ("java.net.ConnectException" . connection-refused-error) + ("java.net.NoRouteToHostException" . network-unreachable-error) ; untested + ("java.net.PortUnreachableException" . protocol-not-supported-error) ; untested + ("java.net.ProtocolException" . protocol-not-supported-error) ; untested + ("java.net.SocketException" . socket-type-not-supported-error) ; untested + ("java.net.SocketTimeoutException" . timeout-error))) + +(defparameter +abcl-nameserver-error-map+ + `(("java.net.UnknownHostException" . ns-host-not-found-error))) + +(defun handle-condition (condition &optional (socket nil) (host-or-ip nil)) + (typecase condition + (java-exception + (let ((java-cause (java-exception-cause condition))) + (let* ((usock-error (cdr (assoc (jclass-of java-cause) +abcl-error-map+ + :test #'string=))) + (usock-error (if (functionp usock-error) + (funcall usock-error condition) + usock-error)) + (nameserver-error (cdr (assoc (jclass-of java-cause) +abcl-nameserver-error-map+ + :test #'string=)))) + (if nameserver-error + (error nameserver-error :socket socket :host-or-ip host-or-ip) + (when usock-error + (error usock-error :socket socket)))))))) + +;;; GET-HOSTS-BY-NAME + +(defun get-address (address) + (when address + (let* ((array (%get-address address)) + (length (jarray-length array))) + (labels ((jbyte (n) + (let ((byte (jarray-ref array n))) + (if (minusp byte) (+ 256 byte) byte)))) + (cond + ((= 4 length) + (vector (jbyte 0) (jbyte 1) (jbyte 2) (jbyte 3))) + ((= 16 length) + (vector (jbyte 0) (jbyte 1) (jbyte 2) (jbyte 3) + (jbyte 4) (jbyte 5) (jbyte 6) (jbyte 7) + (jbyte 8) (jbyte 9) (jbyte 10) (jbyte 11) + (jbyte 12) (jbyte 13) (jbyte 14) (jbyte 15))) + (t nil)))))) ; neither a IPv4 nor IPv6 address?! + +(defun get-hosts-by-name (name) + (with-mapped-conditions (nil name) + (map 'list #'get-address (%get-all-by-name name)))) + +;;; GET-HOST-BY-ADDRESS + +(defun get-host-by-address (host) + (let ((inet4 (host-to-inet4 host))) + (with-mapped-conditions (nil host) + (jcall $@getHostName/0 inet4)))) + +;;; SOCKET-CONNECT + +(defun socket-connect (host port &key (protocol :stream) (element-type 'character) + timeout deadline (nodelay t nodelay-supplied-p) + local-host local-port) + (when deadline (unsupported 'deadline 'socket-connect)) + (let (socket stream usocket) + (ecase protocol + (:stream ; TCP + (let ((channel (jstatic $@open/SocketChannel/0 $*SocketChannel)) + (address (jnew $%InetSocketAddress/2 (host-to-inet4 host) port))) + (setq socket (jcall $@socket/SocketChannel/0 channel)) + ;; bind to local address if needed + (when (or local-host local-port) + (let ((local-address (jnew $%InetSocketAddress/2 (host-to-inet4 local-host) (or local-port 0)))) + (with-mapped-conditions (nil host) + (jcall $@bind/Socket/1 socket local-address)))) + ;; connect to dest address + (with-mapped-conditions (nil host) + (jcall $@connect/SocketChannel/1 channel address)) + (setq stream (ext:get-socket-stream socket :element-type element-type) + usocket (make-stream-socket :stream stream :socket socket)) + (when nodelay-supplied-p + (jcall $@setTcpNoDelay/1 socket (if nodelay ;; both t and :if-supported mean java:+true+ + java:+true+ java:+false+))) + (when timeout + (jcall $@setSoTimeout/Socket/1 socket (truncate (* 1000 timeout)))))) + (:datagram ; UDP + (let ((channel (jstatic $@open/DatagramChannel/0 $*DatagramChannel))) + (setq socket (jcall $@socket/DatagramChannel/0 channel)) + ;; bind to local address if needed + (when (or local-host local-port) + (let ((local-address (jnew $%InetSocketAddress/2 (host-to-inet4 local-host) (or local-port 0)))) + (with-mapped-conditions (nil local-host) + (jcall $@bind/DatagramSocket/1 socket local-address)))) + ;; connect to dest address if needed + (when (and host port) + (let ((address (jnew $%InetSocketAddress/2 (host-to-inet4 host) port))) + (with-mapped-conditions (nil host) + (jcall $@connect/DatagramChannel/1 channel address)))) + (setq usocket (make-datagram-socket socket :connected-p (if (and host port) t nil))) + (when timeout + (jcall $@setSoTimeout/DatagramSocket/1 socket (truncate (* 1000 timeout))))))) + usocket)) + +;;; SOCKET-LISTEN + +(defun socket-listen (host port &key reuseaddress + (reuse-address nil reuse-address-supplied-p) + (backlog 5 backlog-supplied-p) + (element-type 'character)) + (declare (type boolean reuse-address)) + (let* ((reuseaddress (if reuse-address-supplied-p reuse-address reuseaddress)) + (channel (jstatic $@open/ServerSocketChannel/0 $*ServerSocketChannel)) + (socket (jcall $@socket/ServerSocketChannel/0 channel)) + (endpoint (jnew $%InetSocketAddress/2 (host-to-inet4 host) (or port 0)))) + (jcall $@setReuseAddress/1 socket (if reuseaddress java:+true+ java:+false+)) + (with-mapped-conditions (socket host) + (if backlog-supplied-p + (jcall $@bind/ServerSocket/2 socket endpoint backlog) + (jcall $@bind/ServerSocket/1 socket endpoint))) + (make-stream-server-socket socket :element-type element-type))) + +;;; SOCKET-ACCEPT + +(defmethod socket-accept ((usocket stream-server-usocket) + &key (element-type 'character element-type-p)) + (with-mapped-conditions (usocket) + (let* ((client-socket (jcall $@accept/0 (socket usocket))) + (element-type (if element-type-p + element-type + (element-type usocket))) + (stream (ext:get-socket-stream client-socket :element-type element-type))) + (make-stream-socket :stream stream :socket client-socket)))) + +;;; SOCKET-CLOSE + +(defmethod socket-close ((usocket stream-server-usocket)) + (with-mapped-conditions (usocket) + (jcall $@close/ServerSocket/0 (socket usocket)))) + +(defmethod socket-close ((usocket stream-usocket)) + (with-mapped-conditions (usocket) + (close (socket-stream usocket)) + (jcall $@close/Socket/0 (socket usocket)))) + +(defmethod socket-close ((usocket datagram-usocket)) + (with-mapped-conditions (usocket) + (jcall $@close/DatagramSocket/0 (socket usocket)))) + +(defmethod socket-shutdown ((usocket stream-usocket) direction) + (with-mapped-conditions (usocket) + (ecase direction + (:input + (jcall $@shutdownInput/Socket/0 (socket usocket))) + (:output + (jcall $@shutdownOutput/Socket/0 (socket usocket)))))) + +;;; GET-LOCAL/PEER-NAME/ADDRESS/PORT + +(defmethod get-local-name ((usocket usocket)) + (values (get-local-address usocket) + (get-local-port usocket))) + +(defmethod get-peer-name ((usocket usocket)) + (values (get-peer-address usocket) + (get-peer-port usocket))) + +(defmethod get-local-address ((usocket stream-usocket)) + (get-address (jcall $@getLocalAddress/Socket/0 (socket usocket)))) + +(defmethod get-local-address ((usocket stream-server-usocket)) + (get-address (jcall $@getInetAddress/ServerSocket/0 (socket usocket)))) + +(defmethod get-local-address ((usocket datagram-usocket)) + (get-address (jcall $@getLocalAddress/DatagramSocket/0 (socket usocket)))) + +(defmethod get-peer-address ((usocket stream-usocket)) + (get-address (jcall $@getInetAddress/Socket/0 (socket usocket)))) + +(defmethod get-peer-address ((usocket datagram-usocket)) + (get-address (jcall $@getInetAddress/DatagramSocket/0 (socket usocket)))) + +(defmethod get-local-port ((usocket stream-usocket)) + (jcall $@getLocalPort/Socket/0 (socket usocket))) + +(defmethod get-local-port ((usocket stream-server-usocket)) + (jcall $@getLocalPort/ServerSocket/0 (socket usocket))) + +(defmethod get-local-port ((usocket datagram-usocket)) + (jcall $@getLocalPort/DatagramSocket/0 (socket usocket))) + +(defmethod get-peer-port ((usocket stream-usocket)) + (jcall $@getPort/Socket/0 (socket usocket))) + +(defmethod get-peer-port ((usocket datagram-usocket)) + (jcall $@getPort/DatagramSocket/0 (socket usocket))) + +;;; SOCKET-SEND & SOCKET-RECEIVE + +(defun *->byte (data) + (declare (type (unsigned-byte 8) data)) ; required by SOCKET-SEND + (jnew $%Byte/0 (if (> data 127) (- data 256) data))) + +(defun byte->* (byte &optional (element-type '(unsigned-byte 8))) + (let* ((ub8 (if (minusp byte) (+ 256 byte) byte))) + (if (eq element-type 'character) + (code-char ub8) + ub8))) + +(defmethod socket-send ((usocket datagram-usocket) buffer size &key host port (offset 0)) + (let* ((socket (socket usocket)) + (byte-array (jnew-array $*byte size)) + (packet (if (and host port) + (jnew $%DatagramPacket/5 byte-array 0 size (host-to-inet4 host) port) + (jnew $%DatagramPacket/3 byte-array 0 size)))) + ;; prepare sending data + (loop for i from offset below (+ size offset) + do (setf (jarray-ref byte-array i) (*->byte (aref buffer i)))) + (with-mapped-conditions (usocket host) + (jcall $@send/1 socket packet)))) + +;;; TODO: return-host and return-port cannot be get ... +(defmethod socket-receive ((usocket datagram-usocket) buffer length + &key (element-type '(unsigned-byte 8))) + (declare (values (simple-array (unsigned-byte 8) (*)) ; buffer + (integer 0) ; size + (unsigned-byte 32) ; host + (unsigned-byte 16))) ; port + (let* ((socket (socket usocket)) + (real-length (or length +max-datagram-packet-size+)) + (byte-array (jnew-array $*byte real-length)) + (packet (jnew $%DatagramPacket/3 byte-array 0 real-length))) + (with-mapped-conditions (usocket) + (jcall $@receive/1 socket packet)) + (let* ((receive-length (jcall $@getLength/DatagramPacket/0 packet)) + (return-buffer (or buffer (make-array receive-length :element-type element-type)))) + (loop for i from 0 below receive-length + do (setf (aref return-buffer i) + (byte->* (jarray-ref byte-array i) element-type))) + (let ((return-host (if (connected-p usocket) + (get-peer-address usocket) + (get-address (jcall $@getAddress/DatagramPacket/0 packet)))) + (return-port (if (connected-p usocket) + (get-peer-port usocket) + (jcall $@getPort/DatagramPacket/0 packet)))) + (values return-buffer + receive-length + return-host + return-port))))) + +;;; WAIT-FOR-INPUT + +(defun socket-channel-class (usocket) + (cond ((stream-usocket-p usocket) $*SocketChannel) + ((stream-server-usocket-p usocket) $*ServerSocketChannel) + ((datagram-usocket-p usocket) $*DatagramChannel))) + +(defun get-socket-channel (usocket) + (let ((method (cond ((stream-usocket-p usocket) $@getChannel/Socket/0) + ((stream-server-usocket-p usocket) $@getChannel/ServerSocket/0) + ((datagram-usocket-p usocket) $@getChannel/DatagramSocket/0)))) + (jcall method (socket usocket)))) + +(defun wait-for-input-internal (wait-list &key timeout) + (let* ((sockets (wait-list-waiters wait-list)) + (ops (logior $+op-read $+op-accept)) + (selector (jstatic $@open/Selector/0 $*Selector)) + (channels (mapcar #'get-socket-channel sockets))) + (unwind-protect + (with-mapped-conditions () + (dolist (channel channels) + (jcall $@configureBlocking/1 channel java:+false+) + (jcall $@register/2 channel selector (logand ops (jcall $@validOps/0 channel)))) + (let ((ready-count (if timeout + (jcall $@select/1 selector (truncate (* timeout 1000))) + (jcall $@select/0 selector)))) + (when (plusp ready-count) + (let* ((keys (jcall $@selectedKeys/0 selector)) + (iterator (jcall $@iterator/0 keys)) + (%wait (wait-list-%wait wait-list))) + (loop while (jcall $@hasNext/0 iterator) + do (let* ((key (jcall $@next/0 iterator)) + (channel (jcall $@channel/0 key))) + (setf (state (gethash channel %wait)) :read))))))) + (jcall $@close/Selector/0 selector) + (dolist (channel channels) + (jcall $@configureBlocking/1 channel java:+true+))))) + +;;; WAIT-LIST + +;;; NOTE from original worker (Erik): +;;; Note that even though Java has the concept of the Selector class, which +;;; remotely looks like a wait-list, it requires the sockets to be non-blocking. +;;; usocket however doesn't make any such guarantees and is therefore unable to +;;; use the concept outside of the waiting routine itself (blergh!). + +(defun %setup-wait-list (wl) + (setf (wait-list-%wait wl) + (make-hash-table :test #'equal :rehash-size 1.3d0))) + +(defun %add-waiter (wl w) + (setf (gethash (get-socket-channel w) (wait-list-%wait wl)) w)) + +(defun %remove-waiter (wl w) + (remhash (get-socket-channel w) (wait-list-%wait wl))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/allegro.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/allegro.lisp new file mode 100644 index 0000000..4af38af --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/allegro.lisp @@ -0,0 +1,228 @@ +;;;; See LICENSE for licensing information. + +(in-package :usocket) + +#+cormanlisp +(eval-when (:compile-toplevel :load-toplevel :execute) + (require :acl-socket)) + +#+allegro +(eval-when (:compile-toplevel :load-toplevel :execute) + (require :sock) + ;; for wait-for-input: + (require :process) + ;; note: the line below requires ACL 6.2+ + (require :osi)) + +(defun get-host-name () + ;; note: the line below requires ACL 7.0+ to actually *work* on windows + #+allegro (excl.osi:gethostname) + #+cormanlisp "") + +(defparameter +allegro-identifier-error-map+ + '((:address-in-use . address-in-use-error) + (:address-not-available . address-not-available-error) + (:network-down . network-down-error) + (:network-reset . network-reset-error) + (:network-unreachable . network-unreachable-error) + (:connection-aborted . connection-aborted-error) + (:connection-reset . connection-reset-error) + (:no-buffer-space . no-buffers-error) + (:shutdown . shutdown-error) + (:connection-timed-out . timeout-error) + (:connection-refused . connection-refused-error) + (:host-down . host-down-error) + (:host-unreachable . host-unreachable-error))) + +;; TODO: what's the error class of Corman Lisp? +(defun handle-condition (condition &optional (socket nil) (host-or-ip nil)) + "Dispatch correct usocket condition." + (typecase condition + #+allegro + (excl:socket-error + (let ((usock-error + (cdr (assoc (excl:stream-error-identifier condition) + +allegro-identifier-error-map+)))) + (declare (type symbol usock-error)) + (if usock-error + (cond ((subtypep usock-error 'ns-error) + (error usock-error :socket socket :host-or-ip host-or-ip)) + (t + (error usock-error :socket socket))) + (error 'unknown-error + :real-error condition + :socket socket)))))) + +(defun to-format (element-type) + (if (subtypep element-type 'character) + :text + :binary)) + +(defun socket-connect (host port &key (protocol :stream) (element-type 'character) + timeout deadline + (nodelay t) ;; nodelay == t is the ACL default + local-host local-port) + (when timeout (unsupported 'timeout 'socket-connect)) + (when deadline (unsupported 'deadline 'socket-connect)) + (when (eq nodelay :if-supported) + (setf nodelay t)) + + (let ((socket)) + (setf socket + (with-mapped-conditions (socket (or host local-host)) + (ecase protocol + (:stream + (labels ((make-socket () + (socket:make-socket :remote-host (host-to-hostname host) + :remote-port port + :local-host (when local-host + (host-to-hostname local-host)) + :local-port local-port + :format (to-format element-type) + :nodelay nodelay))) + #+allegro + (if timeout + (mp:with-timeout (timeout nil) + (make-socket)) + (make-socket)) + #+cormanlisp (make-socket))) + (:datagram + (apply #'socket:make-socket + (nconc (list :type protocol + :address-family :internet + :local-host (when local-host + (host-to-hostname local-host)) + :local-port local-port + :format (to-format element-type)) + (if (and host port) + (list :connect :active + :remote-host (host-to-hostname host) + :remote-port port) + (list :connect :passive)))))))) + (ecase protocol + (:stream + (make-stream-socket :socket socket :stream socket)) + (:datagram + (make-datagram-socket socket :connected-p (and host port t)))))) + +;; One socket close method is sufficient, +;; because socket-streams are also sockets. +(defmethod socket-close ((usocket usocket)) + "Close socket." + (with-mapped-conditions (usocket) + (close (socket usocket)))) + +(defmethod socket-shutdown ((usocket stream-usocket) direction) + (with-mapped-conditions (usocket) + (socket:shutdown (socket usocket) :direction direction))) + +(defun socket-listen (host port + &key reuseaddress + (reuse-address nil reuse-address-supplied-p) + (backlog 5) + (element-type 'character)) + ;; Allegro and OpenMCL socket interfaces bear very strong resemblence + ;; whatever you change here, change it also for OpenMCL + (let* ((reuseaddress (if reuse-address-supplied-p reuse-address reuseaddress)) + (sock (with-mapped-conditions (nil host) + (apply #'socket:make-socket + (append (list :connect :passive + :reuse-address reuseaddress + :local-port port + :backlog backlog + :format (to-format element-type) + ;; allegro now ignores :format + ) + (when (ip/= host *wildcard-host*) + (list :local-host host))))))) + (make-stream-server-socket sock :element-type element-type))) + +(defmethod socket-accept ((socket stream-server-usocket) &key element-type) + (declare (ignore element-type)) ;; allegro streams are multivalent + (let ((stream-sock + (with-mapped-conditions (socket) + (socket:accept-connection (socket socket))))) + (make-stream-socket :socket stream-sock :stream stream-sock))) + +(defmethod get-local-address ((usocket usocket)) + (hbo-to-vector-quad (socket:local-host (socket usocket)))) + +(defmethod get-peer-address ((usocket stream-usocket)) + (hbo-to-vector-quad (socket:remote-host (socket usocket)))) + +(defmethod get-local-port ((usocket usocket)) + (socket:local-port (socket usocket))) + +(defmethod get-peer-port ((usocket stream-usocket)) + #+allegro + (socket:remote-port (socket usocket))) + +(defmethod get-local-name ((usocket usocket)) + (values (get-local-address usocket) + (get-local-port usocket))) + +(defmethod get-peer-name ((usocket stream-usocket)) + (values (get-peer-address usocket) + (get-peer-port usocket))) + +#+allegro +(defmethod socket-send ((usocket datagram-usocket) buffer size &key host port (offset 0)) + (with-mapped-conditions (usocket host) + (let ((s (socket usocket))) + (socket:send-to s + (if (zerop offset) + buffer + (subseq buffer offset (+ offset size))) + size + :remote-host host + :remote-port port)))) + +#+allegro +(defmethod socket-receive ((usocket datagram-usocket) buffer length &key) + (declare (values (simple-array (unsigned-byte 8) (*)) ; buffer + (integer 0) ; size + (unsigned-byte 32) ; host + (unsigned-byte 16))) ; port + (with-mapped-conditions (usocket) + (let ((s (socket usocket))) + (socket:receive-from s length :buffer buffer :extract t)))) + +(defun get-host-by-address (address) + (with-mapped-conditions (nil address) + (socket:ipaddr-to-hostname (host-to-hbo address)))) + +(defun get-hosts-by-name (name) + ;;###FIXME: ACL has the acldns module which returns all A records + ;; only problem: it doesn't fall back to tcp (from udp) if the returned + ;; structure is too long. + (with-mapped-conditions (nil name) + (list (hbo-to-vector-quad (socket:lookup-hostname + (host-to-hostname name)))))) + +(defun %setup-wait-list (wait-list) + (declare (ignore wait-list))) + +(defun %add-waiter (wait-list waiter) + (push (socket waiter) (wait-list-%wait wait-list))) + +(defun %remove-waiter (wait-list waiter) + (setf (wait-list-%wait wait-list) + (remove (socket waiter) (wait-list-%wait wait-list)))) + +#+allegro +(defun wait-for-input-internal (wait-list &key timeout) + (with-mapped-conditions () + (let ((active-internal-sockets + (if timeout + (mp:wait-for-input-available (wait-list-%wait wait-list) + :timeout timeout) + (mp:wait-for-input-available (wait-list-%wait wait-list))))) + ;; this is quadratic, but hey, the active-internal-sockets + ;; list is very short and it's only quadratic in the length of that one. + ;; When I have more time I could recode it to something of linear + ;; complexity. + ;; [Same code is also used in openmcl.lisp] + (dolist (x active-internal-sockets) + (setf (state (gethash x (wait-list-map wait-list))) + :read)) + wait-list))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/clasp.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/clasp.lisp new file mode 100644 index 0000000..6a41eb0 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/clasp.lisp @@ -0,0 +1,158 @@ +(in-package :usocket) + +#-clasp +(progn + #-:wsock + (ffi:clines + "#include " + "#include " + "#include ") + #+:wsock + (ffi:clines + "#ifndef FD_SETSIZE" + "#define FD_SETSIZE 1024" + "#endif" + "#include ") + (ffi:clines + #+:msvc "#include " + #-:msvc "#include " + "#include ")) +(progn + #-clasp + (defun cerrno () + (ffi:c-inline () () :int + "errno" :one-liner t)) + #+clasp + (defun cerrno () + (sockets-internal:errno)) + + #-clasp + (defun fd-setsize () + (ffi:c-inline () () :fixnum + "FD_SETSIZE" :one-liner t)) + #+clasp + (defun fd-setsize () (sockets-internal:fd-setsize)) + + #-clasp + (defun fdset-alloc () + (ffi:c-inline () () :pointer-void + "ecl_alloc_atomic(sizeof(fd_set))" :one-liner t)) + #+clasp (defun fdset-alloc () (sockets-internal::alloc-atomic-sizeof-fd-set)) + + #-clasp + (defun fdset-zero (fdset) + (ffi:c-inline (fdset) (:pointer-void) :void + "FD_ZERO((fd_set*)#0)" :one-liner t)) + #+clasp(defun fdset-zero (fdset) (sockets-internal:fdset-zero fdset)) + + #-clasp + (defun fdset-set (fdset fd) + (ffi:c-inline (fdset fd) (:pointer-void :fixnum) :void + "FD_SET(#1,(fd_set*)#0)" :one-liner t)) + #+clasp(defun fdset-set (fdset fd) (sockets-internal:fdset-set fd fdset)) + + #-clasp + (defun fdset-clr (fdset fd) + (ffi:c-inline (fdset fd) (:pointer-void :fixnum) :void + "FD_CLR(#1,(fd_set*)#0)" :one-liner t)) + #+clasp(defun fdset-clr (fdset fd) (sockets-internal:fdset-clr fd fdset)) + + #-clasp + (defun fdset-fd-isset (fdset fd) + (ffi:c-inline (fdset fd) (:pointer-void :fixnum) :bool + "FD_ISSET(#1,(fd_set*)#0)" :one-liner t)) + #+clasp(defun fdset-fd-isset (fdset fd) (sockets-internal:fdset-isset fd fdset)) + + (declaim (inline cerrno + fd-setsize + fdset-alloc + fdset-zero + fdset-set + fdset-clr + fdset-fd-isset)) + #-clasp + (defun get-host-name () + (ffi:c-inline + () () :object + "{ char *buf = (char *) ecl_alloc_atomic(257); + + if (gethostname(buf,256) == 0) + @(return) = make_simple_base_string(buf); + else + @(return) = Cnil; + }" :one-liner nil :side-effects nil)) + + #+clasp + (defun get-host-name () + (sockets-internal:get-host-name)) + + #-clasp + (defun read-select (wl to-secs &optional (to-musecs 0)) + (let* ((sockets (wait-list-waiters wl)) + (rfds (wait-list-%wait wl)) + (max-fd (reduce #'(lambda (x y) + (let ((sy (sb-bsd-sockets:socket-file-descriptor + (socket y)))) + (if (< x sy) sy x))) + (cdr sockets) + :initial-value (sb-bsd-sockets:socket-file-descriptor + (socket (car sockets)))))) + (fdset-zero rfds) + (dolist (sock sockets) + (fdset-set rfds (sb-bsd-sockets:socket-file-descriptor + (socket sock)))) + (let ((count + (ffi:c-inline (to-secs to-musecs rfds max-fd) + (t :unsigned-int :pointer-void :int) + :int + " + int count; + struct timeval tv; + + if (#0 != Cnil) { + tv.tv_sec = fixnnint(#0); + tv.tv_usec = #1; + } + @(return) = select(#3 + 1, (fd_set*)#2, NULL, NULL, + (#0 != Cnil) ? &tv : NULL); +" :one-liner nil))) + (cond + ((= 0 count) + (values nil nil)) + ((< count 0) + ;; check for EINTR and EAGAIN; these should not err + (values nil (cerrno))) + (t + (dolist (sock sockets) + (when (fdset-fd-isset rfds (sb-bsd-sockets:socket-file-descriptor + (socket sock))) + (setf (state sock) :READ)))))))) + + #+clasp + (defun read-select (wl to-secs &optional (to-musecs 0)) + (let* ((sockets (wait-list-waiters wl)) + (rfds (wait-list-%wait wl)) + (max-fd (reduce #'(lambda (x y) + (let ((sy (sb-bsd-sockets:socket-file-descriptor + (socket y)))) + (if (< x sy) sy x))) + (cdr sockets) + :initial-value (sb-bsd-sockets:socket-file-descriptor + (socket (car sockets)))))) + (fdset-zero rfds) + (dolist (sock sockets) + (fdset-set rfds (sb-bsd-sockets:socket-file-descriptor + (socket sock)))) + (let ((count (sockets-internal:do-select to-secs to-musecs rfds max-fd))) + (cond + ((= 0 count) + (values nil nil)) + ((< count 0) + ;; check for EINTR and EAGAIN; these should not err + (values nil (cerrno))) + (t + (dolist (sock sockets) + (when (fdset-fd-isset rfds (sb-bsd-sockets:socket-file-descriptor + (socket sock))) + (setf (state sock) :READ)))))))) + ) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/clisp.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/clisp.lisp new file mode 100644 index 0000000..62970c9 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/clisp.lisp @@ -0,0 +1,715 @@ +;;;; See LICENSE for licensing information. + +(in-package :usocket) + +(eval-when (:compile-toplevel :load-toplevel :execute) + #-ffi + (warn "This image doesn't contain FFI package, GET-HOST-NAME won't work.") + #-(or ffi rawsock) + (warn "This image doesn't contain either FFI or RAWSOCK package, no UDP support.")) + +;; utility routine for looking up the current host name +#+ffi +(ffi:def-call-out get-host-name-internal + (:name "gethostname") + (:arguments (name (FFI:C-PTR (FFI:C-ARRAY-MAX ffi:character 256)) + :OUT :ALLOCA) + (len ffi:int)) + #+win32 (:library "WS2_32") + #-win32 (:library :default) + (:language #-win32 :stdc + #+win32 :stdc-stdcall) + (:return-type ffi:int)) + +(defun get-host-name () + #+ffi + (multiple-value-bind (retcode name) + (get-host-name-internal 256) + (when (= retcode 0) + name)) + #-ffi + "localhost") + +(defun get-host-by-address (address) + (with-mapped-conditions (nil address) + (let ((hostent (posix:resolve-host-ipaddr (host-to-hostname address)))) + (posix:hostent-name hostent)))) + +(defun get-hosts-by-name (name) + (with-mapped-conditions (nil name) + (let ((hostent (posix:resolve-host-ipaddr name))) + (mapcar #'host-to-vector-quad + (posix:hostent-addr-list hostent))))) + +;; Format: ((UNIX Windows) . CONDITION) +(defparameter +clisp-error-map+ + #-win32 + `((:EADDRINUSE . address-in-use-error) + (:EADDRNOTAVAIL . address-not-available-error) + (:EBADF . bad-file-descriptor-error) + (:ECONNREFUSED . connection-refused-error) + (:ECONNRESET . connection-reset-error) + (:ECONNABORTED . connection-aborted-error) + (:EINVAL . invalid-argument-error) + (:ENOBUFS . no-buffers-error) + (:ENOMEM . out-of-memory-error) + (:ENOTSUP . operation-not-supported-error) + (:EPERM . operation-not-permitted-error) + (:EPROTONOSUPPORT . protocol-not-supported-error) + (:ESOCKTNOSUPPORT . socket-type-not-supported-error) + (:ENETUNREACH . network-unreachable-error) + (:ENETDOWN . network-down-error) + (:ENETRESET . network-reset-error) + (:ESHUTDOWN . already-shutdown-error) + (:ETIMEDOUT . timeout-error) + (:EHOSTDOWN . host-down-error) + (:EHOSTUNREACH . host-unreachable-error) + ;; when blocked reading, and we close our socket due to a timeout. + ;; POSIX.1 says that EAGAIN and EWOULDBLOCK may have the same values. + (:EAGAIN . timeout-error) + (:EWOULDBLOCK . timeout-error)) ;linux + #+win32 + `((:WSAEADDRINUSE . address-in-use-error) + (:WSAEADDRNOTAVAIL . address-not-available-error) + (:WSAEBADF . bad-file-descriptor-error) + (:WSAECONNREFUSED . connection-refused-error) + (:WSAECONNRESET . connection-reset-error) + (:WSAECONNABORTED . connection-aborted-error) + (:WSAEINVAL . invalid-argument-error) + (:WSAENOBUFS . no-buffers-error) + (:WSAENOMEM . out-of-memory-error) + (:WSAENOTSUP . operation-not-supported-error) + (:WSAEPERM . operation-not-permitted-error) + (:WSAEPROTONOSUPPORT . protocol-not-supported-error) + (:WSAESOCKTNOSUPPORT . socket-type-not-supported-error) + (:WSAENETUNREACH . network-unreachable-error) + (:WSAENETDOWN . network-down-error) + (:WSAENETRESET . network-reset-error) + (:WSAESHUTDOWN . already-shutdown-error) + (:WSAETIMEDOUT . timeout-error) + (:WSAEHOSTDOWN . host-down-error) + (:WSAEHOSTUNREACH . host-unreachable-error))) + +(defun parse-errno (condition) + "Returns a number or keyword if it can parse what is within parens, else NIL" + (let ((s (princ-to-string condition))) + (let ((pos1 (position #\( s)) + (pos2 (position #\) s))) + ;mac: number, linux: keyword + (ignore-errors + (if (digit-char-p (char s (1+ pos1))) + (parse-integer s :start (1+ pos1) :end pos2) + (let ((*package* (find-package "KEYWORD"))) + (car (read-from-string s t nil :start pos1 :end (1+ pos2))))))))) + +(defun handle-condition (condition &optional (socket nil) (host-or-ip nil)) + "Dispatch a usocket condition instead of a CLISP specific one, if we can." + (let ((errno + (cond + ;clisp 2.49+ + ((typep condition (find-symbol "OS-STREAM-ERROR" "EXT")) + (parse-errno condition)) + ;clisp 2.49 + ((typep condition (find-symbol "SIMPLE-STREAM-ERROR" "SYSTEM")) + (car (simple-condition-format-arguments condition)))))) + (when errno + (let ((error-keyword (if (keywordp errno) errno #+ffi(os:errno errno)))) + (let ((usock-error (cdr (assoc error-keyword +clisp-error-map+)))) + (when usock-error + (if (subtypep usock-error 'error) + (cond ((subtypep usock-error 'ns-error) + (error usock-error :socket socket :host-or-ip host-or-ip)) + (t + (error usock-error :socket socket))) + (cond ((subtypep usock-error 'ns-condition) + (signal usock-error :socket socket :host-or-ip host-or-ip)) + (t + (signal usock-error :socket socket)))))))))) + +(defun socket-connect (host port &key (protocol :stream) (element-type 'character) + timeout deadline (nodelay t nodelay-specified) + local-host local-port) + (declare (ignorable timeout local-host local-port)) + (when deadline (unsupported 'deadline 'socket-connect)) + (when (and nodelay-specified + (not (eq nodelay :if-supported))) + (unsupported 'nodelay 'socket-connect)) + (case protocol + (:stream + (let ((socket) + (hostname (host-to-hostname host))) + (with-mapped-conditions (socket host) + (setf socket + (if timeout + (socket:socket-connect port hostname + :element-type element-type + :buffered t + :timeout timeout) + (socket:socket-connect port hostname + :element-type element-type + :buffered t)))) + (make-stream-socket :socket socket + :stream socket))) ;; the socket is a stream too + (:datagram + #+(or rawsock ffi) + (with-mapped-conditions (nil (or host local-host)) + (socket-create-datagram (or local-port *auto-port*) + :local-host (or local-host *wildcard-host*) + :remote-host (and host (host-to-vector-quad host)) + :remote-port port)) + #-(or rawsock ffi) + (unsupported '(protocol :datagram) 'socket-connect)))) + +(defun socket-listen (host port + &key reuseaddress + (reuse-address nil reuse-address-supplied-p) + (backlog 5) + (element-type 'character)) + ;; clisp 2.39 sets SO_REUSEADDRESS to 1 by default; no need to + ;; to explicitly turn it on; unfortunately, there's no way to turn it off... + (declare (ignore reuseaddress reuse-address reuse-address-supplied-p)) + (let ((sock (apply #'socket:socket-server + (append (list port + :backlog backlog) + (when (ip/= host *wildcard-host*) + (list :interface host)))))) + (with-mapped-conditions (nil host) + (make-stream-server-socket sock :element-type element-type)))) + +(defmethod socket-accept ((socket stream-server-usocket) &key element-type) + (let ((stream + (with-mapped-conditions (socket) + (socket:socket-accept (socket socket) + :element-type (or element-type + (element-type socket)))))) + (make-stream-socket :socket stream + :stream stream))) + +;; Only one close method required: +;; sockets and their associated streams +;; are the same object +(defmethod socket-close ((usocket usocket)) + "Close socket." + (with-mapped-conditions (usocket) + (close (socket usocket)))) + +(defmethod socket-close ((usocket stream-server-usocket)) + (socket:socket-server-close (socket usocket))) + +(defmethod socket-shutdown ((usocket stream-usocket) direction) + (with-mapped-conditions (usocket) + (socket:socket-stream-shutdown (socket usocket) direction))) + +(defmethod get-local-name ((usocket stream-usocket)) + (multiple-value-bind + (address port) + (socket:socket-stream-local (socket usocket) t) + (values (dotted-quad-to-vector-quad address) port))) + +(defmethod get-local-name ((usocket stream-server-usocket)) + (values (get-local-address usocket) + (get-local-port usocket))) + +(defmethod get-peer-name ((usocket stream-usocket)) + (multiple-value-bind + (address port) + (socket:socket-stream-peer (socket usocket) t) + (values (dotted-quad-to-vector-quad address) port))) + +(defmethod get-local-address ((usocket usocket)) + (nth-value 0 (get-local-name usocket))) + +(defmethod get-local-address ((usocket stream-server-usocket)) + (dotted-quad-to-vector-quad + (socket:socket-server-host (socket usocket)))) + +(defmethod get-peer-address ((usocket usocket)) + (nth-value 0 (get-peer-name usocket))) + +(defmethod get-local-port ((usocket usocket)) + (nth-value 1 (get-local-name usocket))) + +(defmethod get-local-port ((usocket stream-server-usocket)) + (socket:socket-server-port (socket usocket))) + +(defmethod get-peer-port ((usocket usocket)) + (nth-value 1 (get-peer-name usocket))) + +(defun %setup-wait-list (wait-list) + (declare (ignore wait-list))) + +(defun %add-waiter (wait-list waiter) + ;; clisp's #'socket-status takes a list whose elts look either like, + ;; (socket-stream direction . x) or like, + ;; (socket-server . x) + ;; and it replaces the x's. + (push (cons (socket waiter) + (cond ((stream-usocket-p waiter) (cons NIL NIL)) + (t NIL))) + (wait-list-%wait wait-list))) + +(defun %remove-waiter (wait-list waiter) + (setf (wait-list-%wait wait-list) + (remove (socket waiter) (wait-list-%wait wait-list) :key #'car))) + +(defmethod wait-for-input-internal (wait-list &key timeout) + (with-mapped-conditions () + (multiple-value-bind + (secs musecs) + (split-timeout (or timeout 1)) + (dolist (x (wait-list-%wait wait-list)) + (when (consp (cdr x)) ;it's a socket-stream not socket-server + (setf (cadr x) :INPUT))) + (let* ((request-list (wait-list-%wait wait-list)) + (status-list (if timeout + (socket:socket-status request-list secs musecs) + (socket:socket-status request-list))) + (sockets (wait-list-waiters wait-list))) + (do* ((x (pop sockets) (pop sockets)) + (y (cdr (last (pop status-list))) (cdr (last (pop status-list))))) + ((null x)) + (when (member y '(T :INPUT :EOF)) + (setf (state x) :READ))) + wait-list)))) + +;;; +;;; UDP/Datagram sockets (RAWSOCK version) +;;; + +#+rawsock +(progn + (defun make-sockaddr_in () + (make-array 16 :element-type '(unsigned-byte 8) :initial-element 0)) + + (declaim (inline fill-sockaddr_in)) + (defun fill-sockaddr_in (sockaddr_in ip port) + (port-to-octet-buffer port sockaddr_in) + (ip-to-octet-buffer ip sockaddr_in :start 2) + sockaddr_in) + + (defun socket-create-datagram (local-port + &key (local-host *wildcard-host*) + remote-host + remote-port) + (let ((sock (rawsock:socket :inet :dgram 0)) + (lsock_addr (fill-sockaddr_in (make-sockaddr_in) + local-host local-port)) + (rsock_addr (when remote-host + (fill-sockaddr_in (make-sockaddr_in) + remote-host (or remote-port + local-port))))) + (rawsock:bind sock (rawsock:make-sockaddr :inet lsock_addr)) + (when rsock_addr + (rawsock:connect sock (rawsock:make-sockaddr :inet rsock_addr))) + (make-datagram-socket sock :connected-p (if rsock_addr t nil)))) + + (defmethod socket-receive ((socket datagram-usocket) buffer length &key) + "Returns the buffer, the number of octets copied into the buffer (received) +and the address of the sender as values." + (let* ((sock (socket socket)) + (sockaddr (rawsock:make-sockaddr :inet)) + (real-length (or length +max-datagram-packet-size+)) + (real-buffer (or buffer + (make-array real-length + :element-type '(unsigned-byte 8))))) + (let ((rv (rawsock:recvfrom sock real-buffer sockaddr + :start 0 :end real-length)) + (host 0) (port 0)) + (unless (connected-p socket) + (let ((data (rawsock:sockaddr-data sockaddr))) + (setq host (ip-from-octet-buffer data :start 4) + port (port-from-octet-buffer data :start 2)))) + (values (if buffer real-buffer (subseq real-buffer 0 rv)) + rv + host + port)))) + + (defmethod socket-send ((socket datagram-usocket) buffer size &key host port (offset 0)) + "Returns the number of octets sent." + (let* ((sock (socket socket)) + (sockaddr (when (and host port) + (rawsock:make-sockaddr :inet + (fill-sockaddr_in + (make-sockaddr_in) + (host-byte-order host) + port)))) + (real-size (min size +max-datagram-packet-size+)) + (real-buffer (if (typep buffer '(simple-array (unsigned-byte 8) (*))) + buffer + (make-array real-size + :element-type '(unsigned-byte 8) + :initial-contents (subseq buffer 0 real-size)))) + (rv (if (and host port) + (rawsock:sendto sock real-buffer sockaddr + :start offset + :end (+ offset real-size)) + (rawsock:send sock real-buffer + :start offset + :end (+ offset real-size))))) + rv)) + + (defmethod socket-close ((usocket datagram-usocket)) + (rawsock:sock-close (socket usocket))) + + (declaim (inline get-socket-name)) + (defun get-socket-name (socket function) + (let ((sockaddr (rawsock:make-sockaddr :inet (make-sockaddr_in)))) + (funcall function socket sockaddr) + (let ((data (rawsock:sockaddr-data sockaddr))) + (values (hbo-to-vector-quad (ip-from-octet-buffer data :start 2)) + (port-from-octet-buffer data :start 0))))) + + (defmethod get-local-name ((usocket datagram-usocket)) + (get-socket-name (socket usocket) 'rawsock:getsockname)) + + (defmethod get-peer-name ((usocket datagram-usocket)) + (get-socket-name (socket usocket) 'rawsock:getpeername)) + +) ; progn + +;;; +;;; UDP/Datagram sockets (FFI version) +;;; + +#+(and ffi (not rawsock)) +(progn + ;; C primitive types + (ffi:def-c-type socklen_t ffi:uint32) + + ;; C structures + (ffi:def-c-struct sockaddr + #+macos (sa_len ffi:uint8) + (sa_family #-macos ffi:ushort + #+macos ffi:uint8) + (sa_data (ffi:c-array ffi:char 14))) + + (ffi:def-c-struct sockaddr_in + #+macos (sin_len ffi:uint8) + (sin_family #-macos ffi:short + #+macos ffi:uint8) + (sin_port #-macos ffi:ushort + #+macos ffi:uint16) + (sin_addr ffi:uint32) + (sin_zero (ffi:c-array ffi:char 8))) + + (ffi:def-c-struct timeval + (tv_sec ffi:long) + (tv_usec ffi:long)) + + ;; foreign functions + (ffi:def-call-out %sendto (:name "sendto") + (:arguments (socket ffi:int) + (buffer ffi:c-pointer) + (length ffi:int) + (flags ffi:int) + (address (ffi:c-ptr sockaddr)) + (address-len ffi:int)) + #+win32 (:library "WS2_32") + #-win32 (:library :default) + (:language #-win32 :stdc + #+win32 :stdc-stdcall) + (:return-type ffi:int)) + + (ffi:def-call-out %send (:name "send") + (:arguments (socket ffi:int) + (buffer ffi:c-pointer) + (length ffi:int) + (flags ffi:int)) + #+win32 (:library "WS2_32") + #-win32 (:library :default) + (:language #-win32 :stdc + #+win32 :stdc-stdcall) + (:return-type ffi:int)) + + (ffi:def-call-out %recvfrom (:name "recvfrom") + (:arguments (socket ffi:int) + (buffer ffi:c-pointer) + (length ffi:int) + (flags ffi:int) + (address (ffi:c-ptr sockaddr) :in-out) + (address-len (ffi:c-ptr ffi:int) :in-out)) + #+win32 (:library "WS2_32") + #-win32 (:library :default) + (:language #-win32 :stdc + #+win32 :stdc-stdcall) + (:return-type ffi:int)) + + (ffi:def-call-out %socket (:name "socket") + (:arguments (family ffi:int) + (type ffi:int) + (protocol ffi:int)) + #+win32 (:library "WS2_32") + #-win32 (:library :default) + (:language #-win32 :stdc + #+win32 :stdc-stdcall) + (:return-type ffi:int)) + + (ffi:def-call-out %connect (:name "connect") + (:arguments (socket ffi:int) + (address (ffi:c-ptr sockaddr) :in) + (address_len socklen_t)) + #+win32 (:library "WS2_32") + #-win32 (:library :default) + (:language #-win32 :stdc + #+win32 :stdc-stdcall) + (:return-type ffi:int)) + + (ffi:def-call-out %bind (:name "bind") + (:arguments (socket ffi:int) + (address (ffi:c-ptr sockaddr) :in) + (address_len socklen_t)) + #+win32 (:library "WS2_32") + #-win32 (:library :default) + (:language #-win32 :stdc + #+win32 :stdc-stdcall) + (:return-type ffi:int)) + + (ffi:def-call-out %close (:name #-win32 "close" #+win32 "closesocket") + (:arguments (socket ffi:int)) + #+win32 (:library "WS2_32") + #-win32 (:library :default) + (:language #-win32 :stdc + #+win32 :stdc-stdcall) + (:return-type ffi:int)) + + (ffi:def-call-out %getsockopt (:name "getsockopt") + (:arguments (sockfd ffi:int) + (level ffi:int) + (optname ffi:int) + (optval ffi:c-pointer) + (optlen (ffi:c-ptr socklen_t) :out)) + #+win32 (:library "WS2_32") + #-win32 (:library :default) + (:language #-win32 :stdc + #+win32 :stdc-stdcall) + (:return-type ffi:int)) + + (ffi:def-call-out %setsockopt (:name "setsockopt") + (:arguments (sockfd ffi:int) + (level ffi:int) + (optname ffi:int) + (optval ffi:c-pointer) + (optlen socklen_t)) + #+win32 (:library "WS2_32") + #-win32 (:library :default) + (:language #-win32 :stdc + #+win32 :stdc-stdcall) + (:return-type ffi:int)) + + (ffi:def-call-out %htonl (:name "htonl") + (:arguments (hostlong ffi:uint32)) + #+win32 (:library "WS2_32") + #-win32 (:library :default) + (:language #-win32 :stdc + #+win32 :stdc-stdcall) + (:return-type ffi:uint32)) + + (ffi:def-call-out %htons (:name "htons") + (:arguments (hostshort ffi:uint16)) + #+win32 (:library "WS2_32") + #-win32 (:library :default) + (:language #-win32 :stdc + #+win32 :stdc-stdcall) + (:return-type ffi:uint16)) + + (ffi:def-call-out %ntohl (:name "ntohl") + (:arguments (netlong ffi:uint32)) + #+win32 (:library "WS2_32") + #-win32 (:library :default) + (:language #-win32 :stdc + #+win32 :stdc-stdcall) + (:return-type ffi:uint32)) + + (ffi:def-call-out %ntohs (:name "ntohs") + (:arguments (netshort ffi:uint16)) + #+win32 (:library "WS2_32") + #-win32 (:library :default) + (:language #-win32 :stdc + #+win32 :stdc-stdcall) + (:return-type ffi:uint16)) + + (ffi:def-call-out %getsockname (:name "getsockname") + (:arguments (sockfd ffi:int) + (localaddr (ffi:c-ptr sockaddr) :in-out) + (addrlen (ffi:c-ptr socklen_t) :in-out)) + #+win32 (:library "WS2_32") + #-win32 (:library :default) + (:language #-win32 :stdc + #+win32 :stdc-stdcall) + (:return-type ffi:int)) + + (ffi:def-call-out %getpeername (:name "getpeername") + (:arguments (sockfd ffi:int) + (peeraddr (ffi:c-ptr sockaddr) :in-out) + (addrlen (ffi:c-ptr socklen_t) :in-out)) + #+win32 (:library "WS2_32") + #-win32 (:library :default) + (:language #-win32 :stdc + #+win32 :stdc-stdcall) + (:return-type ffi:int)) + + ;; socket constants + (defconstant +socket-af-inet+ 2) + (defconstant +socket-sock-dgram+ 2) + (defconstant +socket-ip-proto-udp+ 17) + + (defconstant +sockopt-so-rcvtimeo+ #-linux #x1006 #+linux 20 "Socket receive timeout") + + (defparameter *length-of-sockaddr_in* (ffi:sizeof 'sockaddr_in)) + + (declaim (inline fill-sockaddr_in)) + (defun fill-sockaddr_in (sockaddr host port) + (let ((hbo (host-to-hbo host))) + (ffi:with-c-place (place sockaddr) + #+macos + (setf (ffi:slot place 'sin_len) *length-of-sockaddr_in*) + (setf (ffi:slot place 'sin_family) +socket-af-inet+ + (ffi:slot place 'sin_port) (%htons port) + (ffi:slot place 'sin_addr) (%htonl hbo))) + sockaddr)) + + (defun socket-create-datagram (local-port + &key (local-host *wildcard-host*) + remote-host + remote-port) + (let ((sock (%socket +socket-af-inet+ +socket-sock-dgram+ +socket-ip-proto-udp+)) + (lsock_addr (fill-sockaddr_in (ffi:allocate-shallow 'sockaddr_in) + local-host local-port)) + (rsock_addr (when remote-host + (fill-sockaddr_in (ffi:allocate-shallow 'sockaddr_in) + remote-host (or remote-port local-port))))) + (unless (plusp sock) + (error "SOCKET-CREATE-DATAGRAM ERROR (socket): ~A" (os:errno))) + (unwind-protect + (let ((rv (%bind sock (ffi:cast (ffi:foreign-value lsock_addr) 'sockaddr) + *length-of-sockaddr_in*))) + (unless (zerop rv) + (error "SOCKET-CREATE-DATAGRAM ERROR (bind): ~A" (os:errno))) + (when rsock_addr + (let ((rv (%connect sock + (ffi:cast (ffi:foreign-value rsock_addr) 'sockaddr) + *length-of-sockaddr_in*))) + (unless (zerop rv) + (error "SOCKET-CREATE-DATAGRAM ERROR (connect): ~A" (os:errno)))))) + (ffi:foreign-free lsock_addr) + (when remote-host + (ffi:foreign-free rsock_addr))) + (make-datagram-socket sock :connected-p (if rsock_addr t nil)))) + + (defun finalize-datagram-usocket (object) + (when (datagram-usocket-p object) + (socket-close object))) + + (defmethod initialize-instance :after ((usocket datagram-usocket) &key) + (setf (slot-value usocket 'recv-buffer) + (ffi:allocate-shallow 'ffi:uint8 :count +max-datagram-packet-size+)) + ;; finalize the object + (ext:finalize usocket 'finalize-datagram-usocket)) + + (defmethod socket-close ((usocket datagram-usocket)) + (with-slots (recv-buffer socket) usocket + (ffi:foreign-free recv-buffer) + (zerop (%close socket)))) + + (defmethod socket-receive ((usocket datagram-usocket) buffer length &key) + (let ((remote-address (ffi:allocate-shallow 'sockaddr_in)) + (remote-address-length (ffi:allocate-shallow 'ffi:int)) + nbytes (host 0) (port 0)) + (setf (ffi:foreign-value remote-address-length) + *length-of-sockaddr_in*) + (unwind-protect + (multiple-value-bind (n address address-length) + (%recvfrom (socket usocket) + (ffi:foreign-address (slot-value usocket 'recv-buffer)) + +max-datagram-packet-size+ + 0 ; flags + (ffi:cast (ffi:foreign-value remote-address) 'sockaddr) + (ffi:foreign-value remote-address-length)) + (when (minusp n) + (error "SOCKET-RECEIVE ERROR: ~A" (os:errno))) + (setq nbytes n) + (when (= address-length *length-of-sockaddr_in*) + (let ((data (sockaddr-sa_data address))) + (setq host (ip-from-octet-buffer data :start 2) + port (port-from-octet-buffer data)))) + (cond ((plusp n) + (let ((return-buffer (ffi:foreign-value (slot-value usocket 'recv-buffer)))) + (if buffer ; replace exist buffer of create new return buffer + (let ((end-1 (min (or length (length buffer)) +max-datagram-packet-size+)) + (end-2 (min n +max-datagram-packet-size+))) + (replace buffer return-buffer :end1 end-1 :end2 end-2)) + (setq buffer (subseq return-buffer 0 (min n +max-datagram-packet-size+)))))) + ((zerop n)))) + (ffi:foreign-free remote-address) + (ffi:foreign-free remote-address-length)) + (values buffer nbytes host port))) + + ;; implementation note: different from socket-receive, we know how many bytes we want to send everytime, + ;; so, a send buffer will not needed, and if there is a buffer, it's hard to fill its content like those + ;; in LispWorks. So, we allocate new foreign buffer for holding data (unknown sequence subtype) every time. + ;; + ;; I don't know if anyone is watching my coding work, but I think this design is reasonable for CLISP. + (defmethod socket-send ((usocket datagram-usocket) buffer size &key host port (offset 0)) + (declare (type sequence buffer) + (type (integer 0 *) size offset)) + (let ((remote-address + (when (and host port) + (fill-sockaddr_in (ffi:allocate-shallow 'sockaddr_in) host port))) + (send-buffer + (ffi:allocate-deep 'ffi:uint8 + (if (zerop offset) + buffer + (subseq buffer offset (+ offset size))) + :count size :read-only t)) + (real-size (min size +max-datagram-packet-size+)) + (nbytes 0)) + (unwind-protect + (let ((n (if remote-address + (%sendto (socket usocket) + (ffi:foreign-address send-buffer) + real-size + 0 ; flags + (ffi:cast (ffi:foreign-value remote-address) 'sockaddr) + *length-of-sockaddr_in*) + (%send (socket usocket) + (ffi:foreign-address send-buffer) + real-size + 0)))) + (cond ((plusp n) + (setq nbytes n)) + ((zerop n) + (setq nbytes n)) + (t (error "SOCKET-SEND ERROR: ~A" (os:errno))))) + (ffi:foreign-free send-buffer) + (when remote-address + (ffi:foreign-free remote-address)) + nbytes))) + + (declaim (inline get-socket-name)) + (defun get-socket-name (socket function) + (let ((address (ffi:allocate-shallow 'sockaddr_in)) + (address-length (ffi:allocate-shallow 'ffi:int)) + (host 0) (port 0)) + (setf (ffi:foreign-value address-length) *length-of-sockaddr_in*) + (unwind-protect + (multiple-value-bind (rv return-address return-address-length) + (funcall function socket + (ffi:cast (ffi:foreign-value address) 'sockaddr) + (ffi:foreign-value address-length)) + (declare (ignore return-address-length)) + (if (zerop rv) + (let ((data (sockaddr-sa_data return-address))) + (setq host (ip-from-octet-buffer data :start 2) + port (port-from-octet-buffer data))) + (error "GET-SOCKET-NAME ERROR: ~A" (os:errno)))) + (ffi:foreign-free address) + (ffi:foreign-free address-length)) + (values (hbo-to-vector-quad host) port))) + + (defmethod get-local-name ((usocket datagram-usocket)) + (get-socket-name (socket usocket) '%getsockname)) + + (defmethod get-peer-name ((usocket datagram-usocket)) + (get-socket-name (socket usocket) '%getpeername)) + +) ; progn diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/clozure.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/clozure.lisp new file mode 100644 index 0000000..7a1d620 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/clozure.lisp @@ -0,0 +1,73 @@ +;;;; See LICENSE for licensing information. + +;;;; Functions for CCL 1.11 (IPv6) only, see openmcl.lisp for rest of functions. + +(in-package :usocket) + +#+ipv6 +(defun socket-connect (host port &key (protocol :stream) element-type + timeout deadline nodelay + local-host local-port) + (when (eq nodelay :if-supported) + (setf nodelay t)) + (with-mapped-conditions (nil host) + (let* ((remote (when (and host port) + (openmcl-socket:resolve-address :host (host-to-hostname host) + :port port + :socket-type protocol))) + (local (when (and local-host local-port) + (openmcl-socket:resolve-address :host (host-to-hostname local-host) + :port local-port + :socket-type protocol))) + (mcl-sock (apply #'openmcl-socket:make-socket + `(:type ,protocol + ,@(when (or remote local) + `(:address-family ,(openmcl-socket:socket-address-family (or remote local)))) + ,@(when remote + `(:remote-address ,remote)) + ,@(when local + `(:local-address ,local)) + :format ,(to-format element-type protocol) + :external-format ,ccl:*default-external-format* + :deadline ,deadline + :nodelay ,nodelay + :connect-timeout ,timeout + :input-timeout ,timeout)))) + (ecase protocol + (:stream + (make-stream-socket :stream mcl-sock :socket mcl-sock)) + (:datagram + (make-datagram-socket mcl-sock :connected-p (and remote t))))))) + +#+ipv6 +(defun socket-listen (host port + &key + (reuse-address nil reuse-address-supplied-p) + (reuseaddress (when reuse-address-supplied-p reuse-address)) + (backlog 5) + (element-type 'character)) + (let ((local-address (openmcl-socket:resolve-address :host (host-to-hostname host) + :port port :connect :passive))) + (with-mapped-conditions (nil host) + (make-stream-server-socket + (openmcl-socket:make-socket :connect :passive + :address-family (openmcl-socket:socket-address-family local-address) + :local-address local-address + :reuse-address reuseaddress + :backlog backlog + :format (to-format element-type :stream)) + :element-type element-type)))) + +#+ipv6 +(defmethod socket-send ((usocket datagram-usocket) buffer size &key host port (offset 0)) + (let* ((ccl-socket (socket usocket)) + (socket-keys (ccl::socket-keys ccl-socket))) + (with-mapped-conditions (usocket host) + (if (and host port) + (openmcl-socket:send-to ccl-socket buffer size + :remote-host (host-to-hostname host) + :remote-port port + :offset offset) + (openmcl-socket:send-to ccl-socket buffer size + :remote-address (getf socket-keys :remote-address) + :offset offset))))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/cmucl.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/cmucl.lisp new file mode 100644 index 0000000..89627de --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/cmucl.lisp @@ -0,0 +1,298 @@ +;;;; See LICENSE for licensing information. + +(in-package :usocket) + +#+win32 +(defun remap-for-win32 (z) + (mapcar #'(lambda (x) + (cons (mapcar #'(lambda (y) + (+ 10000 y)) + (car x)) + (cdr x))) + z)) + +(defparameter +cmucl-error-map+ + #+win32 + (append (remap-for-win32 +unix-errno-condition-map+) + (remap-for-win32 +unix-errno-error-map+)) + #-win32 + (append +unix-errno-condition-map+ + +unix-errno-error-map+)) + +(defun cmucl-map-socket-error (err &key condition socket host-or-ip) + (let ((usock-error + (cdr (assoc err +cmucl-error-map+ :test #'member)))) + (if usock-error + (if (subtypep usock-error 'error) + (cond ((subtypep usock-error 'ns-error) + (error usock-error :socket socket :host-or-ip host-or-ip)) + (t + (error usock-error :socket socket))) + (cond ((subtypep usock-error 'ns-condition) + (signal usock-error :socket socket :host-or-ip host-or-ip)) + (t + (signal usock-error :socket socket)))) + (error 'unknown-error + :socket socket + :real-error condition)))) + +;; CMUCL error handling is brain-dead: it doesn't preserve any +;; information other than the OS error string from which the +;; error can be determined. The OS error string isn't good enough +;; given that it may have been localized (l10n). +;; +;; The above applies to versions pre 19b; 19d and newer are expected to +;; contain even better error reporting. +;; +;; +;; Just catch the errors and encapsulate them in an unknown-error +(defun handle-condition (condition &optional (socket nil) (host-or-ip nil)) + "Dispatch correct usocket condition." + (typecase condition + (ext::socket-error (cmucl-map-socket-error (ext::socket-errno condition) + :socket socket + :condition condition + :host-or-ip host-or-ip)))) + +(defun socket-connect (host port &key (protocol :stream) (element-type 'character) + timeout deadline (nodelay t nodelay-specified) + (local-host nil local-host-p) + (local-port nil local-port-p) + &aux + (local-bind-p (fboundp 'ext::bind-inet-socket))) + (when timeout (unsupported 'timeout 'socket-connect)) + (when deadline (unsupported 'deadline 'socket-connect)) + (when (and nodelay-specified + (not (eq nodelay :if-supported))) + (unsupported 'nodelay 'socket-connect)) + (when (and local-host-p (not local-bind-p)) + (unsupported 'local-host 'socket-connect :minimum "Snapshot 2008-08 (19E)")) + (when (and local-port-p (not local-bind-p)) + (unsupported 'local-port 'socket-connect :minimum "Snapshot 2008-08 (19E)")) + + (let ((socket)) + (ecase protocol + (:stream + (setf socket + (let ((args (list (host-to-hbo host) port protocol))) + (when (and local-bind-p (or local-host-p local-port-p)) + (nconc args (list :local-host (when local-host + (host-to-hbo local-host)) + :local-port local-port))) + (with-mapped-conditions (socket host) + (apply #'ext:connect-to-inet-socket args)))) + (if socket + (let* ((stream (sys:make-fd-stream socket :input t :output t + :element-type element-type + :buffering :full)) + ;;###FIXME the above line probably needs an :external-format + (usocket (make-stream-socket :socket socket + :stream stream))) + usocket) + (let ((err (unix:unix-errno))) + (when err (cmucl-map-socket-error err))))) + (:datagram + (setf socket + (if (and host port) + (let ((args (list (host-to-hbo host) port protocol))) + (when (and local-bind-p (or local-host-p local-port-p)) + (nconc args (list :local-host (when local-host + (host-to-hbo local-host)) + :local-port local-port))) + (with-mapped-conditions (socket (or host local-host)) + (apply #'ext:connect-to-inet-socket args))) + (if (or local-host-p local-port-p) + (with-mapped-conditions (socket (or host local-host)) + (apply #'ext:create-inet-listener + (nconc (list (or local-port 0) protocol) + (when (and local-host-p + (ip/= local-host *wildcard-host*)) + (list :host (host-to-hbo local-host)))))) + (with-mapped-conditions (socket (or host local-host)) + (ext:create-inet-socket protocol))))) + (if socket + (let ((usocket (make-datagram-socket socket :connected-p (and host port t)))) + (ext:finalize usocket #'(lambda () (when (%open-p usocket) + (ext:close-socket socket)))) + usocket) + (let ((err (unix:unix-errno))) + (when err (cmucl-map-socket-error err)))))))) + +(defun socket-listen (host port + &key reuseaddress + (reuse-address nil reuse-address-supplied-p) + (backlog 5) + (element-type 'character)) + (let* ((reuseaddress (if reuse-address-supplied-p reuse-address reuseaddress)) + (server-sock + (with-mapped-conditions (nil host) + (apply #'ext:create-inet-listener + (nconc (list port :stream + :backlog backlog + :reuse-address reuseaddress) + (when (ip/= host *wildcard-host*) + (list :host + (host-to-hbo host)))))))) + (make-stream-server-socket server-sock :element-type element-type))) + +(defmethod socket-accept ((usocket stream-server-usocket) &key element-type) + (with-mapped-conditions (usocket) + (let* ((sock (ext:accept-tcp-connection (socket usocket))) + (stream (sys:make-fd-stream sock :input t :output t + :element-type (or element-type + (element-type usocket)) + :buffering :full))) + (make-stream-socket :socket sock :stream stream)))) + +;; Sockets and socket streams are represented +;; by different objects. Be sure to close the +;; socket stream when closing a stream socket. +(defmethod socket-close ((usocket stream-usocket)) + "Close socket." + (with-mapped-conditions (usocket) + (close (socket-stream usocket)))) + +(defmethod socket-close ((usocket usocket)) + "Close socket." + (with-mapped-conditions (usocket) + (ext:close-socket (socket usocket)))) + +(defmethod socket-close :after ((socket datagram-usocket)) + (setf (%open-p socket) nil)) + +#+unicode +(defun %unix-send (fd buffer length flags) + (alien:alien-funcall + (alien:extern-alien "send" + (function c-call:int + c-call:int + system:system-area-pointer + c-call:int + c-call:int)) + fd + (system:vector-sap buffer) + length + flags)) + +(defmethod socket-shutdown ((usocket usocket) direction) + (with-mapped-conditions (usocket) + (ext:inet-shutdown (socket usocket) (ecase direction + (:input ext:shut-rd) + (:output ext:shut-wr))))) + +(defmethod socket-send ((usocket datagram-usocket) buffer size &key host port (offset 0) + &aux (real-buffer (if (zerop offset) + buffer + (subseq buffer offset (+ offset size))))) + (with-mapped-conditions (usocket host) + (if (and host port) + (ext:inet-sendto (socket usocket) real-buffer size (host-to-hbo host) port) + #-unicode + (unix:unix-send (socket usocket) real-buffer size 0) + #+unicode + (%unix-send (socket usocket) real-buffer size 0)))) + +(defmethod socket-receive ((usocket datagram-usocket) buffer length &key) + (declare (values (simple-array (unsigned-byte 8) (*)) ; buffer + (integer 0) ; size + (unsigned-byte 32) ; host + (unsigned-byte 16))) ; port + (let ((real-buffer (or buffer + (make-array length :element-type '(unsigned-byte 8)))) + (real-length (or length + (length buffer)))) + (multiple-value-bind (nbytes remote-host remote-port) + (with-mapped-conditions (usocket) + (ext:inet-recvfrom (socket usocket) real-buffer real-length)) + (values real-buffer nbytes remote-host remote-port)))) + +(defmethod get-local-name ((usocket usocket)) + (multiple-value-bind + (address port) + (ext:get-socket-host-and-port (socket usocket)) + (values (hbo-to-vector-quad address) port))) + +(defmethod get-peer-name ((usocket stream-usocket)) + (multiple-value-bind + (address port) + (ext:get-peer-host-and-port (socket usocket)) + (values (hbo-to-vector-quad address) port))) + +(defmethod get-local-address ((usocket usocket)) + (nth-value 0 (get-local-name usocket))) + +(defmethod get-peer-address ((usocket stream-usocket)) + (nth-value 0 (get-peer-name usocket))) + +(defmethod get-local-port ((usocket usocket)) + (nth-value 1 (get-local-name usocket))) + +(defmethod get-peer-port ((usocket stream-usocket)) + (nth-value 1 (get-peer-name usocket))) + + +(defun lookup-host-entry (host) + (multiple-value-bind + (entry errno) + (ext:lookup-host-entry host) + (if entry + entry + ;;###The constants below work on *most* OSes, but are defined as the + ;; constants mentioned in C + (let ((exception + (second (assoc errno + '((1 ns-host-not-found-error) ;; HOST_NOT_FOUND + (2 ns-no-recovery-error) ;; NO_DATA + (3 ns-no-recovery-error) ;; NO_RECOVERY + (4 ns-try-again-condition)))))) ;; TRY_AGAIN + (when exception + (error exception)))))) + + +(defun get-host-by-address (address) + (handler-case (ext:host-entry-name + (lookup-host-entry (host-byte-order address))) + (condition (condition) (handle-condition condition address)))) + +(defun get-hosts-by-name (name) + (handler-case (mapcar #'hbo-to-vector-quad + (ext:host-entry-addr-list + (lookup-host-entry name))) + (condition (condition) (handle-condition condition name)))) + +(defun get-host-name () + (unix:unix-gethostname)) + +(defun %setup-wait-list (wait-list) + (declare (ignore wait-list))) + +(defun %add-waiter (wait-list waiter) + (push (socket waiter) (wait-list-%wait wait-list))) + +(defun %remove-waiter (wait-list waiter) + (setf (wait-list-%wait wait-list) + (remove (socket waiter) (wait-list-%wait wait-list)))) + +(defun wait-for-input-internal (wait-list &key timeout) + (with-mapped-conditions () + (alien:with-alien ((rfds (alien:struct unix:fd-set))) + (unix:fd-zero rfds) + (dolist (socket (wait-list-%wait wait-list)) + (unix:fd-set socket rfds)) + (multiple-value-bind + (secs musecs) + (split-timeout (or timeout 1)) + (multiple-value-bind (count err) + (unix:unix-fast-select (1+ (reduce #'max + (wait-list-%wait wait-list))) + (alien:addr rfds) nil nil + (when timeout secs) musecs) + (declare (ignore err)) + (if (<= 0 count) + ;; process the result... + (dolist (x (wait-list-waiters wait-list)) + (when (unix:fd-isset (socket x) rfds) + (setf (state x) :READ))) + (progn + ;;###FIXME generate an error, except for EINTR + ))))))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/ecl.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/ecl.lisp new file mode 100644 index 0000000..28ddd5a --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/ecl.lisp @@ -0,0 +1,152 @@ +;;;; -*- Mode: Lisp -*- + +;;;; Foreign functions defined by ECL's DFFI, used for #+ecl-bytecmp only. +;;;; See LICENSE for licensing information. + +(in-package :usocket) + +#+(and ecl-bytecmp windows) +(eval-when (:load-toplevel :execute) + (ffi:load-foreign-library "ws2_32.dll" :module "ws2_32")) + +#+(and ecl-bytecmp windows) +(progn + (ffi:def-function ("gethostname" c-gethostname) + ((name (* :unsigned-char)) + (len :int)) + :returning :int + :module "ws2_32") + + (defun get-host-name () + "Returns the hostname" + (ffi:with-foreign-object (name '(:array :unsigned-char 256)) + (when (zerop (c-gethostname (ffi:char-array-to-pointer name) 256)) + (ffi:convert-from-foreign-string name)))) + + (ffi:def-foreign-type ws-socket :unsigned-int) + (ffi:def-foreign-type ws-dword :unsigned-long) + (ffi:def-foreign-type ws-event :unsigned-int) + + (ffi:def-struct wsa-network-events + (network-events :long) + (error-code (:array :int 10))) + + (ffi:def-function ("WSACreateEvent" wsa-event-create) + () + :returning ws-event + :module "ws2_32") + + (ffi:def-function ("WSACloseEvent" c-wsa-event-close) + ((event-object ws-event)) + :returning :int + :module "ws2_32") + + (defun wsa-event-close (ws-event) + (not (zerop (c-wsa-event-close ws-event)))) + + (ffi:def-function ("WSAEnumNetworkEvents" wsa-enum-network-events) + ((socket ws-socket) + (event-object ws-event) + (network-events (* wsa-network-events))) + :returning :int + :module "ws2_32") + + (ffi:def-function ("WSAEventSelect" wsa-event-select) + ((socket ws-socket) + (event-object ws-event) + (network-events :long)) + :returning :int + :module "ws2_32") + + (ffi:def-function ("WSAWaitForMultipleEvents" c-wsa-wait-for-multiple-events) + ((number-of-events ws-dword) + (events (* ws-event)) + (wait-all-p :int) + (timeout ws-dword) + (alertable-p :int)) + :returning ws-dword + :module "ws2_32") + + (defun wsa-wait-for-multiple-events (number-of-events events wait-all-p timeout alertable-p) + (c-wsa-wait-for-multiple-events number-of-events + events + (if wait-all-p -1 0) + timeout + (if alertable-p -1 0))) + + (ffi:def-function ("ioctlsocket" wsa-ioctlsocket) + ((socket ws-socket) + (cmd :long) + (argp (* :unsigned-long))) + :returning :int + :module "ws2_32") + + (ffi:def-function ("WSAGetLastError" wsa-get-last-error) + () + :returning :int + :module "ws2_32") + + (defun maybe-wsa-error (rv &optional socket) + (unless (zerop rv) + (raise-usock-err (wsa-get-last-error) socket))) + + (defun bytes-available-for-read (socket) + (ffi:with-foreign-object (int-ptr :unsigned-long) + (maybe-wsa-error (wsa-ioctlsocket (socket-handle socket) fionread int-ptr) + socket) + (let ((int (ffi:deref-pointer int-ptr :unsigned-long))) + (prog1 int + (when (plusp int) + (setf (state socket) :read)))))) + + (defun map-network-events (func network-events) + (let ((event-map (ffi:get-slot-value network-events 'wsa-network-events 'network-events)) + (error-array (ffi:get-slot-pointer network-events 'wsa-network-events 'error-code))) + (unless (zerop event-map) + (dotimes (i fd-max-events) + (unless (zerop (ldb (byte 1 i) event-map)) + (funcall func (ffi:deref-array error-array '(:array :int 10) i))))))) + + (defun update-ready-and-state-slots (sockets) + (dolist (socket sockets) + (if (%ready-p socket) + (progn + (setf (state socket) :READ)) + (ffi:with-foreign-object (network-events 'wsa-network-events) + (let ((rv (wsa-enum-network-events (socket-handle socket) 0 network-events))) + (if (zerop rv) + (map-network-events + #'(lambda (err-code) + (if (zerop err-code) + (progn + (setf (state socket) :READ) + (when (stream-server-usocket-p socket) + (setf (%ready-p socket) t))) + (raise-usock-err err-code socket))) + network-events) + (maybe-wsa-error rv socket))))))) + + (defun os-wait-list-%wait (wait-list) + (ffi:deref-pointer (wait-list-%wait wait-list) 'ws-event)) + + (defun (setf os-wait-list-%wait) (value wait-list) + (setf (ffi:deref-pointer (wait-list-%wait wait-list) 'ws-event) value)) + + (defun free-wait-list (wl) + (when (wait-list-p wl) + (unless (null (wait-list-%wait wl)) + (wsa-event-close (os-wait-list-%wait wl)) + (ffi:free-foreign-object (wait-list-%wait wl)) + (setf (wait-list-%wait wl) nil)))) + + (defun %setup-wait-list (wait-list) + (setf (wait-list-%wait wait-list) + (ffi:allocate-foreign-object 'ws-event)) + (setf (os-wait-list-%wait wait-list) + (wsa-event-create)) + (ext:set-finalizer wait-list #'free-wait-list)) + + (defun os-socket-handle (usocket) + (socket-handle usocket)) + +) ; #+(and ecl-bytecmp windows) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/genera.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/genera.lisp new file mode 100644 index 0000000..0a12e8b --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/genera.lisp @@ -0,0 +1,264 @@ +;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Package: USOCKET; Base: 10 -*- + + +;;;; See LICENSE for licensing information. + +(in-package :usocket) + +(defclass genera-socket () + ((foreign-address :initform 0 :initarg :foreign-address :accessor gs-foreign-address) + (foreign-port :initform 0 :initarg :foreign-port :accessor gs-foreign-port) + (local-address :initform 0 :initarg :local-address :accessor gs-local-address) + (local-port :initform 0 :initarg :local-port :accessor gs-local-port)) + ) + +(defclass genera-stream-socket (genera-socket) + ((stream :initform nil :initarg :stream :accessor gs-stream)) + ) + +(defclass genera-stream-server-socket (genera-socket) + ((backlog :initform nil :initarg :backlog :accessor gs-backlog) + (element-type :initform nil :initarg :element-type :accessor gs-element-type) + (pending-connections :initform nil :accessor gs-pending-connections)) + ) + +(defclass genera-datagram-socket (genera-socket) + ((connection :initform nil :initarg :connection :accessor gs-connection)) + ) + +(defun host-to-host-object (host) + (let ((host (host-to-hostname host))) + (cond ((string-equal host "localhost") + net:*local-host*) + ((ip-address-string-p host) + (let ((quad (dotted-quad-to-vector-quad host))) + ;;---*** NOTE: This test is temporary until we have a loopback interface + (if (= (aref quad 0) 127) + net:*local-host* + (net:parse-host (format nil "INTERNET|~A" host))))) + (t + (net:parse-host host))))) + +(defun element-type-to-format (element-type protocol) + (cond ((null element-type) + (ecase protocol + (:stream :text) + (:datagram :binary))) + ((subtypep element-type 'character) + :text) + (t :binary))) + +(defun handle-condition (condition &optional (socket nil) (host-or-ip nil)) + (typecase condition + ;;---*** TODO: Add additional conditions as appropriate + (sys:connection-refused + (error 'connection-refused-error :socket socket)) + ((or tcp::tcp-destination-unreachable-during-connection tcp::udp-destination-unreachable) + (error 'host-unreachable-error :socket socket)) + (sys:host-not-responding-during-connection + (error 'timeout-error :socket socket)) + (sys:unknown-host-name + (error 'ns-host-not-found-error :host-or-ip host-or-ip)) + (sys:network-error + (error 'unknown-error :socket socket :real-error condition :errno -1)))) + +(defun socket-connect (host port &key (protocol :stream) element-type + timeout deadline (nodelay nil nodelay-p) + local-host local-port) + (declare (ignore local-host)) + (when deadline + (unsupported 'deadline 'socket-connect)) + (when (and nodelay-p (not (eq nodelay :if-supported))) + (unsupported 'nodelay 'socket-connect)) + (with-mapped-conditions (nil host) + (ecase protocol + (:stream + (let* ((host-object (host-to-host-object host)) + (format (element-type-to-format element-type protocol)) + (characters (eq format :text)) + (timeout (if timeout + (* 60 timeout) + tcp:*tcp-connect-timeout*)) + (stream (tcp:open-tcp-stream host-object port local-port + :characters characters + :ascii-translation characters + :timeout timeout)) + (gs (make-instance 'genera-stream-socket + :stream stream))) + (setf (gs-foreign-address gs) (scl:send stream :foreign-address)) + (setf (gs-foreign-port gs) (scl:send stream :foreign-port)) + (setf (gs-local-address gs) (scl:send stream :local-address)) + (setf (gs-local-port gs) (scl:send stream :local-port)) + (make-stream-socket :socket gs :stream stream))) + (:datagram + ;;---*** TODO + (unsupported 'datagram 'socket-connect))))) + +(defmethod socket-close ((usocket usocket)) + (with-mapped-conditions (usocket) + (socket-close (socket usocket)))) + +(defmethod socket-close ((socket genera-stream-socket)) + (with-slots (stream) socket + (when stream + (scl:send (shiftf stream nil) :close nil)))) + +(defmethod socket-close ((socket genera-stream-server-socket)) + (with-slots (local-port pending-connections) socket + (when local-port + (tcp:remove-tcp-port-listener local-port)) + (dolist (tcb pending-connections) + (tcp::reject-tcb tcb)))) + +(defmethod socket-close ((socket genera-datagram-socket)) + (with-slots (connection) socket + (when connection + (scl:send (shiftf connection nil) :close nil)) + ;;---*** TODO: listening? + )) + +;;; Cribbed from TCP::MAKE-TCB +(defun gensym-tcp-port () + (loop as number = (incf tcp::*last-gensym-port-number*) then tcp::*last-gensym-port-number* + do (cond ((loop for existing-tcb in tcp::*tcb-list* + thereis (= number (tcp::tcb-local-port existing-tcb)))) + ((and (<= #.(expt 2 10) number) (< number #.(expt 2 16))) + (return number)) + (t + (setq tcp::*last-gensym-port-number* #.(expt 2 10)))))) + +(defun socket-listen (host port &key (reuse-address nil reuse-address-p) + (reuseaddress nil reuseaddress-p) + (backlog 5) (element-type 'character)) + (let ((host-object (host-to-host-object host)) + (port (if (zerop port) (gensym-tcp-port) port)) + (reuse-address (cond (reuse-address-p reuse-address) + (reuseaddress-p reuseaddress) + (t nil)))) + (when (<= port 1024) + ;; Don't allow listening on "privileged" ports to mimic Unix/Linux semantics + (error 'operation-not-permitted-error :socket nil)) + (when (tcp:tcp-port-protocol-name port) + ;; Can't replace a Genera server + (error 'address-in-use-error :socket nil)) + (when (tcp:tcp-port-listener port) + (unless reuse-address + (error 'address-in-use-error :socket nil))) + (let ((gs (make-instance 'genera-stream-server-socket + :backlog backlog + :element-type element-type))) + (setf (gs-local-address gs) + (loop for (network address) in (scl:send host-object :network-addresses) + when (typep network 'tcp:internet-network) + return address)) + (setf (gs-local-port gs) port) + (flet ((add-to-queue (tcb) + (cond ((and (not (zerop (gs-local-address gs))) + (not (= (gs-local-address gs) (tcp::tcb-local-address tcb)))) + ;; Reject if not destined for the proper address + (tcp::reject-tcb tcb)) + ((<= (length (gs-pending-connections gs)) (gs-backlog gs)) + (tcp::accept-tcb tcb) + (tcp::tcb-travel-through-states tcb "Accept" nil :listen :syn-received) + (setf (gs-pending-connections gs) + (append (gs-pending-connections gs) (list tcb)))) + (t + ;; Reject if backlog is full + (tcp::reject-tcb tcb))))) + (tcp:add-tcp-port-listener port #'add-to-queue)) + (make-stream-server-socket gs :element-type element-type)))) + +(defmethod socket-accept ((socket stream-server-usocket) &key element-type) + (with-slots (pending-connections) (socket socket) + (loop + (process:process-block "Wait for connection" #'(lambda () + (not (null pending-connections)))) + (let ((tcb (pop pending-connections))) + (when tcb + (let* ((format (element-type-to-format (or element-type (element-type socket)) + :stream)) + (characters (eq format :text)) + (stream (tcp::make-tcp-stream tcb + :characters characters + :ascii-translation characters)) + (gs (make-instance 'genera-stream-socket + :stream stream))) + (setf (gs-foreign-address gs) (scl:send stream :foreign-address)) + (setf (gs-foreign-port gs) (scl:send stream :foreign-port)) + (setf (gs-local-address gs) (scl:send stream :local-address)) + (setf (gs-local-port gs) (scl:send stream :local-port)) + (return (make-stream-socket :socket gs :stream stream)))))))) + +(defmethod get-local-address ((usocket usocket)) + (hbo-to-vector-quad (gs-local-address (socket usocket)))) + +(defmethod get-peer-address ((usocket stream-usocket)) + (hbo-to-vector-quad (gs-foreign-address (socket usocket)))) + +(defmethod get-local-port ((usocket usocket)) + (gs-local-port (socket usocket))) + +(defmethod get-peer-port ((usocket stream-usocket)) + (gs-foreign-port (socket usocket))) + +(defmethod get-local-name ((usocket usocket)) + (values (get-local-address usocket) + (get-local-port usocket))) + +(defmethod get-peer-name ((usocket stream-usocket)) + (values (get-peer-address usocket) + (get-peer-port usocket))) + +(defmethod socket-send ((usocket datagram-usocket) buffer size &key host port (offset 0)) + ;;---*** TODO + (unsupported 'datagram 'socket-send)) + +(defmethod socket-receive ((socket datagram-usocket) buffer length &key) + ;;---*** TODO + (unsupported 'datagram 'socket-receive)) + +(defun get-host-by-address (address) + ) ;; TODO + +(defun get-hosts-by-name (name) + (with-mapped-conditions (nil name) + (let ((host-object (host-to-host-object name))) + (loop for (network address) in (scl:send host-object :network-addresses) + when (typep network 'tcp:internet-network) + collect (hbo-to-vector-quad address))))) + +(defun %setup-wait-list (wait-list) + (declare (ignore wait-list))) + +(defun %add-waiter (wait-list waiter) + (declare (ignore wait-list waiter))) + +(defun %remove-waiter (wait-list waiter) + (declare (ignore wait-list waiter))) + +(defun wait-for-input-internal (wait-list &key timeout) + (with-mapped-conditions () + (process:process-block-with-timeout timeout "Wait for input" + #'(lambda (wait-list) + (let ((ready-sockets nil)) + (dolist (waiter (wait-list-waiters wait-list) ready-sockets) + (setf (state waiter) + (cond ((stream-usocket-p waiter) + (if (listen (socket-stream waiter)) + :read + nil)) + ((datagram-usocket-p waiter) + (let ((connection (gs-connection (socket waiter)))) + (if (and connection + (not (scl:send connection :connection-pending-p))) + :read + nil))) + ((stream-server-usocket-p waiter) + (if (gs-pending-connections (socket waiter)) + :read + nil)))) + (when (not (null (state waiter))) + (setf ready-sockets t))))) + wait-list) + wait-list)) + diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/iolib.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/iolib.lisp new file mode 100644 index 0000000..53e72c5 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/iolib.lisp @@ -0,0 +1,290 @@ +;;;; See LICENSE for licensing information. + +(in-package :usocket) + +(defparameter *backend* :iolib) + +(eval-when (:load-toplevel :execute) + (shadowing-import 'iolib/sockets:socket-option) + (export 'socket-option)) + +(defparameter +iolib-error-map+ + `((iolib/sockets:socket-address-in-use-error . address-in-use-error) + (iolib/sockets:socket-address-family-not-supported-error . socket-type-not-supported-error) + (iolib/sockets:socket-address-not-available-error . address-not-available-error) + (iolib/sockets:socket-network-down-error . network-down-error) + (iolib/sockets:socket-network-reset-error . network-reset-error) + (iolib/sockets:socket-network-unreachable-error . network-unreachable-error) + ;; (iolib/sockets:socket-no-network-error . ?) + (iolib/sockets:socket-connection-aborted-error . connection-aborted-error) + (iolib/sockets:socket-connection-reset-error . connection-reset-error) + (iolib/sockets:socket-connection-refused-error . connection-refused-error) + (iolib/sockets:socket-connection-timeout-error . timeout-error) + ;; (iolib/sockets:socket-connection-in-progress-error . ?) + (iolib/sockets:socket-endpoint-shutdown-error . network-down-error) + (iolib/sockets:socket-no-buffer-space-error . no-buffers-error) + (iolib/sockets:socket-host-down-error . host-down-error) + (iolib/sockets:socket-host-unreachable-error . host-unreachable-error) + ;; (iolib/sockets:socket-already-connected-error . ?) + (iolib/sockets:socket-not-connected-error . connection-refused-error) + (iolib/sockets:socket-option-not-supported-error . operation-not-permitted-error) + (iolib/syscalls:eacces . operation-not-permitted-error) + (iolib/sockets:socket-operation-not-supported-error . operation-not-supported-error) + (iolib/sockets:unknown-protocol . protocol-not-supported-error) + ;; (iolib/sockets:unknown-interface . ?) + (iolib/sockets:unknown-service . protocol-not-supported-error) + (iolib/sockets:socket-error . socket-error) + + ;; Nameservice errors (src/sockets/dns/conditions.lisp) + (iolib/sockets:resolver-error . ns-error) + (iolib/sockets:resolver-fail-error . ns-host-not-found-error) + (iolib/sockets:resolver-again-error . ns-try-again-condition) + (iolib/sockets:resolver-no-name-error . ns-no-recovery-error) + (iolib/sockets:resolver-unknown-error . ns-unknown-error) + )) + +;; IOlib uses (SIMPLE-ARRAY (UNSIGNED-BYTE 16) (8)) to represent IPv6 addresses, +;; while USOCKET shared code uses (SIMPLE-ARRAY (UNSIGNED-BYTE 8) (16)). Here we do the +;; conversion. +(defun iolib-vector-to-vector-quad (host) + (etypecase host + ((or (vector t 4) ; IPv4 + (array (unsigned-byte 8) (4))) + host) + ((or (vector t 8) ; IPv6 + (array (unsigned-byte 16) (8))) + (loop with vector = (make-array 16 :element-type '(unsigned-byte 8)) + for i below 16 by 2 + for word = (aref host (/ i 2)) + do (setf (aref vector i) (ldb (byte 8 8) word) + (aref vector (1+ i)) (ldb (byte 8 0) word)) + finally (return vector))))) + +(defun handle-condition (condition &optional (socket nil) (host-or-ip nil)) + "Dispatch correct usocket condition." + (let* ((usock-error (cdr (assoc (type-of condition) +iolib-error-map+))) + (usock-error (if (functionp usock-error) + (funcall usock-error condition) + usock-error))) + (if usock-error + (if (typep usock-error 'socket-error) + (cond ((subtypep usock-error 'ns-error) + (error usock-error :socket socket :host-or-ip host-or-ip)) + (t + (error usock-error :socket socket))) + (cond ((subtypep usock-error 'ns-condition) + (signal usock-error :socket socket :host-or-ip host-or-ip)) + (t + (signal usock-error :socket socket)))) + (error 'unknown-error + :real-error condition + :socket socket)))) + +(defun ipv6-address-p (host) + (iolib/sockets:ipv6-address-p (iolib/sockets:ensure-hostname host))) + +(defun socket-connect (host port &key (protocol :stream) (element-type 'character) + timeout deadline + (nodelay t) ;; nodelay == t is the ACL default + local-host local-port) + (declare (ignore element-type deadline nodelay)) + (with-mapped-conditions (nil host) + (let* ((remote (when (and host port) (iolib/sockets:ensure-hostname host))) + (local (when (and local-host local-port) + (iolib/sockets:ensure-hostname local-host))) + (ipv6-p (or (and remote (ipv6-address-p remote) + (and local (ipv6-address-p local))))) + (socket (apply #'iolib/sockets:make-socket + `(:type ,protocol + :address-family :internet + :ipv6 ,ipv6-p + :connect ,(cond ((eq protocol :stream) :active) + ((and host port) :active) + (t :passive)) + ,@(when local + `(:local-host ,local :local-port ,local-port)) + :nodelay nodelay)))) + (when remote + (apply #'iolib/sockets:connect + `(,socket ,remote :port ,port ,@(when timeout `(:wait ,timeout)))) + (unless (iolib/sockets:socket-connected-p socket) + (close socket) + (error 'iolib/sockets:socket-error))) + (ecase protocol + (:stream + (make-stream-socket :stream socket :socket socket)) + (:datagram + (make-datagram-socket socket :connected-p (and remote t))))))) + +(defmethod socket-close ((usocket usocket)) + (close (socket usocket))) + +(defmethod socket-shutdown ((usocket stream-usocket) direction) + (with-mapped-conditions () + (case direction + (:input + (iolib/sockets:shutdown (socket usocket) :read t)) + (:output + (iolib/sockets:shutdown (socket usocket) :write t)) + (t ; :io by default + (iolib/sockets:shutdown (socket usocket) :read t :write t))))) + +(defun socket-listen (host port + &key reuseaddress reuse-address + (backlog 5) + (element-type 'character)) + (declare (ignore element-type)) + (with-mapped-conditions (nil host) + (make-stream-server-socket + (iolib/sockets:make-socket :connect :passive + :address-family :internet + :local-host (iolib/sockets:ensure-hostname host) + :local-port port + :backlog backlog + :reuse-address (or reuse-address reuseaddress))))) + +(defmethod socket-accept ((usocket stream-server-usocket) &key element-type) + (declare (ignore element-type)) + (with-mapped-conditions (usocket) + (let ((socket (iolib/sockets:accept-connection (socket usocket)))) + (make-stream-socket :socket socket :stream socket)))) + +(defmethod get-local-address ((usocket usocket)) + (iolib-vector-to-vector-quad + (iolib/sockets:address-to-vector (iolib/sockets:local-host (socket usocket))))) + +(defmethod get-peer-address ((usocket stream-usocket)) + (iolib-vector-to-vector-quad + (iolib/sockets:address-to-vector (iolib/sockets:remote-host (socket usocket))))) + +(defmethod get-local-port ((usocket usocket)) + (iolib/sockets:local-port (socket usocket))) + +(defmethod get-peer-port ((usocket stream-usocket)) + (iolib/sockets:remote-port (socket usocket))) + +(defmethod get-local-name ((usocket usocket)) + (values (get-local-address usocket) + (get-local-port usocket))) + +(defmethod get-peer-name ((usocket stream-usocket)) + (values (get-peer-address usocket) + (get-peer-port usocket))) + +(defmethod socket-send ((usocket datagram-usocket) buffer size &key host port (offset 0)) + (apply #'iolib/sockets:send-to + `(,(socket usocket) ,buffer :start ,offset :end ,(+ offset size) + ,@(when (and host port) + `(:remote-host ,(iolib/sockets:ensure-hostname host) + :remote-port ,port))))) + +(defmethod socket-receive ((usocket datagram-usocket) buffer length &key start end) + (multiple-value-bind (buffer size host port) + (iolib/sockets:receive-from (socket usocket) + :buffer buffer :size length :start start :end end) + (values buffer size (iolib-vector-to-vector-quad host) port))) + +(defun get-hosts-by-name (name) + (with-mapped-conditions (nil name) + (multiple-value-bind (address more-addresses) + (iolib/sockets:lookup-hostname name :ipv6 iolib/sockets:*ipv6*) + (mapcar #'(lambda (x) (iolib-vector-to-vector-quad + (iolib/sockets:address-name x))) + (cons address more-addresses))))) + +(defun get-host-by-address (address) + (with-mapped-conditions (nil address) + nil)) ;; TODO + +(defvar *event-base* + (make-instance 'iolib/multiplex:event-base)) + +(defun %setup-wait-list (wait-list) + (setf (wait-list-%wait wait-list) + (or *event-base* + ;; iolib/multiplex:*default-multiplexer* is used here + (make-instance 'iolib/multiplex:event-base)))) + +(defun make-usocket-read-handler (usocket disconnector) + (lambda (fd event exception) + (declare (ignore fd event exception)) + (handler-case + (if (eq (state usocket) :write) + (setf (state usocket) :read-write) + (setf (state usocket) :read)) + (end-of-file () + (funcall disconnector :close))))) + +(defun make-usocket-write-handler (usocket disconnector) + (lambda (fd event exception) + (declare (ignore fd event exception)) + (handler-case + (if (eq (state usocket) :read) + (setf (state usocket) :read-write) + (setf (state usocket) :write)) + (end-of-file () + (funcall disconnector :close)) + (iolib/streams:hangup () + (funcall disconnector :close))))) + +(defun make-usocket-error-handler (usocket disconnector) + (lambda (fd event exception) + (declare (ignore fd event exception)) + (handler-case + (setf (state usocket) nil) + (end-of-file () + (funcall disconnector :close)) + (iolib/streams:hangup () + (funcall disconnector :close))))) + +(defun make-usocket-disconnector (event-base usocket) + (declare (ignore event-base)) + (lambda (&rest events) + (let ((socket (socket usocket))) + ;; if were asked to close the socket, we do so here + (when (member :close events) + (close socket :abort t))))) + +(defun %add-waiter (wait-list waiter) + (let ((event-base (wait-list-%wait wait-list)) + (fd (iolib/sockets:socket-os-fd (socket waiter)))) + ;; reset socket state + (setf (state waiter) nil) + ;; set read handler + (unless (iolib/multiplex::fd-monitored-p event-base fd :read) + (iolib/multiplex:set-io-handler + event-base fd :read + (make-usocket-read-handler waiter + (make-usocket-disconnector event-base waiter)))) + ;; set write handler + #+ignore + (unless (iolib/multiplex::fd-monitored-p event-base fd :write) + (iolib/multiplex:set-io-handler + event-base fd :write + (make-usocket-write-handler waiter + (make-usocket-disconnector event-base waiter)))) + ;; set error handler + (unless (iolib/multiplex::fd-has-error-handler-p event-base fd) + (iolib/multiplex:set-error-handler + event-base fd + (make-usocket-error-handler waiter + (make-usocket-disconnector event-base waiter)))))) + +(defun %remove-waiter (wait-list waiter) + (let ((event-base (wait-list-%wait wait-list))) + (iolib/multiplex:remove-fd-handlers event-base + (iolib/sockets:socket-os-fd (socket waiter)) + :read t + :write nil + :error t))) + +;; NOTE: `wait-list-waiters` returns all usockets +(defun wait-for-input-internal (wait-list &key timeout) + (let ((event-base (wait-list-%wait wait-list))) + (handler-case + (iolib/multiplex:event-dispatch event-base :timeout timeout) + (iolib/streams:hangup ()) + (end-of-file ())) + ;; close the event-base after use + (unless (eq event-base *event-base*) + (close event-base)))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/lispworks.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/lispworks.lisp new file mode 100644 index 0000000..9dfc757 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/lispworks.lisp @@ -0,0 +1,1001 @@ +;;;; See LICENSE for licensing information. + +(in-package :usocket) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (require "comm") + + #+lispworks3 + (error "LispWorks 3 is not supported")) + +;;; --------------------------------------------------------------------------- +;;; Warn if multiprocessing is not running on Lispworks + +(defun check-for-multiprocessing-started (&optional errorp) + (unless mp:*current-process* + (funcall (if errorp 'error 'warn) + "You must start multiprocessing on Lispworks by calling~ + ~%~3t(~s)~ + ~%for ~s function properly." + 'mp:initialize-multiprocessing + 'wait-for-input))) + +(eval-when (:load-toplevel :execute) + (check-for-multiprocessing-started)) + +#+win32 +(eval-when (:load-toplevel :execute) + (fli:register-module "ws2_32")) + +(fli:define-foreign-function (get-host-name-internal "gethostname" :source) + ((return-string (:reference-return (:ef-mb-string :limit 257))) + (namelen :int)) + :lambda-list (&aux (namelen 256) return-string) + :result-type :int + #+win32 :module + #+win32 "ws2_32") + +(defun get-host-name () + (multiple-value-bind (return-code name) + (get-host-name-internal) + (when (zerop return-code) + name))) + +#+win32 +(defun remap-maybe-for-win32 (z) + (mapcar #'(lambda (x) + (cons (mapcar #'(lambda (y) (+ 10000 y)) (car x)) + (cdr x))) + z)) + +(defparameter +lispworks-error-map+ + #+win32 + (append (remap-maybe-for-win32 +unix-errno-condition-map+) + (remap-maybe-for-win32 +unix-errno-error-map+)) + #-win32 + (append +unix-errno-condition-map+ + +unix-errno-error-map+)) + +(defun raise-usock-err (errno socket &optional condition (host-or-ip nil)) + (let ((usock-error + (cdr (assoc errno +lispworks-error-map+ :test #'member)))) + (if usock-error + (if (subtypep usock-error 'error) + (cond ((subtypep usock-error 'ns-error) + (error usock-error :socket socket :host-or-ip host-or-ip)) + (t + (error usock-error :socket socket))) + (cond ((subtypep usock-error 'ns-condition) + (signal usock-error :socket socket :host-or-ip host-or-ip)) + (t + (signal usock-error :socket socket)))) + (error 'unknown-error + :socket socket + :real-error condition + :errno errno)))) + +(defun handle-condition (condition &optional (socket nil) (host-or-ip nil)) + "Dispatch correct usocket condition." + (typecase condition + (condition (let ((errno #-win32 (lw:errno-value) + #+win32 (wsa-get-last-error))) + (unless (zerop errno) + (raise-usock-err errno socket condition host-or-ip)))))) + +(defconstant *socket_sock_dgram* 2 + "Connectionless, unreliable datagrams of fixed maximum length.") + +(defconstant *socket_ip_proto_udp* 17) + +(defconstant *sockopt_so_rcvtimeo* + #-linux #x1006 + #+linux 20 + "Socket receive timeout") + +(defconstant *sockopt_so_sndtimeo* + #-linux #x1007 + #+linux 21 + "Socket send timeout") + +(fli:define-c-struct timeval + (tv-sec :long) + (tv-usec :long)) + +;;; ssize_t +;;; recvfrom(int socket, void *restrict buffer, size_t length, int flags, +;;; struct sockaddr *restrict address, socklen_t *restrict address_len); +(fli:define-foreign-function (%recvfrom "recvfrom" :source) + ((socket :int) + (buffer (:pointer (:unsigned :byte))) + (length :int) + (flags :int) + (address (:pointer (:struct comm::sockaddr))) + (address-len (:pointer :int))) + :result-type :int + #+win32 :module + #+win32 "ws2_32") + +;;; ssize_t +;;; sendto(int socket, const void *buffer, size_t length, int flags, +;;; const struct sockaddr *dest_addr, socklen_t dest_len); +(fli:define-foreign-function (%sendto "sendto" :source) + ((socket :int) + (buffer (:pointer (:unsigned :byte))) + (length :int) + (flags :int) + (address (:pointer (:struct comm::sockaddr))) + (address-len :int)) + :result-type :int + #+win32 :module + #+win32 "ws2_32") + +#-win32 +(defun set-socket-receive-timeout (socket-fd seconds) + "Set socket option: RCVTIMEO, argument seconds can be a float number" + (declare (type integer socket-fd) + (type number seconds)) + (multiple-value-bind (sec usec) (truncate seconds) + (fli:with-dynamic-foreign-objects ((timeout (:struct timeval))) + (fli:with-foreign-slots (tv-sec tv-usec) timeout + (setf tv-sec sec + tv-usec (truncate (* 1000000 usec))) + (if (zerop (comm::setsockopt socket-fd + comm::*sockopt_sol_socket* + *sockopt_so_rcvtimeo* + (fli:copy-pointer timeout + :type '(:pointer :void)) + (fli:size-of '(:struct timeval)))) + seconds))))) + +#-win32 +(defun set-socket-send-timeout (socket-fd seconds) + "Set socket option: SNDTIMEO, argument seconds can be a float number" + (declare (type integer socket-fd) + (type number seconds)) + (multiple-value-bind (sec usec) (truncate seconds) + (fli:with-dynamic-foreign-objects ((timeout (:struct timeval))) + (fli:with-foreign-slots (tv-sec tv-usec) timeout + (setf tv-sec sec + tv-usec (truncate (* 1000000 usec))) + (if (zerop (comm::setsockopt socket-fd + comm::*sockopt_sol_socket* + *sockopt_so_sndtimeo* + (fli:copy-pointer timeout + :type '(:pointer :void)) + (fli:size-of '(:struct timeval)))) + seconds))))) + +#+win32 +(defun set-socket-receive-timeout (socket-fd seconds) + "Set socket option: RCVTIMEO, argument seconds can be a float number. + On win32, you must bind the socket before use this function." + (declare (type integer socket-fd) + (type number seconds)) + (fli:with-dynamic-foreign-objects ((timeout :int)) + (setf (fli:dereference timeout) + (truncate (* 1000 seconds))) + (if (zerop (comm::setsockopt socket-fd + comm::*sockopt_sol_socket* + *sockopt_so_rcvtimeo* + (fli:copy-pointer timeout + :type '(:pointer :char)) + (fli:size-of :int))) + seconds))) + +#+win32 +(defun set-socket-send-timeout (socket-fd seconds) + "Set socket option: SNDTIMEO, argument seconds can be a float number. + On win32, you must bind the socket before use this function." + (declare (type integer socket-fd) + (type number seconds)) + (fli:with-dynamic-foreign-objects ((timeout :int)) + (setf (fli:dereference timeout) + (truncate (* 1000 seconds))) + (if (zerop (comm::setsockopt socket-fd + comm::*sockopt_sol_socket* + *sockopt_so_sndtimeo* + (fli:copy-pointer timeout + :type '(:pointer :char)) + (fli:size-of :int))) + seconds))) + +#-win32 +(defun get-socket-receive-timeout (socket-fd) + "Get socket option: RCVTIMEO, return value is a float number" + (declare (type integer socket-fd)) + (fli:with-dynamic-foreign-objects ((timeout (:struct timeval)) + (len :int)) + (comm::getsockopt socket-fd + comm::*sockopt_sol_socket* + *sockopt_so_rcvtimeo* + (fli:copy-pointer timeout + :type '(:pointer :void)) + len) + (fli:with-foreign-slots (tv-sec tv-usec) timeout + (float (+ tv-sec (/ tv-usec 1000000)))))) + +#-win32 +(defun get-socket-send-timeout (socket-fd) + "Get socket option: SNDTIMEO, return value is a float number" + (declare (type integer socket-fd)) + (fli:with-dynamic-foreign-objects ((timeout (:struct timeval)) + (len :int)) + (comm::getsockopt socket-fd + comm::*sockopt_sol_socket* + *sockopt_so_sndtimeo* + (fli:copy-pointer timeout + :type '(:pointer :void)) + len) + (fli:with-foreign-slots (tv-sec tv-usec) timeout + (float (+ tv-sec (/ tv-usec 1000000)))))) + +#+win32 +(defun get-socket-receive-timeout (socket-fd) + "Get socket option: RCVTIMEO, return value is a float number" + (declare (type integer socket-fd)) + (fli:with-dynamic-foreign-objects ((timeout :int) + (len :int)) + (comm::getsockopt socket-fd + comm::*sockopt_sol_socket* + *sockopt_so_rcvtimeo* + (fli:copy-pointer timeout + :type '(:pointer :void)) + len) + (float (/ (fli:dereference timeout) 1000)))) + +#+win32 +(defun get-socket-send-timeout (socket-fd) + "Get socket option: SNDTIMEO, return value is a float number" + (declare (type integer socket-fd)) + (fli:with-dynamic-foreign-objects ((timeout :int) + (len :int)) + (comm::getsockopt socket-fd + comm::*sockopt_sol_socket* + *sockopt_so_sndtimeo* + (fli:copy-pointer timeout + :type '(:pointer :void)) + len) + (float (/ (fli:dereference timeout) 1000)))) + +#+(or lispworks4 lispworks5.0) +(defun set-socket-tcp-nodelay (socket-fd new-value) + "Set socket option: TCP_NODELAY, argument is a fixnum (0 or 1)" + (declare (type integer socket-fd) + (type (integer 0 1) new-value)) + (fli:with-dynamic-foreign-objects ((zero-or-one :int)) + (setf (fli:dereference zero-or-one) new-value) + (when (zerop (comm::setsockopt socket-fd + comm::*sockopt_sol_socket* + comm::*sockopt_tcp_nodelay* + (fli:copy-pointer zero-or-one + :type '(:pointer #+win32 :char #-win32 :void)) + (fli:size-of :int))) + new-value))) + +(defun get-socket-tcp-nodelay (socket-fd) + "Get socket option: TCP_NODELAY, return value is a fixnum (0 or 1)" + (declare (type integer socket-fd)) + (fli:with-dynamic-foreign-objects ((zero-or-one :int) + (len :int)) + (if (zerop (comm::getsockopt socket-fd + comm::*sockopt_sol_socket* + comm::*sockopt_tcp_nodelay* + (fli:copy-pointer zero-or-one + :type '(:pointer #+win32 :char #-win32 :void)) + len)) + zero-or-one 0))) ; on error, return 0 + +(defun initialize-dynamic-sockaddr (hostname service protocol &aux (original-hostname hostname)) + (declare (ignorable original-hostname)) + #+(or lispworks4 lispworks5 lispworks6.0) + (let ((server-addr (fli:allocate-dynamic-foreign-object + :type '(:struct comm::sockaddr_in)))) + (values (comm::initialize-sockaddr_in + server-addr + comm::*socket_af_inet* + hostname + service protocol) + comm::*socket_af_inet* + server-addr + (fli:pointer-element-size server-addr))) + #-(or lispworks4 lispworks5 lispworks6.0) ; version>=6.1 + (progn + (when (stringp hostname) + (setq hostname (comm:string-ip-address hostname)) + (unless hostname + (let ((resolved-hostname (comm:get-host-entry original-hostname :fields '(:address)))) + (unless resolved-hostname + (return-from initialize-dynamic-sockaddr :unknown-host)) + (setq hostname resolved-hostname)))) + (if (or (null hostname) + (integerp hostname) + (comm:ipv6-address-p hostname)) + (let ((server-addr (fli:allocate-dynamic-foreign-object + :type '(:struct comm::lw-sockaddr)))) + (multiple-value-bind (error family) + (comm::initialize-sockaddr_in + server-addr + hostname + service protocol) + (values error family + server-addr + (if (eql family comm::*socket_af_inet*) + (fli:size-of '(:struct comm::sockaddr_in)) + (fli:size-of '(:struct comm::sockaddr_in6)))))) + :bad-host))) + +(defun open-udp-socket (&key local-address local-port read-timeout + (address-family comm::*socket_af_inet*)) + "Open a unconnected UDP socket. + For binding on address ANY(*), just not set LOCAL-ADDRESS (NIL), + for binding on random free unused port, set LOCAL-PORT to 0." + + ;; Note: move (ensure-sockets) here to make sure delivered applications + ;; correctly have networking support initialized. + ;; + ;; Following words was from Martin Simmons, forwarded by Camille Troillard: + + ;; Calling comm::ensure-sockets at load time looks like a bug in Lispworks-udp + ;; (it is too early and also unnecessary). + + ;; The LispWorks comm package calls comm::ensure-sockets when it is needed, so I + ;; think open-udp-socket should probably do it too. Calling it more than once is + ;; safe and it will be very fast after the first time. + #+win32 (comm::ensure-sockets) + + (let ((socket-fd (comm::socket address-family *socket_sock_dgram* *socket_ip_proto_udp*))) + (if socket-fd + (progn + (when read-timeout (set-socket-receive-timeout socket-fd read-timeout)) + (if local-port + (fli:with-dynamic-foreign-objects () + (multiple-value-bind (error local-address-family + client-addr client-addr-length) + (initialize-dynamic-sockaddr local-address local-port "udp") + (if (or error (not (eql address-family local-address-family))) + (progn + (comm::close-socket socket-fd) + (error "cannot resolve hostname ~S, service ~S: ~A" + local-address local-port (or error "address family mismatch"))) + (if (comm::bind socket-fd client-addr client-addr-length) + ;; success, return socket fd + socket-fd + (progn + (comm::close-socket socket-fd) + (error "cannot bind")))))) + socket-fd)) + (error "cannot create socket")))) + +(defun connect-to-udp-server (hostname service + &key local-address local-port read-timeout) + "Something like CONNECT-TO-TCP-SERVER" + (fli:with-dynamic-foreign-objects () + (multiple-value-bind (error address-family server-addr server-addr-length) + (initialize-dynamic-sockaddr hostname service "udp") + (when error + (error "cannot resolve hostname ~S, service ~S: ~A" + hostname service error)) + (let ((socket-fd (open-udp-socket :local-address local-address + :local-port local-port + :read-timeout read-timeout + :address-family address-family))) + (if socket-fd + (if (comm::connect socket-fd server-addr server-addr-length) + ;; success, return socket fd + socket-fd + ;; fail, close socket and return nil + (progn + (comm::close-socket socket-fd) + (error "cannot connect"))) + (error "cannot create socket")))))) + +(defun socket-connect (host port &key (protocol :stream) (element-type 'base-char) + timeout deadline (nodelay t) + local-host local-port) + ;; What's the meaning of this keyword? + (when deadline + (unimplemented 'deadline 'socket-connect)) + + #+(and lispworks4 (not lispworks4.4)) ; < 4.4.5 + (when timeout + (unsupported 'timeout 'socket-connect :minimum "LispWorks 4.4.5")) + + #+lispworks4 + (when local-host + (unsupported 'local-host 'socket-connect :minimum "LispWorks 5.0")) + #+lispworks4 + (when local-port + (unsupported 'local-port 'socket-connect :minimum "LispWorks 5.0")) + + (ecase protocol + (:stream + (let ((hostname (host-to-hostname host)) + (stream)) + (setq stream + (with-mapped-conditions (nil host) + (comm:open-tcp-stream hostname port + :element-type element-type + #-(and lispworks4 (not lispworks4.4)) ; >= 4.4.5 + #-(and lispworks4 (not lispworks4.4)) + :timeout timeout + #-lispworks4 #-lispworks4 + #-lispworks4 #-lispworks4 + :local-address (when local-host (host-to-hostname local-host)) + :local-port local-port + #-(or lispworks4 lispworks5.0) ; >= 5.1 + #-(or lispworks4 lispworks5.0) + :nodelay nodelay))) + + ;; Then handle `nodelay' separately for older versions <= 5.0 + #+(or lispworks4 lispworks5.0) + (when (and stream nodelay) + (set-socket-tcp-nodelay + (comm:socket-stream-socket stream) + (bool->int nodelay))) ; ":if-supported" maps to 1 too. + + (if stream + (make-stream-socket :socket (comm:socket-stream-socket stream) + :stream stream) + ;; if no other error catched by above with-mapped-conditions and still fails, then it's a timeout + (error 'timeout-error)))) + (:datagram + (let ((usocket (make-datagram-socket + (if (and host port) + (with-mapped-conditions (nil host) + (connect-to-udp-server (host-to-hostname host) port + :local-address (and local-host (host-to-hostname local-host)) + :local-port local-port + :read-timeout timeout)) + (with-mapped-conditions (nil local-host) + (open-udp-socket :local-address (and local-host (host-to-hostname local-host)) + :local-port local-port + :read-timeout timeout))) + :connected-p (and host port t)))) + usocket)))) + +(defun socket-listen (host port + &key reuseaddress + (reuse-address nil reuse-address-supplied-p) + (backlog 5) + (element-type 'base-char)) + #+lispworks4.1 + (unsupported 'host 'socket-listen :minimum "LispWorks 4.0 or newer than 4.1") + #+lispworks4.1 + (unsupported 'backlog 'socket-listen :minimum "LispWorks 4.0 or newer than 4.1") + + (let* ((reuseaddress (if reuse-address-supplied-p reuse-address reuseaddress)) + (comm::*use_so_reuseaddr* reuseaddress) + (hostname (host-to-hostname host)) + (socket-res-list (with-mapped-conditions (nil host) + (multiple-value-list + #-lispworks4.1 (comm::create-tcp-socket-for-service + port :address hostname :backlog backlog) + #+lispworks4.1 (comm::create-tcp-socket-for-service port)))) + (sock (if (not (or (second socket-res-list) (third socket-res-list))) + (first socket-res-list) + (when (eq (second socket-res-list) :bind) + (error 'address-in-use-error))))) + (make-stream-server-socket sock :element-type element-type))) + +;; Note: COMM::GET-FD-FROM-SOCKET contains addition socket wait operations, which +;; should NOT be applied on socket FDs who have already been called on W-F-I, +;; so we have to check the %READY-P slot to decide if this waiting is necessary, +;; or SOCKET-ACCEPT will just hang. -- Chun Tian (binghe), May 1, 2011 + +(defmethod socket-accept ((usocket stream-server-usocket) &key element-type) + (let* ((socket (with-mapped-conditions (usocket) + #+win32 + (if (%ready-p usocket) + (comm::accept-connection-to-socket (socket usocket)) + (comm::get-fd-from-socket (socket usocket))) + #-win32 + (comm::get-fd-from-socket (socket usocket)))) + (stream (make-instance 'comm:socket-stream + :socket socket + :direction :io + :element-type (or element-type + (element-type usocket))))) + #+win32 + (when socket + (setf (%ready-p usocket) nil)) + (make-stream-socket :socket socket :stream stream))) + +;; Sockets and their streams are different objects +;; close the stream in order to make sure buffers +;; are correctly flushed and the socket closed. +(defmethod socket-close ((usocket stream-usocket)) + "Close socket." + (close (socket-stream usocket))) + +(defmethod socket-close ((usocket usocket)) + (with-mapped-conditions (usocket) + (comm::close-socket (socket usocket)))) + +(defmethod socket-close :after ((socket datagram-usocket)) + "Additional socket-close method for datagram-usocket" + (setf (%open-p socket) nil)) + +(defconstant +shutdown-read+ 0) +(defconstant +shutdown-write+ 1) +(defconstant +shutdown-read-write+ 2) + +;;; int +;;; shutdown(int socket, int what); +(fli:define-foreign-function (%shutdown "shutdown" :source) + ((socket :int) + (what :int)) + :result-type :int + #+win32 :module + #+win32 "ws2_32") + +(defmethod socket-shutdown ((usocket datagram-usocket) direction) + (unless (member direction '(:input :output :io)) + (error 'invalid-argument-error)) + (let ((what (case direction + (:input +shutdown-read+) + (:output +shutdown-write+) + (:io +shutdown-read-write+)))) + (with-mapped-conditions (usocket) + #-(or lispworks4 lispworks5 lispworks6) ; lispworks 7.0+ + (comm::shutdown (socket usocket) what) + #+(or lispworks4 lispworks5 lispworks6) + (= 0 (%shutdown (socket usocket) what))))) + +(defmethod socket-shutdown ((usocket stream-usocket) direction) + (unless (member direction '(:input :output :io)) + (error 'invalid-argument-error)) + (with-mapped-conditions (usocket) + #-(or lispworks4 lispworks5 lispworks6) + (comm:socket-stream-shutdown (socket usocket) direction) + #+(or lispworks4 lispworks5 lispworks6) + (let ((what (case direction + (:input +shutdown-read+) + (:output +shutdown-write+) + (:io +shutdown-read-write+)))) + (= 0 (%shutdown (comm:socket-stream-socket (socket usocket)) what))))) + +(defmethod initialize-instance :after ((socket datagram-usocket) &key) + (setf (slot-value socket 'send-buffer) + (make-array +max-datagram-packet-size+ + :element-type '(unsigned-byte 8) + :allocation :static)) + (setf (slot-value socket 'recv-buffer) + (make-array +max-datagram-packet-size+ + :element-type '(unsigned-byte 8) + :allocation :static))) + +(defvar *length-of-sockaddr_in* + (fli:size-of '(:struct comm::sockaddr_in))) + +(defmethod socket-send ((usocket datagram-usocket) buffer size &key host port (offset 0) + &aux (socket-fd (socket usocket)) + (message (slot-value usocket 'send-buffer))) ; TODO: multiple threads send together? + "Send message to a socket, using sendto()/send()" + (declare (type integer socket-fd) + (type sequence buffer)) + (when host (setq host (host-to-hostname host))) + (fli:with-dynamic-lisp-array-pointer (ptr message :type '(:unsigned :byte)) + (replace message buffer :start2 offset :end2 (+ offset size)) + (let ((n (if (and host port) + (fli:with-dynamic-foreign-objects () + (multiple-value-bind (error family client-addr client-addr-length) + (initialize-dynamic-sockaddr host port "udp") + (declare (ignore family)) + (when error + (error "cannot resolve hostname ~S, port ~S: ~A" + host port error)) + (%sendto socket-fd ptr (min size +max-datagram-packet-size+) 0 + (fli:copy-pointer client-addr :type '(:struct comm::sockaddr)) + client-addr-length))) + (comm::%send socket-fd ptr (min size +max-datagram-packet-size+) 0)))) + (declare (type fixnum n)) + (if (plusp n) + n + (let ((errno #-win32 (lw:errno-value) + #+win32 (wsa-get-last-error))) + (if (zerop errno) + n + (raise-usock-err errno socket-fd host))))))) + +(defmethod socket-receive ((socket datagram-usocket) buffer length &key timeout (max-buffer-size +max-datagram-packet-size+)) + "Receive message from socket, read-timeout is a float number in seconds. + + This function will return 4 values: + 1. receive buffer + 2. number of receive bytes + 3. remote address + 4. remote port" + (declare (values (simple-array (unsigned-byte 8) (*)) ; buffer + (integer 0) ; size + (unsigned-byte 32) ; host + (unsigned-byte 16)) ; port + (type sequence buffer)) + (let ((socket-fd (socket socket)) + (message (slot-value socket 'recv-buffer)) ; TODO: how multiple threads do this in parallel? + (read-timeout timeout) + old-timeout) + (declare (type integer socket-fd)) + (fli:with-dynamic-foreign-objects ((client-addr (:struct comm::sockaddr_in)) + (len :int + #-(or lispworks4 lispworks5.0) ; <= 5.0 + :initial-element *length-of-sockaddr_in*)) + #+(or lispworks4 lispworks5.0) ; <= 5.0 + (setf (fli:dereference len) *length-of-sockaddr_in*) + (fli:with-dynamic-lisp-array-pointer (ptr message :type '(:unsigned :byte)) + ;; setup new read timeout + (when read-timeout + (setf old-timeout (get-socket-receive-timeout socket-fd)) + (set-socket-receive-timeout socket-fd read-timeout)) + (let ((n (%recvfrom socket-fd ptr max-buffer-size 0 + (fli:copy-pointer client-addr :type '(:struct comm::sockaddr)) + len))) + (declare (type fixnum n)) + ;; restore old read timeout + (when (and read-timeout (/= old-timeout read-timeout)) + (set-socket-receive-timeout socket-fd old-timeout)) + ;; Frank James' patch: reset the %read-p for WAIT-FOR-INPUT + #+win32 (setf (%ready-p socket) nil) + (if (plusp n) + (values (if buffer + (replace buffer message + :end1 (min length max-buffer-size) + :end2 (min n max-buffer-size)) + (subseq message 0 (min n max-buffer-size))) + (min n max-buffer-size) + (comm::ntohl (fli:foreign-slot-value + (fli:foreign-slot-value client-addr + 'comm::sin_addr + :object-type '(:struct comm::sockaddr_in) + :type '(:struct comm::in_addr) + :copy-foreign-object nil) + 'comm::s_addr + :object-type '(:struct comm::in_addr))) + (comm::ntohs (fli:foreign-slot-value client-addr + 'comm::sin_port + :object-type '(:struct comm::sockaddr_in) + :type '(:unsigned :short) + :copy-foreign-object nil))) + (let ((errno #-win32 (lw:errno-value) + #+win32 (wsa-get-last-error))) + (if (zerop errno) + (values nil n 0 0) + (raise-usock-err errno socket-fd))))))))) + +(defmethod get-local-name ((usocket usocket)) + (multiple-value-bind + (address port) + (comm:get-socket-address (socket usocket)) + (values (hbo-to-vector-quad address) port))) + +(defmethod get-peer-name ((usocket stream-usocket)) + (multiple-value-bind + (address port) + (comm:get-socket-peer-address (socket usocket)) + (values (hbo-to-vector-quad address) port))) + +(defmethod get-local-address ((usocket usocket)) + (nth-value 0 (get-local-name usocket))) + +(defmethod get-peer-address ((usocket stream-usocket)) + (nth-value 0 (get-peer-name usocket))) + +(defmethod get-local-port ((usocket usocket)) + (nth-value 1 (get-local-name usocket))) + +(defmethod get-peer-port ((usocket stream-usocket)) + (nth-value 1 (get-peer-name usocket))) + +#-(or lispworks4 lispworks5 lispworks6.0) ; version>= 6.1 +(defun ipv6-address-p (hostname) + (when (stringp hostname) + (setq hostname (comm:string-ip-address hostname)) + (unless hostname + (let ((resolved-hostname (comm:get-host-entry hostname :fields '(:address)))) + (unless resolved-hostname + (return-from ipv6-address-p nil)) + (setq hostname resolved-hostname)))) + (comm:ipv6-address-p hostname)) + +(defun lw-hbo-to-vector-quad (hbo) + #+(or lispworks4 lispworks5 lispworks6.0) + (hbo-to-vector-quad hbo) + #-(or lispworks4 lispworks5 lispworks6.0) ; version>= 6.1 + (if (comm:ipv6-address-p hbo) + (ipv6-host-to-vector (comm:ipv6-address-string hbo)) + (hbo-to-vector-quad hbo))) + +(defun get-hosts-by-name (name) + (with-mapped-conditions (nil name) + (mapcar #'lw-hbo-to-vector-quad + (comm:get-host-entry name :fields '(:addresses))))) + +(defun get-host-by-address (address) + (with-mapped-conditions (nil address) + nil)) ;; TODO + +(defun os-socket-handle (usocket) + (socket usocket)) + +(defun usocket-listen (usocket) + (if (stream-usocket-p usocket) + (when (listen (socket-stream usocket)) + usocket) + (when (comm::socket-listen (socket usocket)) + usocket))) + +;;; +;;; Non Windows implementation +;;; The Windows implementation needs to resort to the Windows API in order +;;; to achieve what we want (what we want is waiting without busy-looping) +;;; + +#-win32 +(progn + + (defun %setup-wait-list (wait-list) + (declare (ignore wait-list))) + + (defun %add-waiter (wait-list waiter) + (declare (ignore wait-list waiter))) + + (defun %remove-waiter (wait-list waiter) + (declare (ignore wait-list waiter))) + + (defun wait-for-input-internal (wait-list &key timeout) + (with-mapped-conditions () + ;; unfortunately, it's impossible to share code between + ;; non-win32 and win32 platforms... + ;; Can we have a sane -pref. complete [UDP!?]- API next time, please? + (dolist (x (wait-list-waiters wait-list)) + (mp:notice-fd (os-socket-handle x))) + (labels ((wait-function (socks) + (let (rv) + (dolist (x socks rv) + (when (usocket-listen x) + (setf (state x) :READ + rv t)))))) + (if timeout + (mp:process-wait-with-timeout "Waiting for a socket to become active" + (truncate timeout) + #'wait-function + (wait-list-waiters wait-list)) + (mp:process-wait "Waiting for a socket to become active" + #'wait-function + (wait-list-waiters wait-list)))) + (dolist (x (wait-list-waiters wait-list)) + (mp:unnotice-fd (os-socket-handle x))) + wait-list)) + +) ; end of block + + +;;; +;;; The Windows side of the story +;;; We want to wait without busy looping +;;; This code only works in threads which don't have (hidden) +;;; windows which need to receive messages. There are workarounds in the Windows API +;;; but are those available to 'us'. +;;; + + +#+win32 +(progn + + ;; LispWorks doesn't provide an interface to wait for a socket + ;; to become ready (under Win32, that is) meaning that we need + ;; to resort to system calls to achieve the same thing. + ;; Luckily, it provides us access to the raw socket handles (as we + ;; wrote the code above. + + (defconstant fd-read 1) + (defconstant fd-read-bit 0) + (defconstant fd-write 2) + (defconstant fd-write-bit 1) + (defconstant fd-oob 4) + (defconstant fd-oob-bit 2) + (defconstant fd-accept 8) + (defconstant fd-accept-bit 3) + (defconstant fd-connect 16) + (defconstant fd-connect-bit 4) + (defconstant fd-close 32) + (defconstant fd-close-bit 5) + (defconstant fd-qos 64) + (defconstant fd-qos-bit 6) + (defconstant fd-group-qos 128) + (defconstant fd-group-qos-bit 7) + (defconstant fd-routing-interface 256) + (defconstant fd-routing-interface-bit 8) + (defconstant fd-address-list-change 512) + (defconstant fd-address-list-change-bit 9) + + (defconstant fd-max-events 10) + + (defconstant fionread 1074030207) + + + ;; Note: + ;; + ;; If special finalization has to occur for a given + ;; system resource (handle), an associated object should + ;; be created. A special cleanup action should be added + ;; to the system and a special cleanup action should + ;; be flagged on all objects created for resources like it + ;; + ;; We have 2 functions to do so: + ;; * hcl:add-special-free-action (function-symbol) + ;; * hcl:flag-special-free-action (object) + ;; + ;; Note that the special free action will be called on all + ;; objects which have been flagged for special free, so be + ;; sure to check for the right argument type! + + (fli:define-foreign-type ws-socket () '(:unsigned :int)) + (fli:define-foreign-type win32-handle () '(:unsigned :int)) + (fli:define-c-struct wsa-network-events + (network-events :long) + (error-code (:c-array :int 10))) + + (fli:define-foreign-function (wsa-event-create "WSACreateEvent" :source) + () + :lambda-list nil + :result-type :int + :module "ws2_32") + + (fli:define-foreign-function (wsa-event-close "WSACloseEvent" :source) + ((event-object win32-handle)) + :result-type :int + :module "ws2_32") + + ;; not used + (fli:define-foreign-function (wsa-reset-event "WSAResetEvent" :source) + ((event-object win32-handle)) + :result-type :int + :module "ws2_32") + + (fli:define-foreign-function (wsa-enum-network-events "WSAEnumNetworkEvents" :source) + ((socket ws-socket) + (event-object win32-handle) + (network-events (:reference-return wsa-network-events))) + :result-type :int + :module "ws2_32") + + (fli:define-foreign-function (wsa-event-select "WSAEventSelect" :source) + ((socket ws-socket) + (event-object win32-handle) + (network-events :long)) + :result-type :int + :module "ws2_32") + + (fli:define-foreign-function (wsa-get-last-error "WSAGetLastError" :source) + () + :result-type :int + :module "ws2_32") + + (fli:define-foreign-function (wsa-ioctlsocket "ioctlsocket" :source) + ((socket :long) (cmd :long) (argp (:ptr :long))) + :result-type :int + :module "ws2_32") + + + ;; The Windows system + + + ;; Now that we have access to the system calls, this is the plan: + + ;; 1. Receive a wait-list with associated sockets to wait for + ;; 2. Add all those sockets to an event handle + ;; 3. Listen for an event on that handle (we have a LispWorks system:: internal for that) + ;; 4. After listening, detect if there are errors + ;; (this step is different from Unix, where we can have only one error) + ;; 5. If so, raise one of them + ;; 6. If not so, return the sockets which have input waiting for them + + + (defun maybe-wsa-error (rv &optional socket) + (unless (zerop rv) + (raise-usock-err (wsa-get-last-error) socket))) + + (defun bytes-available-for-read (socket) + (fli:with-dynamic-foreign-objects ((int-ptr :long)) + (let ((rv (wsa-ioctlsocket (os-socket-handle socket) fionread int-ptr))) + (if (= 0 rv) + (fli:dereference int-ptr) + 0)))) + + (defun socket-ready-p (socket) + (if (typep socket 'stream-usocket) + (< 0 (bytes-available-for-read socket)) + (%ready-p socket))) + + (defun waiting-required (sockets) + (notany #'socket-ready-p sockets)) + + (defun wait-for-input-internal (wait-list &key timeout) + (when (waiting-required (wait-list-waiters wait-list)) + (system:wait-for-single-object (wait-list-%wait wait-list) + "Waiting for socket activity" timeout)) + (update-ready-and-state-slots wait-list)) + + (defun map-network-events (func network-events) + (let ((event-map (fli:foreign-slot-value network-events 'network-events)) + (error-array (fli:foreign-slot-pointer network-events 'error-code))) + (unless (zerop event-map) + (dotimes (i fd-max-events) + (unless (zerop (ldb (byte 1 i) event-map)) ;;### could be faster with ash and logand? + (funcall func (fli:foreign-aref error-array i))))))) + + (defun update-ready-and-state-slots (wait-list) + (loop with sockets = (wait-list-waiters wait-list) + for socket in sockets do + (if (or (and (stream-usocket-p socket) + (listen (socket-stream socket))) + (%ready-p socket)) + (setf (state socket) :READ) + (multiple-value-bind + (rv network-events) + (wsa-enum-network-events (os-socket-handle socket) + (wait-list-%wait wait-list) + t) + (if (zerop rv) + (map-network-events #'(lambda (err-code) + (if (zerop err-code) + (setf (%ready-p socket) t + (state socket) :READ) + (raise-usock-err err-code socket))) + network-events) + (maybe-wsa-error rv socket)))))) + + ;; The wait-list part + + (defun free-wait-list (wl) + (when (wait-list-p wl) + (unless (null (wait-list-%wait wl)) + (wsa-event-close (wait-list-%wait wl)) + (setf (wait-list-%wait wl) nil)))) + + (eval-when (:load-toplevel :execute) + (hcl:add-special-free-action 'free-wait-list)) + + (defun %setup-wait-list (wait-list) + (hcl:flag-special-free-action wait-list) + (setf (wait-list-%wait wait-list) (wsa-event-create))) + + (defun %add-waiter (wait-list waiter) + (let ((events (etypecase waiter + (stream-server-usocket (logior fd-connect fd-accept fd-close)) + (stream-usocket (logior fd-connect fd-read fd-oob fd-close)) + (datagram-usocket (logior fd-read))))) + (maybe-wsa-error + (wsa-event-select (os-socket-handle waiter) (wait-list-%wait wait-list) events) + waiter))) + + (defun %remove-waiter (wait-list waiter) + (maybe-wsa-error + (wsa-event-select (os-socket-handle waiter) (wait-list-%wait wait-list) 0) + waiter)) + +) ; end of WIN32-block + +(defun set-socket-reuse-address (socket-fd reuse-address-p) + (declare (type integer socket-fd) + (type boolean reuse-address-p)) + (fli:with-dynamic-foreign-objects ((value :int)) + (setf (fli:dereference value) (if reuse-address-p 1 0)) + (if (zerop (comm::setsockopt socket-fd + comm::*sockopt_sol_socket* + comm::*sockopt_so_reuseaddr* + (fli:copy-pointer value + :type '(:pointer :void)) + (fli:size-of :int))) + reuse-address-p))) + +(defun get-socket-reuse-address (socket-fd) + (declare (type integer socket-fd)) + (fli:with-dynamic-foreign-objects ((value :int) (len :int)) + (if (zerop (comm::getsockopt socket-fd + comm::*sockopt_sol_socket* + comm::*sockopt_so_reuseaddr* + (fli:copy-pointer value + :type '(:pointer :void)) + len)) + (= 1 (fli:dereference value))))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/mcl.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/mcl.lisp new file mode 100644 index 0000000..e62103c --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/mcl.lisp @@ -0,0 +1,271 @@ +;; MCL backend for USOCKET 0.4.1 +;; Terje Norderhaug , January 1, 2009 + +(in-package :usocket) + +(defun handle-condition (condition &optional socket (host-or-ip nil)) + ; incomplete, needs to handle additional conditions + (flet ((raise-error (&optional socket-condition host-or-ip) + (if socket-condition + (cond ((typep socket-condition ns-error) + (error socket-condition :socket socket :host-or-ip host-or-ip)) + (t + (error socket-condition :socket socket))) + (error 'unknown-error :socket socket :real-error condition)))) + (typecase condition + (ccl:host-stopped-responding + (raise-error 'host-down-error host-or-ip)) + (ccl:host-not-responding + (raise-error 'host-unreachable-error host-or-ip)) + (ccl:connection-reset + (raise-error 'connection-reset-error)) + (ccl:connection-timed-out + (raise-error 'timeout-error)) + (ccl:opentransport-protocol-error + (raise-error 'protocol-not-supported-error)) + (otherwise + (raise-error condition host-or-ip))))) + +(defun socket-connect (host port &key (element-type 'character) timeout deadline nodelay + local-host local-port (protocol :stream)) + (when (eq nodelay :if-supported) + (setf nodelay t)) + (ecase protocol + (:stream + (with-mapped-conditions (nil host) + (let* ((socket + (make-instance 'active-socket + :remote-host (when host (host-to-hostname host)) + :remote-port port + :local-host (when local-host (host-to-hostname local-host)) + :local-port local-port + :deadline deadline + :nodelay nodelay + :connect-timeout (and timeout (round (* timeout 60))) + :element-type element-type)) + (stream (socket-open-stream socket))) + (make-stream-socket :socket socket :stream stream)))) + (:datagram + (with-mapped-conditions (nil (or host local-host)) + (make-datagram-socket + (ccl::open-udp-socket :local-address (and local-host (host-to-hbo local-host)) + :local-port local-port)))))) + +(defun socket-listen (host port + &key reuseaddress + (reuse-address nil reuse-address-supplied-p) + (backlog 5) + (element-type 'character)) + (let* ((reuseaddress (if reuse-address-supplied-p reuse-address reuseaddress)) + (socket (with-mapped-conditions () + (make-instance 'passive-socket + :local-port port + :local-host (host-to-hbo host) + :reuse-address reuseaddress + :backlog backlog)))) + (make-stream-server-socket socket :element-type element-type))) + +(defmethod socket-accept ((usocket stream-server-usocket) &key element-type) + (let* ((socket (socket usocket)) + (stream (with-mapped-conditions (usocket) + (socket-accept socket :element-type element-type)))) + (make-stream-socket :socket socket :stream stream))) + +(defmethod socket-close ((usocket usocket)) + (with-mapped-conditions (usocket) + (socket-close (socket usocket)))) + +(defmethod socket-shutdown ((usocket usocket) direction) + (declare (ignore usocket direction)) + ;; As far as I can tell there isn't a way to shutdown a socket in mcl. + (unsupported "shutdown" 'socket-shutdown)) + +(defmethod ccl::stream-close ((usocket usocket)) + (socket-close usocket)) + +(defun get-hosts-by-name (name) + (with-mapped-conditions (nil name) + (list (hbo-to-vector-quad (ccl::get-host-address + (host-to-hostname name)))))) + +(defun get-host-by-address (address) + (with-mapped-conditions (nil address) + (ccl::inet-host-name (host-to-hbo address)))) + +(defmethod get-local-name ((usocket usocket)) + (values (get-local-address usocket) + (get-local-port usocket))) + +(defmethod get-peer-name ((usocket stream-usocket)) + (values (get-peer-address usocket) + (get-peer-port usocket))) + +(defmethod get-local-address ((usocket usocket)) + (hbo-to-vector-quad (ccl::get-host-address (or (local-host (socket usocket)) "")))) + +(defmethod get-local-port ((usocket usocket)) + (local-port (socket usocket))) + +(defmethod get-peer-address ((usocket stream-usocket)) + (hbo-to-vector-quad (ccl::get-host-address (remote-host (socket usocket))))) + +(defmethod get-peer-port ((usocket stream-usocket)) + (remote-port (socket usocket))) + +(defun %setup-wait-list (wait-list) + (declare (ignore wait-list))) + +(defun %add-waiter (wait-list waiter) + (declare (ignore wait-list waiter))) + +(defun %remove-waiter (wait-list waiter) + (declare (ignore wait-list waiter))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; BASIC MCL SOCKET IMPLEMENTATION + +(defclass socket () + ((local-port :reader local-port :initarg :local-port) + (local-host :reader local-host :initarg :local-host) + (element-type :reader element-type :initform 'ccl::base-character :initarg :element-type))) + +(defclass active-socket (socket) + ((remote-host :reader remote-host :initarg :remote-host) + (remote-port :reader remote-port :initarg :remote-port) + (deadline :initarg :deadline) + (nodelay :initarg :nodelay) + (connect-timeout :reader connect-timeout :initform NIL :initarg :connect-timeout + :type (or null fixnum) :documentation "ticks (60th of a second)"))) + +(defmethod socket-open-stream ((socket active-socket)) + (ccl::open-tcp-stream (or (remote-host socket)(ccl::local-interface-ip-address)) (remote-port socket) + :element-type (if (subtypep (element-type socket) 'character) 'ccl::base-character 'unsigned-byte) + :connect-timeout (connect-timeout socket))) + +(defmethod socket-close ((socket active-socket)) + NIL) + +(defclass passive-socket (socket) + ((streams :accessor socket-streams :type list :initform NIL + :documentation "Circular list of streams with first element the next to open") + (reuse-address :reader reuse-address :initarg :reuse-address) + (lock :reader socket-lock :initform (ccl:make-lock "Socket")))) + +(defmethod initialize-instance :after ((socket passive-socket) &key backlog) + (loop repeat backlog + collect (socket-open-listener socket) into streams + finally (setf (socket-streams socket) + (cdr (rplacd (last streams) streams)))) + (when (zerop (local-port socket)) + (setf (slot-value socket 'local-port) + (or (ccl::process-wait-with-timeout "binding port" (* 10 60) + #'ccl::stream-local-port (car (socket-streams socket))) + (error "timeout"))))) + +(defmethod socket-accept ((socket passive-socket) &key element-type &aux (lock (socket-lock socket))) + (flet ((connection-established-p (stream) + (ccl::with-io-buffer-locked ((ccl::stream-io-buffer stream nil)) + (let ((state (ccl::opentransport-stream-connection-state stream))) + (not (eq :unbnd state)))))) + (with-mapped-conditions () + (ccl:with-lock-grabbed (lock nil "Socket Lock") + (let ((connection (shiftf (car (socket-streams socket)) + (socket-open-listener socket element-type)))) + (pop (socket-streams socket)) + (ccl:process-wait "Accepting" #'connection-established-p connection) + connection))))) + +(defmethod socket-close ((socket passive-socket)) + (loop + with streams = (socket-streams socket) + for (stream tail) on streams + do (close stream :abort T) + until (eq tail streams) + finally (setf (socket-streams socket) NIL))) + +(defmethod socket-open-listener (socket &optional element-type) + ; see http://code.google.com/p/mcl/issues/detail?id=28 + (let* ((ccl::*passive-interface-address* (local-host socket)) + (new (ccl::open-tcp-stream NIL (or (local-port socket) #$kOTAnyInetAddress) + :reuse-local-port-p (reuse-address socket) + :element-type (if (subtypep (or element-type (element-type socket)) + 'character) + 'ccl::base-character + 'unsigned-byte)))) + (declare (special ccl::*passive-interface-address*)) + new)) + +(defmethod input-available-p ((stream ccl::opentransport-stream)) + (macrolet ((when-io-buffer-lock-grabbed ((lock &optional multiple-value-p) &body body) + "Evaluates the body if and only if the lock is successfully grabbed" + ;; like with-io-buffer-lock-grabbed but returns immediately instead of polling the lock + (let ((needs-unlocking-p (gensym)) + (lock-var (gensym))) + `(let* ((,lock-var ,lock) + (ccl::*grabbed-io-buffer-locks* (cons ,lock-var ccl::*grabbed-io-buffer-locks*)) + (,needs-unlocking-p (needs-unlocking-p ,lock-var))) + (declare (dynamic-extent ccl::*grabbed-io-buffer-locks*)) + (when ,needs-unlocking-p + (,(if multiple-value-p 'multiple-value-prog1 'prog1) + (progn ,@body) + (ccl::%release-io-buffer-lock ,lock-var))))))) + (labels ((needs-unlocking-p (lock) + (declare (type ccl::lock lock)) + ;; crucial - clears bogus lock.value as in grab-io-buffer-lock-out-of-line: + (ccl::%io-buffer-lock-really-grabbed-p lock) + (ccl:store-conditional lock nil ccl:*current-process*))) + "similar to stream-listen on buffered-input-stream-mixin but without waiting for lock" + (let ((io-buffer (ccl::stream-io-buffer stream))) + (or (not (eql 0 (ccl::io-buffer-incount io-buffer))) + (ccl::io-buffer-untyi-char io-buffer) + (locally (declare (optimize (speed 3) (safety 0))) + (when-io-buffer-lock-grabbed ((ccl::io-buffer-lock io-buffer)) + (funcall (ccl::io-buffer-listen-function io-buffer) stream io-buffer)))))))) + +(defmethod connection-established-p ((stream ccl::opentransport-stream)) + (ccl::with-io-buffer-locked ((ccl::stream-io-buffer stream nil)) + (let ((state (ccl::opentransport-stream-connection-state stream))) + (not (eq :unbnd state))))) + +(defun wait-for-input-internal (wait-list &key timeout &aux result) + (labels ((ready-sockets (sockets) + (dolist (sock sockets result) + (when (cond ((stream-usocket-p sock) + (input-available-p (socket-stream sock))) + ((stream-server-usocket-p sock) + (let ((ot-stream (first (socket-streams (socket sock))))) + (or (input-available-p ot-stream) + (connection-established-p ot-stream))))) + (push sock result))))) + (with-mapped-conditions () + (ccl:process-wait-with-timeout + "socket input" + (when timeout (truncate (* timeout 60))) + #'ready-sockets + (wait-list-waiters wait-list))) + (nreverse result))) + +;;; datagram socket methods + +(defmethod initialize-instance :after ((usocket datagram-usocket) &key) + (with-slots (socket send-buffer recv-buffer) usocket + (setq send-buffer + (ccl::make-TUnitData (ccl::ot-conn-endpoint socket))) + (setq recv-buffer + (ccl::make-TUnitData (ccl::ot-conn-endpoint socket))))) + +(defmethod socket-send ((usocket datagram-usocket) buffer size &key host port (offset 0)) + (with-mapped-conditions (usocket host) + (with-slots (socket send-buffer) usocket + (unless (and host port) + (unsupported 'host 'socket-send)) + (ccl::send-message socket send-buffer buffer size host port offset)))) + +(defmethod socket-receive ((usocket datagram-usocket) buffer length &key) + (with-mapped-conditions (usocket) + (with-slots (socket recv-buffer) usocket + (ccl::receive-message socket recv-buffer buffer length)))) + +(defmethod socket-close ((socket datagram-usocket)) + nil) ; TODO diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/mezzano.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/mezzano.lisp new file mode 100644 index 0000000..225c77d --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/mezzano.lisp @@ -0,0 +1,99 @@ +;;;; -*- Mode: Common-Lisp -*- + +;;;; See LICENSE for licensing information. + +(in-package :usocket) + +(defun handle-condition (condition &optional (socket nil)) + (typecase condition + ;; TODO: Add additional conditions as appropriate + (mezzano.network.tcp:connection-timed-out + (error 'timeout-error :socket socket)))) + +(defun socket-connect (host port &key (protocol :stream) element-type + timeout deadline (nodelay nil nodelay-p) + local-host local-port) + (declare (ignore local-host local-port)) + (when deadline + (unsupported 'deadline 'socket-connect)) + (when (and nodelay-p (not (eq nodelay :if-supported))) + (unsupported 'nodelay 'socket-connect)) + (when timeout + (unsupported 'timeout 'socket-connect)) + (with-mapped-conditions () + (ecase protocol + (:stream + (let ((s (mezzano.network.tcp:tcp-stream-connect host port :element-type element-type))) + (make-stream-socket :socket s + :stream s))) + (:datagram + ;; TODO: + (unsupported 'datagram 'socket-connect))))) + +(defun socket-listen (host port &key reuseaddress + (reuse-address nil reuse-address-supplied-p) + (backlog 5) + (element-type 'character)) + (declare (ignore reuseaddress reuse-address reuse-address-supplied-p)) + (let ((ip (mezzano.network.ip:make-ipv4-address host))) + (make-stream-server-socket (mezzano.network.tcp:tcp-listen ip port :backlog backlog) + :element-type element-type))) + +(defun get-hosts-by-name (name) + (declare (ignore name))) + +(defun get-host-by-address (address) + (declare (ignore address))) + +(defun %setup-wait-list (wait-list) + (declare (ignore wait-list))) + +(defun %add-waiter (wait-list waiter) + (declare (ignore wait-list waiter))) + +(defun %remove-waiter (wait-list waiter) + (declare (ignore wait-list waiter))) + +(defun wait-for-input-internal (wait-list &key timeout) + (declare (ignore wait-list timeout))) + +(defmethod socket-close ((usocket stream-usocket)) + (with-mapped-conditions () + (close (socket-stream usocket)))) + +(defmethod socket-close ((usocket stream-server-usocket)) + (with-mapped-conditions () + (mezzano.network.tcp:close-tcp-listener (socket usocket)))) + +(defmethod socket-accept ((usocket stream-server-usocket) &key element-type) + (declare (ignore element-type)) + (with-mapped-conditions (usocket) + (let ((s (mezzano.network.tcp:tcp-accept (socket usocket)))) + (make-stream-socket :socket s + :stream s)))) + +(defmethod get-local-name ((usocket stream-usocket)) + (values (get-local-address usocket) + (get-local-port usocket))) + +(defmethod get-peer-name ((usocket stream-usocket)) + (values (get-peer-address usocket) + (get-peer-port usocket))) + +(defmethod get-local-address ((usocket stream-usocket)) + (mezzano.network.ip:ipv4-address-to-string + (mezzano.network.tcp:tcp-connection-local-ip + (mezzano.network.tcp:tcp-stream-connection (socket usocket))))) + +(defmethod get-local-port ((usocket stream-usocket)) + (mezzano.network.tcp:tcp-connection-local-port + (mezzano.network.tcp:tcp-stream-connection (socket usocket)))) + +(defmethod get-peer-address ((usocket stream-usocket)) + (mezzano.network.ip:ipv4-address-to-string + (mezzano.network.tcp:tcp-connection-remote-ip + (mezzano.network.tcp:tcp-stream-connection (socket usocket))))) + +(defmethod get-peer-port ((usocket stream-usocket)) + (mezzano.network.tcp:tcp-connection-remote-port + (mezzano.network.tcp:tcp-stream-connection (socket usocket)))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/mocl.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/mocl.lisp new file mode 100644 index 0000000..1157b0d --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/mocl.lisp @@ -0,0 +1,155 @@ +;;;; See LICENSE for licensing information. + +(in-package :usocket) + +(defun handle-condition (condition &optional (socket nil) (host-or-ip nil)) + "Dispatch correct usocket condition." + (declare (ignore socket)) + (signal condition)) + +(defun socket-connect (host port &key (protocol :stream) (element-type 'character) + timeout deadline (nodelay t nodelay-specified) + (local-host nil local-host-p) + (local-port nil local-port-p)) + (when (and nodelay-specified + (not (eq nodelay :if-supported))) + (unsupported 'nodelay 'socket-connect)) + (when deadline (unsupported 'deadline 'socket-connect)) + (when timeout (unimplemented 'timeout 'socket-connect)) + (when local-host-p + (unimplemented 'local-host 'socket-connect)) + (when local-port-p + (unimplemented 'local-port 'socket-connect)) + + (let (socket) + (ecase protocol + (:stream + (setf socket (rt::socket-connect host port)) + (let ((stream (rt::make-socket-stream socket :binaryp (not (eq element-type 'character))))) + (make-stream-socket :socket socket :stream stream))) + (:datagram + (error 'unsupported + :feature '(protocol :datagram) + :context 'socket-connect))))) + +(defun socket-listen (host port + &key reuseaddress + (reuse-address nil reuse-address-supplied-p) + (backlog 5) + (element-type 'character)) + (unimplemented 'socket-listen 'mocl)) + +(defmethod socket-accept ((usocket stream-server-usocket) &key element-type) + (unimplemented 'socket-accept 'mocl)) + +;; Sockets and their associated streams are modelled as +;; different objects. Be sure to close the socket stream +;; when closing stream-sockets; it makes sure buffers +;; are flushed and the socket is closed correctly afterwards. +(defmethod socket-close ((usocket usocket)) + "Close socket." + (rt::socket-shutdown usocket) + (rt::c-fclose usocket)) + +(defmethod socket-close ((usocket stream-usocket)) + "Close socket." + (close (socket-stream usocket))) + +;; (defmethod socket-close :after ((socket datagram-usocket)) +;; (setf (%open-p socket) nil)) + +(defmethod socket-shutdown ((usocket stream-usocket) direction) + (declare (ignore usocket direction)) + ;; sure would be nice if there was some documentation for mocl... + (unimplemented "shutdown" 'socket-shutdown)) + +;; (defmethod socket-send ((usocket datagram-usocket) buffer size &key host port) +;; (let ((s (socket usocket)) +;; (host (if host (host-to-hbo host))) +;; (real-buffer (if (zerop offset) +;; buffer +;; (subseq buffer offset (+ offset size))))) +;; (multiple-value-bind (result errno) +;; (ext:inet-socket-send-to s real-buffer size +;; :remote-host host :remote-port port) +;; (or result +;; (mocl-map-socket-error errno :socket usocket))))) + +;; (defmethod socket-receive ((socket datagram-usocket) buffer length &key) +;; (declare (values (simple-array (unsigned-byte 8) (*)) ; buffer +;; (integer 0) ; size +;; (unsigned-byte 32) ; host +;; (unsigned-byte 16))) ; port +;; (let ((s (socket socket))) +;; (let ((real-buffer (or buffer +;; (make-array length :element-type '(unsigned-byte 8)))) +;; (real-length (or length +;; (length buffer)))) +;; (multiple-value-bind (result errno remote-host remote-port) +;; (ext:inet-socket-receive-from s real-buffer real-length) +;; (if result +;; (values real-buffer result remote-host remote-port) +;; (mocl-map-socket-error errno :socket socket)))))) + +;; (defmethod get-local-name ((usocket usocket)) +;; (multiple-value-bind (address port) +;; (with-mapped-conditions (usocket) +;; (ext:get-socket-host-and-port (socket usocket))) +;; (values (hbo-to-vector-quad address) port))) + +;; (defmethod get-peer-name ((usocket stream-usocket)) +;; (multiple-value-bind (address port) +;; (with-mapped-conditions (usocket) +;; (ext:get-peer-host-and-port (socket usocket))) +;; (values (hbo-to-vector-quad address) port))) + +;; (defmethod get-local-address ((usocket usocket)) +;; (nth-value 0 (get-local-name usocket))) + +;; (defmethod get-peer-address ((usocket stream-usocket)) +;; (nth-value 0 (get-peer-name usocket))) + +;; (defmethod get-local-port ((usocket usocket)) +;; (nth-value 1 (get-local-name usocket))) + +;; (defmethod get-peer-port ((usocket stream-usocket)) +;; (nth-value 1 (get-peer-name usocket))) + + +;; (defun get-host-by-address (address) +;; (multiple-value-bind (host errno) +;; (ext:lookup-host-entry (host-byte-order address)) +;; (cond (host +;; (ext:host-entry-name host)) +;; (t +;; (let ((condition (cdr (assoc errno +unix-ns-error-map+)))) +;; (cond (condition +;; (error condition :host-or-ip address)) +;; (t +;; (error 'ns-unknown-error :host-or-ip address +;; :real-error errno)))))))) + +(defun get-hosts-by-name (name) + (rt::lookup-host name)) + +;; (defun get-host-name () +;; (unix:unix-gethostname)) + + +;; +;; +;; WAIT-LIST part +;; + + +(defun %add-waiter (wl waiter) + (declare (ignore wl waiter))) + +(defun %remove-waiter (wl waiter) + (declare (ignore wl waiter))) + +(defun %setup-wait-list (wl) + (declare (ignore wl))) + +(defun wait-for-input-internal (wait-list &key timeout) + (unimplemented 'wait-for-input-internal 'mocl)) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/openmcl.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/openmcl.lisp new file mode 100644 index 0000000..113692d --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/openmcl.lisp @@ -0,0 +1,268 @@ +;;;; See LICENSE for licensing information. + +(in-package :usocket) + +(defun get-host-name () + (ccl::%stack-block ((resultbuf 256)) + (when (zerop (#_gethostname resultbuf 256)) + (ccl::%get-cstring resultbuf)))) + +(defparameter +openmcl-error-map+ + '((:address-in-use . address-in-use-error) + (:connection-aborted . connection-aborted-error) + (:no-buffer-space . no-buffers-error) + (:connection-timed-out . timeout-error) + (:connection-refused . connection-refused-error) + (:host-unreachable . host-unreachable-error) + (:host-down . host-down-error) + (:network-down . network-down-error) + (:address-not-available . address-not-available-error) + (:network-reset . network-reset-error) + (:connection-reset . connection-reset-error) + (:shutdown . shutdown-error) + (:access-denied . operation-not-permitted-error))) + +(defparameter +openmcl-nameserver-error-map+ + '((:no-recovery . ns-no-recovery-error) + (:try-again . ns-try-again-condition) + (:host-not-found . ns-host-not-found-error))) + +;; we need something which the openmcl implementors 'forgot' to do: +;; wait for more than one socket-or-fd + +(defun input-available-p (sockets &optional ticks-to-wait) + (ccl::rletz ((tv :timeval)) + (ccl::ticks-to-timeval ticks-to-wait tv) + ;;### The trickery below can be moved to the wait-list now... + (ccl::%stack-block ((infds ccl::*fd-set-size*)) + (ccl::fd-zero infds) + (let ((max-fd -1)) + (dolist (sock sockets) + (let ((fd (openmcl-socket:socket-os-fd (socket sock)))) + (when fd ;; may be NIL if closed + (setf max-fd (max max-fd fd)) + (ccl::fd-set fd infds)))) + (let ((res (#_select (1+ max-fd) + infds (ccl::%null-ptr) (ccl::%null-ptr) + (if ticks-to-wait tv (ccl::%null-ptr))))) + (when (> res 0) + (dolist (sock sockets) + (let ((fd (openmcl-socket:socket-os-fd (socket sock)))) + (when (and fd (ccl::fd-is-set fd infds)) + (setf (state sock) :READ))))) + sockets))))) + +(defun raise-error-from-id (condition-id socket real-condition) + (let ((usock-err (cdr (assoc condition-id +openmcl-error-map+)))) + (if usock-err + (error usock-err :socket socket) + (error 'unknown-error :socket socket :real-error real-condition)))) + +(defun handle-condition (condition &optional socket (host-or-ip nil)) + (typecase condition + (openmcl-socket:socket-error + (raise-error-from-id (openmcl-socket:socket-error-identifier condition) + socket condition)) + (ccl:input-timeout + (error 'timeout-error :socket socket)) + (ccl:communication-deadline-expired + (error 'deadline-timeout-error :socket socket)) + (ccl::socket-creation-error #| ugh! |# + (let* ((condition-id (ccl::socket-creation-error-identifier condition)) + (nameserver-error (cdr (assoc condition-id + +openmcl-nameserver-error-map+)))) + (if nameserver-error + (if (typep nameserver-error 'serious-condition) + (error nameserver-error :host-or-ip host-or-ip) + (signal nameserver-error :host-or-ip host-or-ip)) + (raise-error-from-id condition-id socket condition)))))) + +(defun to-format (element-type protocol) + (cond ((null element-type) + (ecase protocol ; default value of different protocol + (:stream :text) + (:datagram :binary))) + ((subtypep element-type 'character) + :text) + (t :binary))) + +#-ipv6 +(defun socket-connect (host port &key (protocol :stream) element-type + timeout deadline nodelay + local-host local-port) + (when (eq nodelay :if-supported) + (setf nodelay t)) + (with-mapped-conditions (nil host) + (ecase protocol + (:stream + (let ((mcl-sock + (openmcl-socket:make-socket :remote-host (host-to-hostname host) + :remote-port port + :local-host local-host + :local-port local-port + :format (to-format element-type protocol) + :external-format ccl:*default-external-format* + :deadline deadline + :nodelay nodelay + :connect-timeout timeout))) + (make-stream-socket :stream mcl-sock :socket mcl-sock))) + (:datagram + (let* ((mcl-sock + (openmcl-socket:make-socket :address-family :internet + :type :datagram + :local-host local-host + :local-port local-port + :input-timeout timeout + :format (to-format element-type protocol) + :external-format ccl:*default-external-format*)) + (usocket (make-datagram-socket mcl-sock))) + (when (and host port) + (ccl::inet-connect (ccl::socket-device mcl-sock) + (ccl::host-as-inet-host host) + (ccl::port-as-inet-port port "udp"))) + (setf (connected-p usocket) t) + usocket))))) + +#-ipv6 +(defun socket-listen (host port + &key reuseaddress + (reuse-address nil reuse-address-supplied-p) + (backlog 5) + (element-type 'character)) + (let* ((reuseaddress (if reuse-address-supplied-p reuse-address reuseaddress)) + (real-host (host-to-hostname host)) + (sock (with-mapped-conditions (nil host) + (apply #'openmcl-socket:make-socket + (append (list :connect :passive + :reuse-address reuseaddress + :local-port port + :backlog backlog + :format (to-format element-type :stream)) + (unless (eq host *wildcard-host*) + (list :local-host real-host))))))) + (make-stream-server-socket sock :element-type element-type))) + +(defmethod socket-accept ((usocket stream-server-usocket) &key element-type) + (declare (ignore element-type)) ;; openmcl streams are bi/multivalent + (let ((sock (with-mapped-conditions (usocket) + (openmcl-socket:accept-connection (socket usocket))))) + (make-stream-socket :socket sock :stream sock))) + +;; One close method is sufficient because sockets +;; and their associated objects are represented +;; by the same object. +(defmethod socket-close ((usocket usocket)) + (with-mapped-conditions (usocket) + (close (socket usocket)))) + +(defmethod socket-shutdown ((usocket usocket) direction) + (with-mapped-conditions (usocket) + (openmcl-socket:shutdown (socket usocket) :direction direction))) + +#-ipv6 +(defmethod socket-send ((usocket datagram-usocket) buffer size &key host port (offset 0)) + (with-mapped-conditions (usocket host) + (if (and host port) + (openmcl-socket:send-to (socket usocket) buffer size + :remote-host (host-to-hbo host) + :remote-port port + :offset offset) + ;; Clozure CL's socket function SEND-TO doesn't support operations on connected UDP sockets, + ;; so we have to define our own. + (let* ((socket (socket usocket)) + (fd (ccl::socket-device socket))) + (multiple-value-setq (buffer offset) + (ccl::verify-socket-buffer buffer offset size)) + (ccl::%stack-block ((bufptr size)) + (ccl::%copy-ivector-to-ptr buffer offset bufptr 0 size) + (ccl::socket-call socket "send" + (ccl::with-eagain fd :output + (ccl::ignoring-eintr + (ccl::check-socket-error (#_send fd bufptr size 0)))))))))) + +(defmethod socket-receive ((usocket datagram-usocket) buffer length &key) + (with-mapped-conditions (usocket) + (openmcl-socket:receive-from (socket usocket) length :buffer buffer))) + +(defun usocket-host-address (address) + (cond + ((integerp address) + (hbo-to-vector-quad address)) + ((and (arrayp address) + (= (length address) 16) + (every #'= address #(0 0 0 0 0 0 0 0 0 0 #xff #xff))) + (make-array 4 :displaced-to address :displaced-index-offset 12)) + (t + address))) + +(defmethod get-local-address ((usocket usocket)) + (usocket-host-address (openmcl-socket:local-host (socket usocket)))) + +(defmethod get-peer-address ((usocket stream-usocket)) + (usocket-host-address (openmcl-socket:remote-host (socket usocket)))) + +(defmethod get-local-port ((usocket usocket)) + (openmcl-socket:local-port (socket usocket))) + +(defmethod get-peer-port ((usocket stream-usocket)) + (openmcl-socket:remote-port (socket usocket))) + +(defmethod get-local-name ((usocket usocket)) + (values (get-local-address usocket) + (get-local-port usocket))) + +(defmethod get-peer-name ((usocket stream-usocket)) + (values (get-peer-address usocket) + (get-peer-port usocket))) + +(defun get-host-by-address (address) + (with-mapped-conditions (nil address) + (openmcl-socket:ipaddr-to-hostname (host-to-hbo address)))) + +(defun get-hosts-by-name (name) + (with-mapped-conditions (nil name) + (list (hbo-to-vector-quad (openmcl-socket:lookup-hostname + (host-to-hostname name)))))) + +(defun %setup-wait-list (wait-list) + (declare (ignore wait-list))) + +(defun %add-waiter (wait-list waiter) + (declare (ignore wait-list waiter))) + +(defun %remove-waiter (wait-list waiter) + (declare (ignore wait-list waiter))) + +(defun wait-for-input-internal (wait-list &key timeout) + (with-mapped-conditions () + (let* ((ticks-timeout (truncate (* (or timeout 1) + ccl::*ticks-per-second*)))) + (input-available-p (wait-list-waiters wait-list) + (when timeout ticks-timeout)) + wait-list))) + +;;; Helper functions for option.lisp + +(defun get-socket-option-reuseaddr (socket) + (ccl::int-getsockopt (ccl::socket-device socket) + #$SOL_SOCKET #$SO_REUSEADDR)) + +(defun set-socket-option-reuseaddr (socket value) + (ccl::int-setsockopt (ccl::socket-device socket) + #$SOL_SOCKET #$SO_REUSEADDR value)) + +(defun get-socket-option-broadcast (socket) + (ccl::int-getsockopt (ccl::socket-device socket) + #$SOL_SOCKET #$SO_BROADCAST)) + +(defun set-socket-option-broadcast (socket value) + (ccl::int-setsockopt (ccl::socket-device socket) + #$SOL_SOCKET #$SO_BROADCAST value)) + +(defun get-socket-option-tcp-nodelay (socket) + (ccl::int-getsockopt (ccl::socket-device socket) + #$IPPROTO_TCP #$TCP_NODELAY)) + +(defun set-socket-option-tcp-nodelay (socket value) + (ccl::int-setsockopt (ccl::socket-device socket) + #$IPPROTO_TCP #$TCP_NODELAY value)) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/sbcl.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/sbcl.lisp new file mode 100644 index 0000000..5684430 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/sbcl.lisp @@ -0,0 +1,935 @@ +;;;; -*- Mode: Common-Lisp -*- + +;;;; See LICENSE for licensing information. + +(in-package :usocket) + +#+sbcl +(progn + #-win32 + (defun get-host-name () + (sb-unix:unix-gethostname)) + + ;; we assume winsock has already been loaded, after all, + ;; we already loaded sb-bsd-sockets and sb-alien + #+win32 + (defun get-host-name () + (sb-alien:with-alien ((buf (sb-alien:array sb-alien:char 256))) + (let ((result (sb-alien:alien-funcall + (sb-alien:extern-alien "gethostname" + (sb-alien:function sb-alien:int + (* sb-alien:char) + sb-alien:int)) + (sb-alien:cast buf (* sb-alien:char)) + 256))) + (when (= result 0) + (sb-alien:cast buf sb-alien:c-string)))))) + +#+(and ecl (not ecl-bytecmp)) +(progn + #-:wsock + (ffi:clines + "#include " + "#include " + "#include ") + #+:wsock + (ffi:clines + "#ifndef FD_SETSIZE" + "#define FD_SETSIZE 1024" + "#endif" + "#include ") + + (ffi:clines + #+:msvc "#include " + #-:msvc "#include " + "#include ") +#| + #+:prefixed-api + (ffi:clines + "#define CONS(x, y) ecl_cons((x), (y))" + "#define MAKE_INTEGER(x) ecl_make_integer((x))") + #-:prefixed-api + (ffi:clines + "#define CONS(x, y) make_cons((x), (y))" + "#define MAKE_INTEGER(x) make_integer((x))") +|# + + (defun cerrno () + (ffi:c-inline () () :int + "errno" :one-liner t)) + + (defun fd-setsize () + (ffi:c-inline () () :fixnum + "FD_SETSIZE" :one-liner t)) + + (defun fdset-alloc () + (ffi:c-inline () () :pointer-void + "ecl_alloc_atomic(sizeof(fd_set))" :one-liner t)) + + (defun fdset-zero (fdset) + (ffi:c-inline (fdset) (:pointer-void) :void + "FD_ZERO((fd_set*)#0)" :one-liner t)) + + (defun fdset-set (fdset fd) + (ffi:c-inline (fdset fd) (:pointer-void :fixnum) :void + "FD_SET(#1,(fd_set*)#0)" :one-liner t)) + + (defun fdset-clr (fdset fd) + (ffi:c-inline (fdset fd) (:pointer-void :fixnum) :void + "FD_CLR(#1,(fd_set*)#0)" :one-liner t)) + + (defun fdset-fd-isset (fdset fd) + (ffi:c-inline (fdset fd) (:pointer-void :fixnum) :bool + "FD_ISSET(#1,(fd_set*)#0)" :one-liner t)) + + (declaim (inline cerrno + fd-setsize + fdset-alloc + fdset-zero + fdset-set + fdset-clr + fdset-fd-isset)) + + (defun get-host-name () + (ffi:c-inline + () () :object + "{ char *buf = (char *) ecl_alloc_atomic(257); + + if (gethostname(buf,256) == 0) + @(return) = make_simple_base_string(buf); + else + @(return) = Cnil; + }" :one-liner nil :side-effects nil)) + + (defun read-select (wl to-secs &optional (to-musecs 0)) + (let* ((sockets (wait-list-waiters wl)) + (rfds (wait-list-%wait wl)) + (max-fd (reduce #'(lambda (x y) + (let ((sy (sb-bsd-sockets:socket-file-descriptor + (socket y)))) + (if (< x sy) sy x))) + (cdr sockets) + :initial-value (sb-bsd-sockets:socket-file-descriptor + (socket (car sockets)))))) + (fdset-zero rfds) + (dolist (sock sockets) + (fdset-set rfds (sb-bsd-sockets:socket-file-descriptor + (socket sock)))) + (let ((count + (ffi:c-inline (to-secs to-musecs rfds max-fd) + (t :unsigned-int :pointer-void :int) + :int + " + int count; + struct timeval tv; + struct timeval tvs; + struct timeval tve; + unsigned long elapsed; + unsigned long remaining; + int retval = -1; + + if (#0 != Cnil) { + tv.tv_sec = fixnnint(#0); + tv.tv_usec = #1; + } + remaining = ((tv.tv_sec*1000000) + tv.tv_usec); + + do { + (void)gettimeofday(&tvs, NULL); // start time + + retval = select(#3 + 1, (fd_set*)#2, NULL, NULL, + (#0 != Cnil) ? &tv : NULL); + + if ( (retval < 0) && (errno == EINTR) && (#0 != Cnil) ) { + (void)gettimeofday(&tve, NULL); // end time + elapsed = (tve.tv_sec - tvs.tv_sec)*1000000 + (tve.tv_usec - tvs.tv_usec); + remaining = remaining - elapsed; + if ( remaining < 0 ) { // already past timeout, just exit + retval = 0; + break; + } + + tv.tv_sec = remaining / 1000000; + tv.tv_usec = remaining - (tv.tv_sec * 1000000); + } + + } while ((retval < 0) && (errno == EINTR)); + + @(return) = retval; +" :one-liner nil))) + (cond + ((= 0 count) + (values nil nil)) + ((< count 0) + ;; check for EAGAIN; these should not err + (values nil (cerrno))) + (t + (dolist (sock sockets) + (when (fdset-fd-isset rfds (sb-bsd-sockets:socket-file-descriptor + (socket sock))) + (setf (state sock) :READ)))))))) +) ; progn + +(defun map-socket-error (sock-err) + (map-errno-error (sb-bsd-sockets::socket-error-errno sock-err))) + +(defparameter +sbcl-condition-map+ + '((interrupted-error . interrupted-condition))) + +(defparameter +sbcl-error-map+ + `((sb-bsd-sockets:address-in-use-error . address-in-use-error) + (sb-bsd-sockets::no-address-error . address-not-available-error) + (sb-bsd-sockets:bad-file-descriptor-error . bad-file-descriptor-error) + (sb-bsd-sockets:connection-refused-error . connection-refused-error) + (sb-bsd-sockets:invalid-argument-error . invalid-argument-error) + (sb-bsd-sockets:no-buffers-error . no-buffers-error) + (sb-bsd-sockets:operation-not-supported-error + . operation-not-supported-error) + (sb-bsd-sockets:operation-not-permitted-error + . operation-not-permitted-error) + (sb-bsd-sockets:protocol-not-supported-error + . protocol-not-supported-error) + #-(or ecl clasp) + (sb-bsd-sockets:unknown-protocol + . protocol-not-supported-error) + (sb-bsd-sockets:socket-type-not-supported-error + . socket-type-not-supported-error) + (sb-bsd-sockets:network-unreachable-error . network-unreachable-error) + (sb-bsd-sockets:operation-timeout-error . timeout-error) + #-(or ecl clasp) + (sb-sys:io-timeout . timeout-error) + #+sbcl + (sb-ext:timeout . timeout-error) + (sb-bsd-sockets:socket-error . ,#'map-socket-error) + + ;; Nameservice errors: mapped to unknown-error + #-(or ecl clasp) + (sb-bsd-sockets:no-recovery-error . ns-no-recovery-error) + #-(or ecl clasp) + (sb-bsd-sockets:try-again-error . ns-try-again-condition) + #-(or ecl clasp) + (sb-bsd-sockets:host-not-found-error . ns-host-not-found-error))) + +;; this function servers as a general template for other backends +(defun handle-condition (condition &optional (socket nil) (host-or-ip nil)) + "Dispatch correct usocket condition." + (typecase condition + (serious-condition + (let* ((usock-error (cdr (assoc (type-of condition) +sbcl-error-map+))) + (usock-error (if (functionp usock-error) + (funcall usock-error condition) + usock-error))) + (declare (type symbol usock-error)) + (if usock-error + (cond ((subtypep usock-error 'ns-error) + (error usock-error :socket socket :host-or-ip host-or-ip)) + (t + (error usock-error :socket socket))) + (error 'unknown-error + :real-error condition + :socket socket)))) + (condition + (let* ((usock-cond (cdr (assoc (type-of condition) +sbcl-condition-map+))) + (usock-cond (if (functionp usock-cond) + (funcall usock-cond condition) + usock-cond))) + (if usock-cond + (cond ((subtypep usock-cond 'ns-condition) + (signal usock-cond :socket socket :host-or-ip host-or-ip)) + (t + (signal usock-cond :socket socket))) + (signal 'unknown-condition + :real-condition condition + :socket socket)))))) + +;;; "The socket stream ends up with a bogus name as it is created before +;;; the socket is connected, making things harder to debug than they need +;;; to be." -- Nikodemus Siivola + +(defvar *dummy-stream* + (let ((stream (make-broadcast-stream))) + (close stream) + stream)) + +;;; Amusingly, neither SBCL's own, nor GBBopen's WITH-TIMEOUT is asynch +;;; unwind safe. The one I posted is -- that's what the WITHOUT-INTERRUPTS +;;; and WITH-LOCAL-INTERRUPTS were for. :) But yeah, it's miles saner than +;;; the SB-EXT:WITH-TIMEOUT. -- Nikodemus Siivola + +#+(and sbcl (not win32)) +(defmacro %with-timeout ((seconds timeout-form) &body body) + "Runs BODY as an implicit PROGN with timeout of SECONDS. If +timeout occurs before BODY has finished, BODY is unwound and +TIMEOUT-FORM is executed with its values returned instead. + +Note that BODY is unwound asynchronously when a timeout occurs, +so unless all code executed during it -- including anything +down the call chain -- is asynch unwind safe, bad things will +happen. Use with care." + (let ((exec (gensym)) (unwind (gensym)) (timer (gensym)) + (timeout (gensym)) (block (gensym))) + `(block ,block + (tagbody + (flet ((,unwind () + (go ,timeout)) + (,exec () + ,@body)) + (declare (dynamic-extent #',exec #',unwind)) + (let ((,timer (sb-ext:make-timer #',unwind))) + (declare (dynamic-extent ,timer)) + (sb-sys:without-interrupts + (unwind-protect + (progn + (sb-ext:schedule-timer ,timer ,seconds) + (return-from ,block + (sb-sys:with-local-interrupts + (,exec)))) + (sb-ext:unschedule-timer ,timer))))) + ,timeout + (return-from ,block ,timeout-form))))) + +(defun get-hosts-by-name (name) + (with-mapped-conditions (nil name) + (multiple-value-bind (host4 host6) + (sb-bsd-sockets:get-host-by-name name) + (let ((addr4 (when host4 + (sb-bsd-sockets::host-ent-addresses host4))) + (addr6 (when host6 + (sb-bsd-sockets::host-ent-addresses host6)))) + (append addr4 addr6))))) + +(defun socket-connect (host port &key (protocol :stream) (element-type 'character) + timeout deadline (nodelay t nodelay-specified) + local-host local-port + &aux + (sockopt-tcp-nodelay-p + (fboundp 'sb-bsd-sockets::sockopt-tcp-nodelay))) + (when deadline (unsupported 'deadline 'socket-connect)) + #+(or ecl clasp) + (when timeout (unsupported 'timeout 'socket-connect)) + (when (and nodelay-specified + ;; 20080802: ECL added this function to its sockets + ;; package today. There's no guarantee the functions + ;; we need are available, but we can make sure not to + ;; call them if they aren't + (not (eq nodelay :if-supported)) + (not sockopt-tcp-nodelay-p)) + (unsupported 'nodelay 'socket-connect)) + (when (eq nodelay :if-supported) + (setf nodelay t)) + + (let* ((remote (when host + (car (get-hosts-by-name (host-to-hostname host))))) + (local (when local-host + (car (get-hosts-by-name (host-to-hostname local-host))))) + (ipv6 (or (and remote (= 16 (length remote))) + (and local (= 16 (length local))))) + (socket (make-instance #+sbcl (if ipv6 + 'sb-bsd-sockets::inet6-socket + 'sb-bsd-sockets:inet-socket) + #+(or ecl clasp) 'sb-bsd-sockets:inet-socket + :type protocol + :protocol (case protocol + (:stream :tcp) + (:datagram :udp)))) + usocket + ok) + + (unwind-protect + (progn + (ecase protocol + (:stream + ;; If make a real socket stream before the socket is + ;; connected, it gets a misleading name so supply a + ;; dummy value to start with. + (setf usocket (make-stream-socket :socket socket :stream *dummy-stream*)) + ;; binghe: use SOCKOPT-TCP-NODELAY as internal symbol + ;; to pass compilation on ECL without it. + (when (and nodelay-specified sockopt-tcp-nodelay-p) + (setf (sb-bsd-sockets::sockopt-tcp-nodelay socket) nodelay)) + (when (or local-host local-port) + (sb-bsd-sockets:socket-bind socket + (if ipv6 + (or local (ipv6-host-to-vector "::0")) + (or local (host-to-vector-quad *wildcard-host*))) + (or local-port *auto-port*))) + + (with-mapped-conditions (usocket host) + #+(and sbcl (not win32)) + (labels ((connect () + (sb-bsd-sockets:socket-connect socket remote port))) + (if timeout + (%with-timeout (timeout (error 'sb-ext:timeout)) (connect)) + (connect))) + #+(or ecl clasp (and sbcl win32)) + (sb-bsd-sockets:socket-connect socket remote port) + ;; Now that we're connected make the stream. + (setf (socket-stream usocket) + (sb-bsd-sockets:socket-make-stream socket + :input t :output t :buffering :full + :element-type element-type + ;; Robert Brown said on Aug 4, 2011: + ;; ... This means that SBCL streams created by usocket have a true + ;; serve-events property. When writing large amounts of data to several + ;; streams, the kernel will eventually stop accepting data from SBCL. + ;; When this happens, SBCL either waits for I/O to be possible on + ;; the file descriptor it's writing to or queues the data to be flushed later. + ;; Because usocket streams specify serve-events as true, SBCL + ;; always queues. Instead, it should wait for I/O to be available and + ;; write the remaining data to the socket. That's what serve-events + ;; equal to NIL gets you. + ;; + ;; Nikodemus Siivola said on Aug 8, 2011: + ;; It's set to T for purely historical reasons, and will soon change to + ;; NIL in SBCL. (The docstring has warned of T being a temporary default + ;; for as long as the :SERVE-EVENTS keyword argument has existed.) + :serve-events nil)))) + (:datagram + (when (or local-host local-port) + (sb-bsd-sockets:socket-bind socket + (if ipv6 + (or local (ipv6-host-to-vector "::0")) + (or local (host-to-vector-quad *wildcard-host*))) + (or local-port *auto-port*))) + (setf usocket (make-datagram-socket socket)) + (when (and host port) + (with-mapped-conditions (usocket) + (sb-bsd-sockets:socket-connect socket remote port) + (setf (connected-p usocket) t))))) + (setf ok t)) + ;; Clean up in case of an error. + (unless ok + (sb-bsd-sockets:socket-close socket :abort t))) + usocket)) + +(defun socket-listen (host port + &key reuseaddress + (reuse-address nil reuse-address-supplied-p) + (backlog 5) + (element-type 'character)) + (let* (#+sbcl + (local (when host + (car (get-hosts-by-name (host-to-hostname host))))) + #+sbcl + (ipv6 (and local (= 16 (length local)))) + (reuseaddress (if reuse-address-supplied-p reuse-address reuseaddress)) + (ip #+sbcl (if (and local (not (eq host *wildcard-host*))) + local + (hbo-to-vector-quad sb-bsd-sockets-internal::inaddr-any)) + #+(or ecl clasp) (host-to-vector-quad host)) + (sock (make-instance #+sbcl (if ipv6 + 'sb-bsd-sockets::inet6-socket + 'sb-bsd-sockets:inet-socket) + #+(or ecl clasp) 'sb-bsd-sockets:inet-socket + :type :stream + :protocol :tcp))) + (handler-case + (with-mapped-conditions (nil host) + (setf (sb-bsd-sockets:sockopt-reuse-address sock) reuseaddress) + (sb-bsd-sockets:socket-bind sock ip port) + (sb-bsd-sockets:socket-listen sock backlog) + (make-stream-server-socket sock :element-type element-type)) + (t (c) + ;; Make sure we don't leak filedescriptors + (sb-bsd-sockets:socket-close sock) + (error c))))) + +;;; "2. SB-BSD-SOCKETS:SOCKET-ACCEPT method returns NIL for EAGAIN/EINTR, +;;; instead of raising a condition. It's always possible for +;;; SOCKET-ACCEPT on non-blocking socket to fail, even after the socket +;;; was detected to be ready: connection might be reset, for example. +;;; +;;; "I had to redefine SOCKET-ACCEPT method of STREAM-SERVER-USOCKET to +;;; handle this situation. Here is the redefinition:" -- Anton Kovalenko + +(defmethod socket-accept ((usocket stream-server-usocket) &key element-type) + (with-mapped-conditions (usocket) + (let ((socket (sb-bsd-sockets:socket-accept (socket usocket)))) + (when socket + (prog1 + (make-stream-socket + :socket socket + :stream (sb-bsd-sockets:socket-make-stream + socket + :input t :output t :buffering :full + :element-type (or element-type + (element-type usocket)))) + + ;; next time wait for event again if we had EAGAIN/EINTR + ;; or else we'd enter a tight loop of failed accepts + #+win32 + (setf (%ready-p usocket) nil)))))) + +;; Sockets and their associated streams are modelled as +;; different objects. Be sure to close the stream (which +;; closes the socket too) when closing a stream-socket. +(defmethod socket-close ((usocket usocket)) + (with-mapped-conditions (usocket) + (sb-bsd-sockets:socket-close (socket usocket)))) + +(defmethod socket-close ((usocket stream-usocket)) + (with-mapped-conditions (usocket) + (close (socket-stream usocket)))) + +#+sbcl +(defmethod socket-shutdown ((usocket stream-usocket) direction) + (with-mapped-conditions (usocket) + (sb-bsd-sockets::socket-shutdown (socket usocket) :direction direction))) + +#+ecl +(defmethod socket-shutdown ((usocket stream-usocket) direction) + (let ((sock-fd (sb-bsd-sockets:socket-file-descriptor (socket usocket))) + (direction-flag (ecase direction + (:input 0) + (:output 1)))) + (unless (zerop (ffi:c-inline (sock-fd direction-flag) (:int :int) :int + "shutdown(#0, #1)" :one-liner t)) + (error (map-errno-error (cerrno)))))) + +#+clasp +(defmethod socket-shutdown ((usocket stream-usocket) direction) + (let ((sock-fd (sb-bsd-sockets:socket-file-descriptor (socket usocket))) + (direction-flag (ecase direction + (:input 0) + (:output 1)))) + (unless (zerop (sockets-internal:shutdown sock-fd direction-flag)) + (error (map-errno-error (cerrno)))))) + +(defmethod socket-send ((usocket datagram-usocket) buffer size &key host port (offset 0)) + (let ((remote (when host + (car (get-hosts-by-name (host-to-hostname host)))))) + (with-mapped-conditions (usocket host) + (let* ((s (socket usocket)) + (dest (if (and host port) (list remote port) nil)) + (real-buffer (if (zerop offset) + buffer + (subseq buffer offset (+ offset size))))) + (sb-bsd-sockets:socket-send s real-buffer size :address dest))))) + +(defmethod socket-receive ((usocket datagram-usocket) buffer length + &key (element-type '(unsigned-byte 8))) + #+sbcl + (declare (values (simple-array (unsigned-byte 8) (*)) ; buffer + (integer 0) ; size + (simple-array (unsigned-byte 8) (*)) ; host + (unsigned-byte 16))) ; port + (with-mapped-conditions (usocket) + (let ((s (socket usocket))) + (sb-bsd-sockets:socket-receive s buffer length :element-type element-type)))) + +(defmethod get-local-name ((usocket usocket)) + (sb-bsd-sockets:socket-name (socket usocket))) + +(defmethod get-peer-name ((usocket stream-usocket)) + (sb-bsd-sockets:socket-peername (socket usocket))) + +(defmethod get-local-address ((usocket usocket)) + (nth-value 0 (get-local-name usocket))) + +(defmethod get-peer-address ((usocket stream-usocket)) + (nth-value 0 (get-peer-name usocket))) + +(defmethod get-local-port ((usocket usocket)) + (nth-value 1 (get-local-name usocket))) + +(defmethod get-peer-port ((usocket stream-usocket)) + (nth-value 1 (get-peer-name usocket))) + +(defun get-host-by-address (address) + (with-mapped-conditions (nil address) + (sb-bsd-sockets::host-ent-name + (sb-bsd-sockets:get-host-by-address address)))) + +#+(and sbcl (not win32)) +(progn + (defun %setup-wait-list (wait-list) + (declare (ignore wait-list))) + + (defun %add-waiter (wait-list waiter) + (push (socket waiter) (wait-list-%wait wait-list))) + + (defun %remove-waiter (wait-list waiter) + (setf (wait-list-%wait wait-list) + (remove (socket waiter) (wait-list-%wait wait-list)))) + + (defun wait-for-input-internal (sockets &key timeout) + (with-mapped-conditions () + (sb-alien:with-alien ((rfds (sb-alien:struct sb-unix:fd-set))) + (sb-unix:fd-zero rfds) + (dolist (socket (wait-list-%wait sockets)) + (sb-unix:fd-set + (sb-bsd-sockets:socket-file-descriptor socket) + rfds)) + (multiple-value-bind + (secs musecs) + (split-timeout (or timeout 1)) + (let* ((wait-list (wait-list-%wait sockets)) + count err) + (if (null wait-list) + (setq count 0) ;; no need to call + (multiple-value-setq (count err) + (sb-unix:unix-fast-select + ;; "invalid number of arguments: 0" if wait-list is null. + (1+ (reduce #'max wait-list + :key #'sb-bsd-sockets:socket-file-descriptor)) + (sb-alien:addr rfds) nil nil + (when timeout secs) (when timeout musecs)))) + (if (null count) ; something wrong in #'sb-unix:unix-fast-select + (unless (= err sb-unix:eintr) + (error (map-errno-error err))) + (when (< 0 count) ; do nothing if count = 0 + ;; process the result... + (dolist (x (wait-list-waiters sockets)) + (when (sb-unix:fd-isset + (sb-bsd-sockets:socket-file-descriptor + (socket x)) + rfds) + (setf (state x) :READ)))))))))) +) ; progn + +;;; WAIT-FOR-INPUT support for SBCL on Windows platform (Chun Tian (binghe)) +;;; Based on LispWorks version written by Erik Huelsmann. + +#+win32 ; shared by ECL and SBCL +(eval-when (:compile-toplevel :load-toplevel :execute) + (defconstant +wsa-wait-failed+ #xffffffff) + (defconstant +wsa-infinite+ #xffffffff) + (defconstant +wsa-wait-event-0+ 0) + (defconstant +wsa-wait-timeout+ 258)) + +#+win32 ; shared by ECL and SBCL +(progn + (defconstant fd-read 1) + (defconstant fd-read-bit 0) + (defconstant fd-write 2) + (defconstant fd-write-bit 1) + (defconstant fd-oob 4) + (defconstant fd-oob-bit 2) + (defconstant fd-accept 8) + (defconstant fd-accept-bit 3) + (defconstant fd-connect 16) + (defconstant fd-connect-bit 4) + (defconstant fd-close 32) + (defconstant fd-close-bit 5) + (defconstant fd-qos 64) + (defconstant fd-qos-bit 6) + (defconstant fd-group-qos 128) + (defconstant fd-group-qos-bit 7) + (defconstant fd-routing-interface 256) + (defconstant fd-routing-interface-bit 8) + (defconstant fd-address-list-change 512) + (defconstant fd-address-list-change-bit 9) + (defconstant fd-max-events 10) + (defconstant fionread 1074030207) + + ;; Note: for ECL, socket-handle will return raw Windows Handle, + ;; while SBCL returns OSF Handle instead. + (defun socket-handle (usocket) + (sb-bsd-sockets:socket-file-descriptor (socket usocket))) + + (defun socket-ready-p (socket) + (if (typep socket 'stream-usocket) + (plusp (bytes-available-for-read socket)) + (%ready-p socket))) + + (defun waiting-required (sockets) + (notany #'socket-ready-p sockets)) + + (defun raise-usock-err (errno &optional socket) + (error 'unknown-error + :socket socket + :real-error errno)) + + (defun wait-for-input-internal (wait-list &key timeout) + (when (waiting-required (wait-list-waiters wait-list)) + (let ((rv (wsa-wait-for-multiple-events 1 (wait-list-%wait wait-list) + nil + (if timeout + (truncate (* 1000 timeout)) + +wsa-infinite+) + nil))) + (ecase rv + ((#.+wsa-wait-event-0+) + (update-ready-and-state-slots wait-list)) + ((#.+wsa-wait-timeout+)) ; do nothing here + ((#.+wsa-wait-failed+) + (maybe-wsa-error rv)))))) + + (defun %add-waiter (wait-list waiter) + (let ((events (etypecase waiter + (stream-server-usocket (logior fd-connect fd-accept fd-close)) + (stream-usocket (logior fd-read)) + (datagram-usocket (logior fd-read))))) + (maybe-wsa-error + (wsa-event-select (os-socket-handle waiter) (os-wait-list-%wait wait-list) events) + waiter))) + + (defun %remove-waiter (wait-list waiter) + (maybe-wsa-error + (wsa-event-select (os-socket-handle waiter) (os-wait-list-%wait wait-list) 0) + waiter)) +) ; progn + +#+(and sbcl win32) +(progn + ;; "SOCKET is defined as intptr_t in Windows headers; however, WS-SOCKET + ;; is defined as unsigned-int, i.e. 32-bit even on 64-bit platform. It + ;; seems to be a good thing to redefine WS-SOCKET as SB-ALIEN:SIGNED, + ;; which is always machine word-sized (exactly as intptr_t; + ;; N.B. as of Windows/x64, long and signed-long are 32-bit, and thus not + ;; enough -- potentially)." + ;; -- Anton Kovalenko , Mar 22, 2011 + (sb-alien:define-alien-type ws-socket sb-alien:signed) + + (sb-alien:define-alien-type ws-dword sb-alien:unsigned-long) + (sb-alien:define-alien-type ws-event sb-alien::hinstance) + + (sb-alien:define-alien-type nil + (sb-alien:struct wsa-network-events + (network-events sb-alien:long) + (error-code (array sb-alien:int 10)))) ; 10 = fd-max-events + + (sb-alien:define-alien-routine ("WSACreateEvent" wsa-event-create) + ws-event) ; return type only + + (sb-alien:define-alien-routine ("WSACloseEvent" wsa-event-close) + (boolean #.sb-vm::n-machine-word-bits) + (event-object ws-event)) + + ;; not used + (sb-alien:define-alien-routine ("WSAResetEvent" wsa-reset-event) + (boolean #.sb-vm::n-machine-word-bits) + (event-object ws-event)) + + (sb-alien:define-alien-routine ("WSAEnumNetworkEvents" wsa-enum-network-events) + sb-alien:int + (socket ws-socket) + (event-object ws-event) + (network-events (* (sb-alien:struct wsa-network-events)))) + + (sb-alien:define-alien-routine ("WSAEventSelect" wsa-event-select) + sb-alien:int + (socket ws-socket) + (event-object ws-event) + (network-events sb-alien:long)) + + (sb-alien:define-alien-routine ("WSAWaitForMultipleEvents" wsa-wait-for-multiple-events) + ws-dword + (number-of-events ws-dword) + (events (* ws-event)) + (wait-all-p (boolean #.sb-vm::n-machine-word-bits)) + (timeout ws-dword) + (alertable-p (boolean #.sb-vm::n-machine-word-bits))) + + (sb-alien:define-alien-routine ("ioctlsocket" wsa-ioctlsocket) + sb-alien:int + (socket ws-socket) + (cmd sb-alien:long) + (argp (* sb-alien:unsigned-long))) + + (defun maybe-wsa-error (rv &optional socket) + (unless (zerop rv) + (raise-usock-err (sockint::wsa-get-last-error) socket))) + + (defun os-socket-handle (usocket) + (sb-bsd-sockets:socket-file-descriptor (socket usocket))) + + (defun bytes-available-for-read (socket) + (sb-alien:with-alien ((int-ptr sb-alien:unsigned-long)) + (maybe-wsa-error (wsa-ioctlsocket (os-socket-handle socket) fionread (sb-alien:addr int-ptr)) + socket) + (prog1 int-ptr + (when (plusp int-ptr) + (setf (state socket) :read))))) + + (defun map-network-events (func network-events) + (let ((event-map (sb-alien:slot network-events 'network-events)) + (error-array (sb-alien:slot network-events 'error-code))) + (unless (zerop event-map) + (dotimes (i fd-max-events) + (unless (zerop (ldb (byte 1 i) event-map)) ;;### could be faster with ash and logand? + (funcall func (sb-alien:deref error-array i))))))) + + (defun update-ready-and-state-slots (wait-list) + (loop with sockets = (wait-list-waiters wait-list) + for socket in sockets do + (if (%ready-p socket) + (progn + (setf (state socket) :READ)) + (sb-alien:with-alien ((network-events (sb-alien:struct wsa-network-events))) + (let ((rv (wsa-enum-network-events (os-socket-handle socket) + (os-wait-list-%wait wait-list) + (sb-alien:addr network-events)))) + (if (zerop rv) + (map-network-events + #'(lambda (err-code) + (if (zerop err-code) + (progn + (setf (state socket) :READ) + (when (stream-server-usocket-p socket) + (setf (%ready-p socket) t))) + (raise-usock-err err-code socket))) + network-events) + (maybe-wsa-error rv socket))))))) + + (defun os-wait-list-%wait (wait-list) + (sb-alien:deref (wait-list-%wait wait-list))) + + (defun (setf os-wait-list-%wait) (value wait-list) + (setf (sb-alien:deref (wait-list-%wait wait-list)) value)) + + ;; "Event handles are leaking in current SBCL backend implementation, + ;; because of SBCL-unfriendly usage of finalizers. + ;; + ;; "SBCL never calls a finalizer that closes over a finalized object: a + ;; reference from that closure prevents its collection forever. That's + ;; the case with USOCKET in %SETUP-WAIT-LIST. + ;; + ;; "I use the following redefinition of %SETUP-WAIT-LIST: + ;; + ;; "Of course it may be rewritten with more clarity, but you can see the + ;; core idea: I'm closing over those components of WAIT-LIST that I need + ;; for finalization, not the wait-list itself. With the original + ;; %SETUP-WAIT-LIST, hunchentoot stops working after ~100k accepted + ;; connections; it doesn't happen with redefined %SETUP-WAIT-LIST." + ;; + ;; -- Anton Kovalenko , Mar 22, 2011 + + (defun %setup-wait-list (wait-list) + (setf (wait-list-%wait wait-list) (sb-alien:make-alien ws-event)) + (setf (os-wait-list-%wait wait-list) (wsa-event-create)) + (sb-ext:finalize wait-list + (let ((event-handle (os-wait-list-%wait wait-list)) + (alien (wait-list-%wait wait-list))) + #'(lambda () + (wsa-event-close event-handle) + (unless (null alien) + (sb-alien:free-alien alien)))))) + +) ; progn + +#+(and (or ecl clasp) (not win32)) +(progn + (defun wait-for-input-internal (wl &key timeout) + (with-mapped-conditions () + (multiple-value-bind (secs usecs) + (split-timeout (or timeout 1)) + (multiple-value-bind (result-fds err) + (read-select wl (when timeout secs) usecs) + (declare (ignore result-fds)) + (unless (null err) + (error (map-errno-error err))))))) + + (defun %setup-wait-list (wl) + (setf (wait-list-%wait wl) + (fdset-alloc))) + + (defun %add-waiter (wl w) + (declare (ignore wl w))) + + (defun %remove-waiter (wl w) + (declare (ignore wl w))) +) ; progn + +#+(and (or ecl clasp) win32 (not ecl-bytecmp)) +(progn + (defun maybe-wsa-error (rv &optional syscall) + (unless (zerop rv) + (sb-bsd-sockets::socket-error syscall))) + + (defun %setup-wait-list (wl) + (setf (wait-list-%wait wl) + (ffi:c-inline () () :int + "WSAEVENT event; + event = WSACreateEvent(); + @(return) = event;"))) + + (defun %add-waiter (wait-list waiter) + (let ((events (etypecase waiter + (stream-server-usocket (logior fd-connect fd-accept fd-close)) + (stream-usocket (logior fd-read)) + (datagram-usocket (logior fd-read))))) + (maybe-wsa-error + (ffi:c-inline ((socket-handle waiter) (wait-list-%wait wait-list) events) + (:fixnum :fixnum :fixnum) :fixnum + "int result; + result = WSAEventSelect((SOCKET)#0, (WSAEVENT)#1, (long)#2); + @(return) = result;") + '%add-waiter))) + + (defun %remove-waiter (wait-list waiter) + (maybe-wsa-error + (ffi:c-inline ((socket-handle waiter) (wait-list-%wait wait-list)) + (:fixnum :fixnum) :fixnum + "int result; + result = WSAEventSelect((SOCKET)#0, (WSAEVENT)#1, 0L); + @(return) = result;") + '%remove-waiter)) + + ;; TODO: how to handle error (result) in this call? + (declaim (inline %bytes-available-for-read)) + (defun %bytes-available-for-read (socket) + (ffi:c-inline ((socket-handle socket)) (:fixnum) :fixnum + "u_long nbytes; + int result; + nbytes = 0L; + result = ioctlsocket((SOCKET)#0, FIONREAD, &nbytes); + @(return) = nbytes;")) + + (defun bytes-available-for-read (socket) + (let ((nbytes (%bytes-available-for-read socket))) + (when (plusp nbytes) + (setf (state socket) :read)) + nbytes)) + + (defun update-ready-and-state-slots (wait-list) + (loop with sockets = (wait-list-waiters wait-list) + for socket in sockets do + (if (%ready-p socket) + (setf (state socket) :READ) + (let ((events (etypecase socket + (stream-server-usocket (logior fd-connect fd-accept fd-close)) + (stream-usocket (logior fd-read)) + (datagram-usocket (logior fd-read))))) + ;; TODO: check the iErrorCode array + (multiple-value-bind (valid-p ready-p) + (ffi:c-inline ((socket-handle socket) events) (:fixnum :fixnum) + (values :bool :bool) + ;; TODO: replace 0 (2nd arg) with (wait-list-%wait wait-list) + "WSANETWORKEVENTS network_events; + int i, result; + result = WSAEnumNetworkEvents((SOCKET)#0, 0, &network_events); + if (!result) { + @(return 0) = Ct; + @(return 1) = (#1 & network_events.lNetworkEvents)? Ct : Cnil; + } else { + @(return 0) = Cnil; + @(return 1) = Cnil; + }") + (if valid-p + (when ready-p + (setf (state socket) :READ) + (when (stream-server-usocket-p socket) + (setf (%ready-p socket) t))) + (sb-bsd-sockets::socket-error 'update-ready-and-state-slots))))))) + + (defun wait-for-input-internal (wait-list &key timeout) + (when (waiting-required (wait-list-waiters wait-list)) + (let ((rv (ffi:c-inline ((wait-list-%wait wait-list) + (if timeout + (truncate (* 1000 timeout)) + +wsa-infinite+)) + (:fixnum :fixnum) :fixnum + "DWORD result; + WSAEVENT events[1]; + events[0] = (WSAEVENT)#0; + result = WSAWaitForMultipleEvents(1, events, NULL, #1, NULL); + @(return) = result;"))) + (ecase rv + ((#.+wsa-wait-event-0+) + (update-ready-and-state-slots (wait-list-waiters wait-list))) + ((#.+wsa-wait-timeout+)) ; do nothing here + ((#.+wsa-wait-failed+) + (sb-bsd-sockets::socket-error 'wait-for-input-internal)))))) + +) ; progn diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/scl.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/scl.lisp new file mode 100644 index 0000000..d26b7c9 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/backend/scl.lisp @@ -0,0 +1,266 @@ +;;;; See LICENSE for licensing information. + +(in-package :usocket) + +(defparameter +scl-error-map+ + (append +unix-errno-condition-map+ + +unix-errno-error-map+)) + +(defun scl-map-socket-error (err &key condition socket) + (let ((usock-err (cdr (assoc err +scl-error-map+ :test #'member)))) + (cond (usock-err + (if (subtypep usock-err 'error) + (error usock-err :socket socket) + (signal usock-err :socket socket))) + (t + (error 'unknown-error + :socket socket + :real-error condition))))) + +(defun handle-condition (condition &optional (socket nil) (host-or-ip nil)) + "Dispatch correct usocket condition." + (typecase condition + (ext::socket-error + (scl-map-socket-error (ext::socket-errno condition) + :socket socket + :condition condition)))) + +(defun socket-connect (host port &key (protocol :stream) (element-type 'character) + timeout deadline (nodelay t nodelay-specified) + (local-host nil local-host-p) + (local-port nil local-port-p) + &aux + (patch-udp-p (fboundp 'ext::inet-socket-send-to))) + (when (and nodelay-specified + (not (eq nodelay :if-supported))) + (unsupported 'nodelay 'socket-connect)) + (when deadline (unsupported 'deadline 'socket-connect)) + (when timeout (unsupported 'timeout 'socket-connect)) + (when (and local-host-p (not patch-udp-p)) + (unsupported 'local-host 'socket-connect :minimum "1.3.9")) + (when (and local-port-p (not patch-udp-p)) + (unsupported 'local-port 'socket-connect :minimum "1.3.9")) + + (let ((socket)) + (ecase protocol + (:stream + (setf socket (let ((args (list (host-to-hbo host) port :kind protocol))) + (when (and patch-udp-p (or local-host-p local-port-p)) + (nconc args (list :local-host (when local-host + (host-to-hbo local-host)) + :local-port local-port))) + (with-mapped-conditions (socket) + (apply #'ext:connect-to-inet-socket args)))) + (let ((stream (sys:make-fd-stream socket :input t :output t + :element-type element-type + :buffering :full))) + (make-stream-socket :socket socket :stream stream))) + (:datagram + (when (not patch-udp-p) + (error 'unsupported + :feature '(protocol :datagram) + :context 'socket-connect + :minumum "1.3.9")) + (setf socket + (if (and host port) + (let ((args (list (host-to-hbo host) port :kind protocol))) + (when (and patch-udp-p (or local-host-p local-port-p)) + (nconc args (list :local-host (when local-host + (host-to-hbo local-host)) + :local-port local-port))) + (with-mapped-conditions (socket) + (apply #'ext:connect-to-inet-socket args))) + (if (or local-host-p local-port-p) + (with-mapped-conditions () + (ext:create-inet-listener (or local-port 0) + protocol + :host (when local-host + (if (ip= local-host *wildcard-host*) + 0 + (host-to-hbo local-host))))) + (with-mapped-conditions () + (ext:create-inet-socket protocol))))) + (let ((usocket (make-datagram-socket socket :connected-p (and host port t)))) + (ext:finalize usocket #'(lambda () + (when (%open-p usocket) + (ext:close-socket socket)))) + usocket))))) + +(defun socket-listen (host port + &key reuseaddress + (reuse-address nil reuse-address-supplied-p) + (backlog 5) + (element-type 'character)) + (let* ((reuseaddress (if reuse-address-supplied-p reuse-address reuseaddress)) + (host (if (ip= host *wildcard-host*) + 0 + (host-to-hbo host))) + (server-sock + (with-mapped-conditions () + (ext:create-inet-listener port :stream + :host host + :reuse-address reuseaddress + :backlog backlog)))) + (make-stream-server-socket server-sock :element-type element-type))) + +(defmethod socket-accept ((usocket stream-server-usocket) &key element-type) + (with-mapped-conditions (usocket) + (let* ((sock (ext:accept-tcp-connection (socket usocket))) + (stream (sys:make-fd-stream sock :input t :output t + :element-type (or element-type + (element-type usocket)) + :buffering :full))) + (make-stream-socket :socket sock :stream stream)))) + +;; Sockets and their associated streams are modelled as +;; different objects. Be sure to close the socket stream +;; when closing stream-sockets; it makes sure buffers +;; are flushed and the socket is closed correctly afterwards. +(defmethod socket-close ((usocket usocket)) + "Close socket." + (with-mapped-conditions (usocket) + (ext:close-socket (socket usocket)))) + +(defmethod socket-close ((usocket stream-usocket)) + "Close socket." + (with-mapped-conditions (usocket) + (close (socket-stream usocket)))) + +(defmethod socket-close :after ((socket datagram-usocket)) + (setf (%open-p socket) nil)) + +(defmethod socket-shutdown ((usocket usocket) direction) + (declare (ignore usocket direction)) + (unsupported "shutdown" 'socket-shutdown)) + +(defmethod socket-send ((usocket datagram-usocket) buffer size &key host port) + (let ((s (socket usocket)) + (host (if host (host-to-hbo host))) + (real-buffer (if (zerop offset) + buffer + (subseq buffer offset (+ offset size))))) + (multiple-value-bind (result errno) + (ext:inet-socket-send-to s real-buffer size + :remote-host host :remote-port port) + (or result + (scl-map-socket-error errno :socket usocket))))) + +(defmethod socket-receive ((socket datagram-usocket) buffer length &key) + (declare (values (simple-array (unsigned-byte 8) (*)) ; buffer + (integer 0) ; size + (unsigned-byte 32) ; host + (unsigned-byte 16))) ; port + (let ((s (socket socket))) + (let ((real-buffer (or buffer + (make-array length :element-type '(unsigned-byte 8)))) + (real-length (or length + (length buffer)))) + (multiple-value-bind (result errno remote-host remote-port) + (ext:inet-socket-receive-from s real-buffer real-length) + (if result + (values real-buffer result remote-host remote-port) + (scl-map-socket-error errno :socket socket)))))) + +(defmethod get-local-name ((usocket usocket)) + (multiple-value-bind (address port) + (with-mapped-conditions (usocket) + (ext:get-socket-host-and-port (socket usocket))) + (values (hbo-to-vector-quad address) port))) + +(defmethod get-peer-name ((usocket stream-usocket)) + (multiple-value-bind (address port) + (with-mapped-conditions (usocket) + (ext:get-peer-host-and-port (socket usocket))) + (values (hbo-to-vector-quad address) port))) + +(defmethod get-local-address ((usocket usocket)) + (nth-value 0 (get-local-name usocket))) + +(defmethod get-peer-address ((usocket stream-usocket)) + (nth-value 0 (get-peer-name usocket))) + +(defmethod get-local-port ((usocket usocket)) + (nth-value 1 (get-local-name usocket))) + +(defmethod get-peer-port ((usocket stream-usocket)) + (nth-value 1 (get-peer-name usocket))) + + +(defun get-host-by-address (address) + (multiple-value-bind (host errno) + (ext:lookup-host-entry (host-byte-order address)) + (cond (host + (ext:host-entry-name host)) + (t + (let ((condition (cdr (assoc errno +unix-ns-error-map+)))) + (cond (condition + (error condition :host-or-ip address)) + (t + (error 'ns-unknown-error :host-or-ip address + :real-error errno)))))))) + +(defun get-hosts-by-name (name) + (multiple-value-bind (host errno) + (ext:lookup-host-entry name) + (cond (host + (mapcar #'hbo-to-vector-quad + (ext:host-entry-addr-list host))) + (t + (let ((condition (cdr (assoc errno +unix-ns-error-map+)))) + (cond (condition + (error condition :host-or-ip name)) + (t + (error 'ns-unknown-error :host-or-ip name + :real-error errno)))))))) + +(defun get-host-name () + (unix:unix-gethostname)) + + +;; +;; +;; WAIT-LIST part +;; + + +(defun %add-waiter (wl waiter) + (declare (ignore wl waiter))) + +(defun %remove-waiter (wl waiter) + (declare (ignore wl waiter))) + +(defun %setup-wait-list (wl) + (declare (ignore wl))) + +(defun wait-for-input-internal (wait-list &key timeout) + (let* ((sockets (wait-list-waiters wait-list)) + (pollfd-size (alien:alien-size (alien:struct unix::pollfd) :bytes)) + (nfds (length sockets)) + (bytes (* nfds pollfd-size))) + (alien:with-bytes (fds-sap bytes) + (do ((sockets sockets (rest sockets)) + (base 0 (+ base 8))) + ((endp sockets)) + (let ((fd (socket (first sockets)))) + (setf (sys:sap-ref-32 fds-sap base) fd) + (setf (sys:sap-ref-16 fds-sap (+ base 4)) unix::pollin))) + (multiple-value-bind (result errno) + (let ((thread:*thread-whostate* "Poll wait") + (timeout (if timeout + (truncate (* timeout 1000)) + -1))) + (declare (inline unix:unix-poll)) + (unix:unix-poll (alien:sap-alien fds-sap + (* (alien:struct unix::pollfd))) + nfds timeout)) + (cond ((not result) + (error "~@" + (unix:get-unix-error-msg errno))) + (t + (do ((sockets sockets (rest sockets)) + (base 0 (+ base 8))) + ((endp sockets)) + (let ((flags (sys:sap-ref-16 fds-sap (+ base 6)))) + (unless (zerop (logand flags unix::pollin)) + (setf (state (first sockets)) :READ)))))))))) + diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/condition.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/condition.lisp new file mode 100644 index 0000000..1e1dc44 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/condition.lisp @@ -0,0 +1,237 @@ +;;;; -*- Mode: LISP; Base: 10; Syntax: ANSI-Common-lisp; Package: USOCKET -*- +;;;; See LICENSE for licensing information. + +(in-package :usocket) + +;; Condition signalled by operations with unsupported arguments +;; For trivial-sockets compatibility. + +(define-condition insufficient-implementation (error) + ((feature :initarg :feature :reader feature) + (context :initarg :context :reader context + :documentation "String designator of the public API function which +the feature belongs to.")) + (:documentation "The ancestor of all errors usocket may generate +because of insufficient support from the underlying implementation +with respect to the arguments given to `function'. + +One call may signal several errors, if the caller allows processing +to continue. +")) + +(define-condition unsupported (insufficient-implementation) + ((minimum :initarg :minimum :reader minimum + :documentation "Indicates the minimal version of the +implementation required to support the requested feature.")) + (:report (lambda (c stream) + (format stream "~A in ~A is unsupported." + (feature c) (context c)) + (when (minimum c) + (format stream " Minimum version (~A) is required." + (minimum c))))) + (:documentation "Signalled when the underlying implementation +doesn't allow supporting the requested feature. + +When you see this error, go bug your vendor/implementation developer!")) + +(define-condition unimplemented (insufficient-implementation) + () + (:report (lambda (c stream) + (format stream "~A in ~A is unimplemented." + (feature c) (context c)))) + (:documentation "Signalled if a certain feature might be implemented, +based on the features of the underlying implementation, but hasn't +been implemented yet.")) + +;; Conditions raised by sockets operations + +(define-condition socket-condition (condition) + ((socket :initarg :socket + :accessor usocket-socket)) + ;;###FIXME: no slots (yet); should at least be the affected usocket... + (:documentation "Parent condition for all socket related conditions.")) + +(define-condition socket-error (socket-condition error) + () ;; no slots (yet) + (:documentation "Parent error for all socket related errors")) + +(define-condition ns-condition (condition) + ((host-or-ip :initarg :host-or-ip + :accessor host-or-ip)) + (:documentation "Parent condition for all name resolution conditions.")) + +(define-condition ns-error (ns-condition error) + () + (:documentation "Parent error for all name resolution errors.")) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defun define-usocket-condition-class (class &rest parents) + `(progn + (define-condition ,class ,parents ()) + (eval-when (:load-toplevel :execute) + (export ',class))))) + +(defmacro define-usocket-condition-classes (class-list parents) + `(progn ,@(mapcar #'(lambda (x) + (apply #'define-usocket-condition-class + x parents)) + class-list))) + +;; Mass define and export our conditions +(define-usocket-condition-classes + (interrupted-condition) + (socket-condition)) + +(define-condition unknown-condition (socket-condition) + ((real-condition :initarg :real-condition + :accessor usocket-real-condition)) + (:documentation "Condition raised when there's no other - more applicable - +condition available.")) + + +;; Mass define and export our errors +(define-usocket-condition-classes + (address-in-use-error + address-not-available-error + bad-file-descriptor-error + connection-refused-error + connection-aborted-error + connection-reset-error + invalid-argument-error + no-buffers-error + operation-not-supported-error + operation-not-permitted-error + protocol-not-supported-error + socket-type-not-supported-error + network-unreachable-error + network-down-error + network-reset-error + host-down-error + host-unreachable-error + shutdown-error + timeout-error + deadline-timeout-error + invalid-socket-error + invalid-socket-stream-error) + (socket-error)) + +(define-condition unknown-error (socket-error) + ((real-error :initarg :real-error + :accessor usocket-real-error + :initform nil) + (errno :initarg :errno + :reader usocket-errno + :initform 0)) + (:report (lambda (c stream) + (typecase c + (simple-condition + (format stream + (simple-condition-format-control (usocket-real-error c)) + (simple-condition-format-arguments (usocket-real-error c)))) + (otherwise + (format stream "The condition ~A occurred with errno: ~D." + (usocket-real-error c) + (usocket-errno c)))))) + (:documentation "Error raised when there's no other - more applicable - +error available.")) + +(define-usocket-condition-classes + (ns-try-again-condition) + (ns-condition)) + +(define-condition ns-unknown-condition (ns-condition) + ((real-condition :initarg :real-condition + :accessor ns-real-condition + :initform nil)) + (:documentation "Condition raised when there's no other - more applicable - +condition available.")) + +(define-usocket-condition-classes + ;; the no-data error code in the Unix 98 api + ;; isn't really an error: there's just no data to return. + ;; with lisp, we just return NIL (indicating no data) instead of + ;; raising an exception... + (ns-host-not-found-error + ns-no-recovery-error) + (ns-error)) + +(define-condition ns-unknown-error (ns-error) + ((real-error :initarg :real-error + :accessor ns-real-error + :initform nil)) + (:report (lambda (c stream) + (typecase c + (simple-condition + (format stream + (simple-condition-format-control (usocket-real-error c)) + (simple-condition-format-arguments (usocket-real-error c)))) + (otherwise + (format stream "The condition ~A occurred." (usocket-real-error c)))))) + (:documentation "Error raised when there's no other - more applicable - +error available.")) + +(defmacro with-mapped-conditions ((&optional socket host-or-ip) &body body) + `(handler-bind ((condition + #'(lambda (c) (handle-condition c ,socket ,host-or-ip)))) + ,@body)) + +(defparameter +unix-errno-condition-map+ + `(((11) . ns-try-again-condition) ;; EAGAIN + ((35) . ns-try-again-condition) ;; EDEADLCK + ((4) . interrupted-condition))) ;; EINTR + +(defparameter +unix-errno-error-map+ + ;;### the first column is for non-(linux or srv4) systems + ;; the second for linux + ;; the third for srv4 + ;;###FIXME: How do I determine on which Unix we're running + ;; (at least in clisp and sbcl; I know about cmucl...) + ;; The table below works under the assumption we'll *only* see + ;; socket associated errors... + `(((48 98) . address-in-use-error) + ((49 99) . address-not-available-error) + ((9) . bad-file-descriptor-error) + ((61 111) . connection-refused-error) + ((54 104) . connection-reset-error) + ((53 103) . connection-aborted-error) + ((22) . invalid-argument-error) + ((55 105) . no-buffers-error) + ((12) . out-of-memory-error) + ((45 95) . operation-not-supported-error) + ((1) . operation-not-permitted-error) + ((43 92) . protocol-not-supported-error) + ((44 93) . socket-type-not-supported-error) + ((51 101) . network-unreachable-error) + ((50 100) . network-down-error) + ((52 102) . network-reset-error) + ((58 108) . already-shutdown-error) + ((60 110) . timeout-error) + ((64 112) . host-down-error) + ((65 113) . host-unreachable-error))) + +(defun map-errno-condition (errno) + (cdr (assoc errno +unix-errno-error-map+ :test #'member))) + +(defun map-errno-error (errno) + (cdr (assoc errno +unix-errno-error-map+ :test #'member))) + +(defparameter +unix-ns-error-map+ + `((1 . ns-host-not-found-error) + (2 . ns-try-again-condition) + (3 . ns-no-recovery-error))) + +(defmacro unsupported (feature context &key minimum) + `(cerror "Ignore it and continue" 'unsupported + :feature ,feature + :context ,context + :minimum ,minimum)) + +(defmacro unimplemented (feature context) + `(signal 'unimplemented :feature ,feature :context ,context)) + +;;; People may want to ignore all unsupported warnings, here it is. +(defmacro ignore-unsupported-warnings (&body body) + `(handler-bind ((unsupported + #'(lambda (c) + (declare (ignore c)) (continue)))) + (progn ,@body))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/doc/intro.dita b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/doc/intro.dita new file mode 100644 index 0000000..174639a --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/doc/intro.dita @@ -0,0 +1,10 @@ + + + + + +Introduction + +Chun Tian +

diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/doc/reference.dita b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/doc/reference.dita new file mode 100644 index 0000000..d4e3f9f --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/doc/reference.dita @@ -0,0 +1,11 @@ + + + + + + +API References +Chun Tian +

diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/doc/usocket.ditamap b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/doc/usocket.ditamap new file mode 100644 index 0000000..2dfe2b9 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/doc/usocket.ditamap @@ -0,0 +1,11 @@ + + + + + + +USOCKET Manual + + +API References diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/abcl-socket.txt b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/abcl-socket.txt new file mode 100644 index 0000000..531ace9 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/abcl-socket.txt @@ -0,0 +1,18 @@ + +ABCL provides a callback interface to java objects, next to these calls: + + - ext:make-socket + - ext:socket-close + - ext:make-server-socket + - ext:socket-accept + - ext:get-socket-stream (returning an io-stream) + +abcl-swank (see SLIME) shows how to call directly into java. + + +See for the sockets implementation: + + - src/org/armedbear/lisp + * socket.lisp + * socket_stream.java + * SocketStream.java diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/active-sockets-apis.txt b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/active-sockets-apis.txt new file mode 100644 index 0000000..b74ccfe --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/active-sockets-apis.txt @@ -0,0 +1,75 @@ + -*- text -*- + +A document to summarizing which API's of the different implementations +are associated with 'Step 1'. + +Interface to be implemented in step 1: + + - socket-connect + - socket-close + - get-host-by-address + - get-hosts-by-name + +(and something to do with errors; maybe move this to step 1a?) + +SBCL +==== + + sockets: + - socket-bind + - make-instance 'inet-socket + - socket-make-stream + - socket-connect (ip vector-quad) port + - socket-close + + DNS name resolution: + - get-host-by-name + - get-host-by-address + - ::host-ent-addresses + - host-ent-name + + +CMUCL +===== + + sockets: + - ext:connect-to-inet-socket (ip integer) port + - sys:make-fd-stream + - ext:close-socket + + DNS name resolution: + - ext:host-entry-name + - ext::lookup-host-entry + - ext:host-entry-addr-list + - ext:lookup-host-entry + + +ABCL +==== + + sockets + - ext:socket-connect (hostname string) port + - ext:get-socket-stream + - ext:socket-close + + +clisp +===== + + sockets + - socket-connect port (hostname string) + - close (socket) + + +Allegro +======= + + sockets + - make-socket + - socket-connect + - close + + DNS resolution + - lookup-hostname + - ipaddr-to-hostname + diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/address-apis.txt b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/address-apis.txt new file mode 100644 index 0000000..2661ac2 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/address-apis.txt @@ -0,0 +1,73 @@ + + -*- text -*- + +Step 2 of the master plan: Implementing (get-local-address sock) and +(get-peer-address sock). + + +Step 2 is about implementing: + + (get-local-address sock) -> ip + (get-peer-address sock) -> ip + (get-local-port sock) -> port + (get-peer-port sock) -> port + (get-local-name sock) -> ip, port + (get-peer-name sock) -> ip, port + + +ABCL +==== + + FFI / J-calls to "getLocalAddress"+"getAddress", "getLocalPort" (local) + FFI / J-calls to "getInetAddress"+"getAddress", "getPort" (peer) + + (see SLIME / swank-abcl.lisp for an example on how to do that) + + +Allegro +======= + + (values (socket:remote-host sock) + (socket:remote-port)) -> 32bit ip, port + + (values (socket:local-host sock) + (socket:local-port sock)) -> 32bit ip, port + +CLISP +===== + + (socket:socket-stream-local sock nil) -> address (as dotted quad), port + (socket:socket-stream-peer sock nil) -> address (as dotted quad), port + + +CMUCL +===== + + (ext:get-peer-host-and-port sock-fd) -> 32-bit-addr, port (peer) + (ext:get-socket-host-and-port sock-fd) -> 32-bit-addr, port (local) + + +LispWorks +========= + + (comm:socket-stream-address sock-stream) -> 32-bit-addr, port + or: (comm:get-socket-address sock) -> 32-bit-addr, port + + (comm:socket-stream-peer-address sock-stream) -> 32-bit-addr, port + or: (comm:get-socket-peer-address sock) -> 32-bit-addr, port + + +OpenMCL +======= + + (values (ccl:local-host sock) (ccl:local-port sock)) -> 32-bit ip, port + (values (ccl:remote-host sock) (ccl:remote-port sock)) -> 32-bit ip, port + + +SBCL +==== + + (sb-bsd-sockets:socket-name sock) -> vector-quad, port + (sb-bsd-sockets:socket-peer-name sock) -> vector-quad, port + + diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/allegro-socket.txt b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/allegro-socket.txt new file mode 100644 index 0000000..8f90ca7 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/allegro-socket.txt @@ -0,0 +1,46 @@ + + +(require :sock) + +accept-connection (sock passive-socket) &key wait Generic function. +dotted-to-ipaddr dotted &key errorp Function. +ipaddr-to-dotted ipaddr &key values Function. +ipaddr-to-hostname ipaddr Function. +lookup-hostname hostname +lookup-port portname protocol Function. +make-socket &key type format address-family connect &allow-other-keys Function. +with-pending-connect &body body Macro. +receive-from (sock datagram-socket) size &key buffer extract Generic function. +send-to sock &key +shutdown sock &key direction +socket-control stream &key output-chunking output-chunking-eof input-chunking +socket-os-fd sock Generic function. + +remote-host socket Generic function. +local-host socket Generic function. +local-port socket + +remote-filename socket +local-filename socket +remote-port socket +socket-address-family socket +socket-connect socket +socket-format socket +socket-type socket + +errors + +:address-in-use Local socket address already in use +:address-not-available Local socket address not available +:network-down Network is down +:network-reset Network has been reset +:connection-aborted Connection aborted +:connection-reset Connection reset by peer +:no-buffer-space No buffer space +:shutdown Connection shut down +:connection-timed-out Connection timed out +:connection-refused Connection refused +:host-down Host is down +:host-unreachable Host is unreachable +:unknown Unknown error + diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/backends.txt b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/backends.txt new file mode 100644 index 0000000..c2c770f --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/backends.txt @@ -0,0 +1,60 @@ + -*- text -*- + +$Id$ + +A document to describe which APIs a backend should implement. + + +Each backend should implement: + +Functions: + + - handle-condition + - socket-connect + - socket-listen + - get-hosts-by-name [ optional ] + - get-host-by-address [ optional ] + + - wait-for-input-internal (new in 0.4.x) + +Methods: + + - socket-close + - socket-accept + - get-local-name + - get-peer-name + + and - for ip sockets - these methods: + + - get-local-address + - get-local-port + - get-peer-address + - get-peer-port + + +An error-handling function, resolving implementation specific errors +to this list of errors: + + - address-in-use-error + - address-not-available-error + - bad-file-descriptor-error + - connection-refused-error + - invalid-argument-error + - no-buffers-error + - operation-not-supported-error + - operation-not-permitted-error + - protocol-not-supported-error + - socket-type-not-supported-error + - network-unreachable-error + - network-down-error + - network-reset-error + - host-down-error + - host-unreachable-error + - shutdown-error + - timeout-error + - unkown-error + +and these conditions: + + - interrupted-condition + - unkown-condition diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/clisp-sockets.txt b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/clisp-sockets.txt new file mode 100644 index 0000000..e680fe8 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/clisp-sockets.txt @@ -0,0 +1,38 @@ +http://clisp.cons.org/impnotes.html#socket + +(SOCKET:SOCKET-SERVER &OPTIONAL [port-or-socket]) +(SOCKET:SOCKET-SERVER-HOST socket-server) +(SOCKET:SOCKET-SERVER-PORT socket-server) +(SOCKET:SOCKET-WAIT socket-server &OPTIONAL [seconds [microseconds]]) +(SOCKET:SOCKET-ACCEPT socket-server &KEY :ELEMENT-TYPE :EXTERNAL-FORMAT :BUFFERED :TIMEOUT) +(SOCKET:SOCKET-CONNECT port &OPTIONAL [host] &KEY :ELEMENT-TYPE :EXTERNAL-FORMAT :BUFFERED :TIMEOUT) +(SOCKET:SOCKET-STATUS socket-stream-or-list &OPTIONAL [seconds [microseconds]]) +(SOCKET:SOCKET-STREAM-HOST socket-stream) +(SOCKET:SOCKET-STREAM-PORT socket-stream) +(SOCKET:SOCKET-SERVICE-PORT &OPTIONAL service-name (protocol "tcp")) +(SOCKET:SOCKET-STREAM-PEER socket-stream [do-not-resolve-p]) +(SOCKET:SOCKET-STREAM-LOCAL socket-stream [do-not-resolve-p]) +(SOCKET:SOCKET-STREAM-SHUTDOWN socket-stream direction) +(SOCKET:SOCKET-OPTIONS socket-server &REST {option}*) + + +(posix:resolve-host-ipaddr &optional host) + +with the host-ent structure: + + name - host name + aliases - LIST of aliases + addr-list - LIST of IPs as dotted quads (IPv4) or coloned octets (IPv6) + addrtype - INTEGER address type IPv4 or IPv6 + + +Errors are of type + +SYSTEM::SIMPLE-OS-ERROR + with a 1 element (integer) SYSTEM::$FORMAT-ARGUMENTS list + +This integer stores the OS error reported; meaning WSA* codes on Win32 +and E* codes on *nix, only: unix.lisp in CMUCL shows +BSD, Linux and SRV4 have different number assignments for the same +E* constant names :-( + diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/cmucl-sockets.txt b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/cmucl-sockets.txt new file mode 100644 index 0000000..7b81ca3 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/cmucl-sockets.txt @@ -0,0 +1,69 @@ +http://cvs2.cons.org/ftp-area/cmucl/doc/cmu-user/internet.html + +$Id$ + +extensions:lookup-host-entry host + +[structure] +host-entry + + name aliases addr-type addr-list + +[Function] +extensions:create-inet-listener port &optional kind &key :reuse-address :backlog :interface + => socket fd + +[Function] +extensions:accept-tcp-connection unconnected + => socket fd, address + +[Function] +extensions:connect-to-inet-socket host port &optional kind + => socket fd + +[Function] +extensions:close-socket socket + + + +[Private function] +extensions::get-peer-host-and-port socket-fd + +[Private function] +extentsions::get-socket-host-and-port socket-fd + + + +There's currently only 1 condition to be raised: + + SOCKET-ERROR (derived from SIMPLE-ERROR) + which has a SOCKET-ERRNO slot containing the unix error number. + + + + +[Function] +extensions:add-oob-handler fd char handler + +[Function] +extensions:remove-oob-handler fd char + +[Function] +extensions:remove-all-oob-handlers fd + +[Function] +extensions:send-character-out-of-band fd char + +[Function] +extensions:create-inet-socket &optional type + => socket fd + +[Function] +extensions:get-socket-option socket level optname + +[Function] +extensions:set-socket-option socket level optname optval + +[Function] +extensions:ip-string addr + diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/design.txt b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/design.txt new file mode 100644 index 0000000..2f9c487 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/design.txt @@ -0,0 +1,136 @@ + + -*- text -*- + +$Id$ + + + usocket: Universal sockets library + ================================== + +Contents +======== + + * Motivation + * Design goal + * Functional requirements + * Class structure + + + +Motivation +========== + +There are 2 other portability sockets packages [that I know of] +out there: + + 1) trivial-sockets + 2) acl-compat (which is a *lot* broader, but contains sockets too) + +The first misses some functionality which is fundamental when +the requirements stop being 'trivial', such as finding out the +addresses of either side connected to the tcp/ip stream. + +The second, being a complete compatibility library for Allegro, +contains much more than only sockets. Next to that, as the docs +say, is it mainly directed at providing the functionality required +to port portable-allegroserve - meaning it may be (very) incomplete +on some platforms. + +So, that's why I decided to inherit Erik Enge's project to build +a library with the intention to provide portability code in only +1 area of programming, targeted at 'not so trivial' programming. + +Also, I need this library to extend cl-irc with full DCC functionality. + + + +Design goal +=========== + +To provide a portable TCP/IP socket interface for as many +implementations as possible, while keeping the portability layer +as thin as possible. + + + +Functional requirements +======================= + +The interface provided should allow: + - 'client'/active sockets + - 'server'/listening sockets + - provide the usual stream methods to operate on the connection stream + (not necessarily the socket itself; maybe a socket slot too) + +For now, as long as there are no possibilities to have UDP sockets +to write a DNS client library: (which in the end may work better, +because in this respect all implementations are different...) + - retrieve IP addresses/ports for both sides of the connection + +Several relevant support functionalities will have to be provided too: + - long <-> quad-vector operators + - quad-vector <-> string operators + - hostname <-> quad-vector operators (hostname resolution) + + +Minimally, I'd like to support: + - SBCL + - CMUCL + - ABCL (ArmedBear) + - clisp + - Allegro + - LispWorks + - OpenMCL + + +Comments on the design above +============================ + +I don't think it's a good idea to implement name lookup in the +very first of steps: we'll see if this is required to get the +package accepted; not all implementations support it. + +Name resolution errors ... +Since there is no name resolution library (yet), nor standardized +hooks into the standard C library to do it the same way on +all platforms, name resolution errors can manifest themselves +in a lot of different ways. How to marshall these to the +library users? + +Several solutions come to mind: + +1) Map them to 'unknown-error +2) Give them their own errors and map to those + ... which implies that they are actually supported atm. +3) ... + +Given that the library doesn't now, but may in the future, +include name resolution officially, I tend to think (1) is the +right answer: it leaves it all undecided. + +These errors can be raised by the nameresolution service +(netdb.h) as values for 'int h_errno': + +- HOST_NOT_FOUND (1) +- TRY_AGAIN (2) /* Server fail or non-authoritive Host not found */ +- NO_RECOVERY (3) /* Failed permanently */ +- NO_DATA (4) /* Valid address, no data for requested record */ + +int *__h_errno_location(void) points to thread local h_errno on +threaded glibc2 systems. + + +Class structure +=============== + + usocket + | + +- datagram-usocket + +- stream-usocket + \- stream-server-usocket + +The usocket class will have methods to query local properties, such +as: + + - get-local-name: to query to which interface the socket is bound + - diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/errors.txt b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/errors.txt new file mode 100644 index 0000000..148525c --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/errors.txt @@ -0,0 +1,20 @@ +EADDRINUSE 48 address-in-use-error +EADDRNOTAVAIL 49 address-not-available-error +EAGAIN interrupted-error ;; not 1 error code: bsd == 11; non-bsd == 35 +EBADF 9 bad-file-descriptor-error +ECONNREFUSED 61 connection-refused-error +EINTR 4 interrupted-error +EINVAL 22 invalid-argument-error +ENOBUFS 55 no-buffers-error +ENOMEM 12 out-of-memory-error +EOPNOTSUPP 45 operation-not-supported-error +EPERM 1 operation-not-permitted-error +EPROTONOSUPPORT 43 protocol-not-supported-error +ESOCKTNOSUPPORT 44 socket-type-not-supported-error +ENETUNREACH 51 network-unreachable-error +ENETDOWN 50 network-down-error +ENETRESET 52 network-reset-error +ESHUTDOWN 58 already-shutdown-error +ETIMEDOUT 60 connection-timeout-error +EHOSTDOWN 64 host-down-error +EHOSTUNREACH 65 host-unreachable-error diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/lw-sockets.txt b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/lw-sockets.txt new file mode 100644 index 0000000..666ede8 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/lw-sockets.txt @@ -0,0 +1,41 @@ + +$Id$ + +http://www.lispworks.com/reference/lwu41/lwref/LWRM_37.HTM + +Package: COMM + +ip-address-string +socket-stream-address +socket-stream-peer-address +start-up-server +start-up-server-and-mp +string-ip-address +with-noticed-socket-stream + +Needed components for usocket: + +comm::get-fd-from-socket socket-fd + => socket-fd + +comm::accept-connection-to-socket socket-fd + => socket-fd + +comm::close-socket +comm::create-tcp-socket-for-service + => socket-fd + +open-tcp-stream peer-host peer-port &key direction element-type + => socket-stream + +get-host-entry (see http://www.lispworks.com/documentation/lw445/LWRM/html/lwref-30.htm#pgfId-897837) +get-socket-address + +get-socket-peer-address + => address, port + +socket-stream socket-fd + => stream + +socket socket-stream (guessed from http://www.lispworks.com/documentation/lw445/LWRM/html/lwref-43.htm) + => socket-fd diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/openmcl-sockets.txt b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/openmcl-sockets.txt new file mode 100644 index 0000000..1a7ee4d --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/openmcl-sockets.txt @@ -0,0 +1,27 @@ +http://openmcl.clozure.com/Doc/sockets.html + + make-socket [Function] + accept-connection [Function] + dotted-to-ipaddr [Function] + ipaddr-to-dotted [Function] + ipaddr-to-hostname [Function] + lookup-hostname [Function] + lookup-port [Function] + receive-from [Function] + send-to [Function] + shutdown [Function] + socket-os-fd [Function] + remote-port [Function] + local-host [Function] + local-port [Function] + + socket-address-family [Function] + + socket-connect [Function] + socket-format [Function] + socket-type [Function] + socket-error [Class] + socket-error-code [Function] + socket-error-identifier [Function] + socket-error-situation [Function] + close [method] diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/sb-bsd-sockets.txt b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/sb-bsd-sockets.txt new file mode 100644 index 0000000..e80b583 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/sb-bsd-sockets.txt @@ -0,0 +1,114 @@ +http://www.xach.com/sbcl/sb-bsd-sockets.html + +$Id$ + +package: sb-bsd-sockets + +class: socket + +slots: + + * file-descriptor : + * family : + * protocol : + * type : + * stream : + +operators: + + (socket-bind (s socket) &rest address) Generic Function + (socket-accept (socket socket)) Method + (socket-connect (s socket) &rest address) Generic Function + (socket-peername (socket socket)) Method + (socket-name (socket socket)) Method + (socket-receive (socket socket) buffer length &key oob peek waitall (element-type 'character)) Method + (socket-listen (socket socket) backlog) Method + (socket-close (socket socket)) Method + (socket-make-stream (socket socket) &rest args) Method + + (sockopt-reuse-address (socket socket) argument) Accessor + (sockopt-keep-alive (socket socket) argument) Accessor + (sockopt-oob-inline (socket socket) argument) Accessor + (sockopt-bsd-compatible (socket socket) argument) Accessor + (sockopt-pass-credentials (socket socket) argument) Accessor + (sockopt-debug (socket socket) argument) Accessor + (sockopt-dont-route (socket socket) argument) Accessor + (sockopt-broadcast (socket socket) argument) Accessor + (sockopt-tcp-nodelay (socket socket) argument) Accessor + +inet-domain sockets + +class: inet-socket + +slots: + + * family : + +operators: + + (make-inet-address dotted-quads) Function + (get-protocol-by-name name) Function + (make-inet-socket type protocol) Function + +file-domain sockets + +class: unix-socket + +slots: + + * family : + +class: host-ent + +Slots: + + * name : + * aliases : + * address-type : + * addresses : + + (host-ent-address (host-ent host-ent)) Method + (get-host-by-name host-name) Function + (get-host-by-address address) Function + (name-service-error where) Function + (non-blocking-mode (socket socket)) Method + +(define-socket-condition sockint::EADDRINUSE address-in-use-error) +(define-socket-condition sockint::EAGAIN interrupted-error) +(define-socket-condition sockint::EBADF bad-file-descriptor-error) +(define-socket-condition sockint::ECONNREFUSED connection-refused-error) +(define-socket-condition sockint::EINTR interrupted-error) +(define-socket-condition sockint::EINVAL invalid-argument-error) +(define-socket-condition sockint::ENOBUFS no-buffers-error) +(define-socket-condition sockint::ENOMEM out-of-memory-error) +(define-socket-condition sockint::EOPNOTSUPP operation-not-supported-error) +(define-socket-condition sockint::EPERM operation-not-permitted-error) +(define-socket-condition sockint::EPROTONOSUPPORT protocol-not-supported-error) +(define-socket-condition sockint::ESOCKTNOSUPPORT socket-type-not-supported-error) +(define-socket-condition sockint::ENETUNREACH network-unreachable-error) + +Exported errors: +* (apropos "ERROR" :sb-bsd-sockets) + +SB-BSD-SOCKETS:INTERRUPTED-ERROR +SB-BSD-SOCKETS:TRY-AGAIN-ERROR +* SB-BSD-SOCKETS:NO-RECOVERY-ERROR (EFAIL?) +SB-BSD-SOCKETS:CONNECTION-REFUSED-ERROR +SB-BSD-SOCKETS:INVALID-ARGUMENT-ERROR +* SB-BSD-SOCKETS:HOST-NOT-FOUND-ERROR +SB-BSD-SOCKETS:OPERATION-NOT-PERMITTED-ERROR +SB-BSD-SOCKETS:OPERATION-NOT-SUPPORTED-ERROR +SB-BSD-SOCKETS:PROTOCOL-NOT-SUPPORTED-ERROR +SB-BSD-SOCKETS:OPERATION-TIMEOUT-ERROR +SB-BSD-SOCKETS:SOCKET-TYPE-NOT-SUPPORTED-ERROR +SB-BSD-SOCKETS:NO-BUFFERS-ERROR +SB-BSD-SOCKETS:NETWORK-UNREACHABLE-ERROR +SB-BSD-SOCKETS:BAD-FILE-DESCRIPTOR-ERROR +SB-BSD-SOCKETS:ADDRESS-IN-USE-ERROR +SB-BSD-SOCKETS:OUT-OF-MEMORY-ERROR + +And 1 non-exported error: + +SB-BSD-SOCKETS::NO-ADDRESS-ERROR + +*-ed errors aren't yet addressed in the errorlist supported by usocket diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/usock-sockets.txt b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/usock-sockets.txt new file mode 100644 index 0000000..562dc58 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/notes/usock-sockets.txt @@ -0,0 +1,28 @@ +Package: + + clisp : socket + cmucl : extensions + sbcl : sb-bsd-sockets + lw : comm + openmcl: openmcl-socket + allegro: sock + +Connecting (TCP/inet only) + + clisp : socket-connect port &optional [host] &key :element-type :external-format :buffered :timeout = > socket-stream + cmucl : connect-to-inet-socket host port &optional kind => file descriptor + sbcl : sb-socket-connect socket &rest address => socket + lw : open-tcp-stream hostname service &key direction element-type buffered => stream-object + openmcl: socket-connect socket => :active, :passive or nil + allegro: make-socket (&rest args &key type format connect address-family eol) => socket + +Closing + + clisp : close socket + cmucl : close-socket socket + sbcl : socket-close socket + lw : close socket + openmcl: close socket + allegro: close socket + +Errors \ No newline at end of file diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/option.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/option.lisp new file mode 100644 index 0000000..4bc3e1b --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/option.lisp @@ -0,0 +1,353 @@ +;;;; -*- Mode: LISP; Base: 10; Syntax: ANSI-Common-lisp; Package: USOCKET -*- +;;;; SOCKET-OPTION, a high-level socket option get/set framework + +;;;; See LICENSE for licensing information. + +(in-package :usocket) + +;; put here because option.lisp is for native backend only +(defparameter *backend* :native) + +;;; Interface definition + +(defgeneric socket-option (socket option &key) + (:documentation + "Get a socket's internal options")) + +(defgeneric (setf socket-option) (new-value socket option &key) + (:documentation + "Set a socket's internal options")) + +;;; Handling of wrong type of arguments + +(defmethod socket-option ((socket usocket) (option t) &key) + (error 'type-error :datum option :expected-type 'keyword)) + +(defmethod (setf socket-option) (new-value (socket usocket) (option t) &key) + (declare (ignore new-value)) + (socket-option socket option)) + +(defmethod socket-option ((socket usocket) (option symbol) &key) + (if (keywordp option) + (error 'unimplemented :feature option :context 'socket-option) + (error 'type-error :datum option :expected-type 'keyword))) + +(defmethod (setf socket-option) (new-value (socket usocket) (option symbol) &key) + (declare (ignore new-value)) + (socket-option socket option)) + +;;; Socket option: RECEIVE-TIMEOUT (SO_RCVTIMEO) + +(defmethod socket-option ((usocket stream-usocket) + (option (eql :receive-timeout)) &key) + (declare (ignorable option)) + (let ((socket (socket usocket))) + (declare (ignorable socket)) + #+abcl + () ; TODO + #+allegro + () ; TODO + #+clisp + (socket:socket-options socket :so-rcvtimeo) + #+clozure + (ccl:stream-input-timeout socket) + #+cmu + (lisp::fd-stream-timeout (socket-stream usocket)) + #+(or ecl clasp) + (sb-bsd-sockets:sockopt-receive-timeout socket) + #+lispworks + (get-socket-receive-timeout socket) + #+mcl + () ; TODO + #+mocl + () ; unknown + #+sbcl + (sb-impl::fd-stream-timeout (socket-stream usocket)) + #+scl + ())) ; TODO + +(defmethod (setf socket-option) (new-value (usocket stream-usocket) + (option (eql :receive-timeout)) &key) + (declare (type number new-value) (ignorable new-value option)) + (let ((socket (socket usocket)) + (timeout new-value)) + (declare (ignorable socket timeout)) + #+abcl + () ; TODO + #+allegro + () ; TODO + #+clisp + (socket:socket-options socket :so-rcvtimeo timeout) + #+clozure + (setf (ccl:stream-input-timeout socket) timeout) + #+cmu + (setf (lisp::fd-stream-timeout (socket-stream usocket)) + (coerce timeout 'integer)) + #+(or ecl clasp) + (setf (sb-bsd-sockets:sockopt-receive-timeout socket) timeout) + #+lispworks + (set-socket-receive-timeout socket timeout) + #+mcl + () ; TODO + #+mocl + () ; unknown + #+sbcl + (setf (sb-impl::fd-stream-timeout (socket-stream usocket)) + (coerce timeout 'single-float)) + #+scl + () ; TODO + new-value)) + +;;; Socket option: SEND-TIMEOUT (SO_SNDTIMEO) + +(defmethod socket-option ((usocket stream-usocket) + (option (eql :send-timeout)) &key) + (declare (ignorable option)) + (let ((socket (socket usocket))) + (declare (ignorable socket)) + #+abcl + () ; TODO + #+allegro + () ; TODO + #+clisp + (socket:socket-options socket :so-sndtimeo) + #+clozure + (ccl:stream-output-timeout socket) + #+cmu + (lisp::fd-stream-timeout (socket-stream usocket)) + #+(or ecl clasp) + (sb-bsd-sockets:sockopt-send-timeout socket) + #+lispworks + (get-socket-send-timeout socket) + #+mcl + () ; TODO + #+mocl + () ; unknown + #+sbcl + (sb-impl::fd-stream-timeout (socket-stream usocket)) + #+scl + ())) ; TODO + +(defmethod (setf socket-option) (new-value (usocket stream-usocket) + (option (eql :send-timeout)) &key) + (declare (type number new-value) (ignorable new-value option)) + (let ((socket (socket usocket)) + (timeout new-value)) + (declare (ignorable socket timeout)) + #+abcl + () ; TODO + #+allegro + () ; TODO + #+clisp + (socket:socket-options socket :so-sndtimeo timeout) + #+clozure + (setf (ccl:stream-output-timeout socket) timeout) + #+cmu + (setf (lisp::fd-stream-timeout (socket-stream usocket)) + (coerce timeout 'integer)) + #+(or ecl clasp) + (setf (sb-bsd-sockets:sockopt-send-timeout socket) timeout) + #+lispworks + (set-socket-send-timeout socket timeout) + #+mcl + () ; TODO + #+mocl + () ; unknown + #+sbcl + (setf (sb-impl::fd-stream-timeout (socket-stream usocket)) + (coerce timeout 'single-float)) + #+scl + () ; TODO + new-value)) + +;;; Socket option: REUSE-ADDRESS (SO_REUSEADDR), for TCP server + +(defmethod socket-option ((usocket stream-server-usocket) + (option (eql :reuse-address)) &key) + (declare (ignorable option)) + (let ((socket (socket usocket))) + (declare (ignorable socket)) + #+abcl + () ; TODO + #+allegro + () ; TODO + #+clisp + (int->bool (socket:socket-options socket :so-reuseaddr)) + #+clozure + (int->bool (get-socket-option-reuseaddr socket)) + #+cmu + () ; TODO + #+lispworks + (get-socket-reuse-address socket) + #+mcl + () ; TODO + #+mocl + () ; unknown + #+(or ecl sbcl clasp) + (sb-bsd-sockets:sockopt-reuse-address socket) + #+scl + ())) ; TODO + +(defmethod (setf socket-option) (new-value (usocket stream-server-usocket) + (option (eql :reuse-address)) &key) + (declare (type boolean new-value) (ignorable new-value option)) + (let ((socket (socket usocket))) + (declare (ignorable socket)) + #+abcl + () ; TODO + #+allegro + (socket:set-socket-options socket option new-value) + #+clisp + (socket:socket-options socket :so-reuseaddr (bool->int new-value)) + #+clozure + (set-socket-option-reuseaddr socket (bool->int new-value)) + #+cmu + () ; TODO + #+lispworks + (set-socket-reuse-address socket new-value) + #+mcl + () ; TODO + #+mocl + () ; unknown + #+(or ecl sbcl clasp) + (setf (sb-bsd-sockets:sockopt-reuse-address socket) new-value) + #+scl + () ; TODO + new-value)) + +;;; Socket option: BROADCAST (SO_BROADCAST), for UDP client + +(defmethod socket-option ((usocket datagram-usocket) + (option (eql :broadcast)) &key) + (declare (ignorable option)) + (let ((socket (socket usocket))) + (declare (ignorable socket)) + #+abcl + () ; TODO + #+allegro + () ; TODO + #+clisp + (int->bool (socket:socket-options socket :so-broadcast)) + #+clozure + (int->bool (get-socket-option-broadcast socket)) + #+cmu + () ; TODO + #+(or ecl clasp) + () ; TODO + #+lispworks + () ; TODO + #+mcl + () ; TODO + #+mocl + () ; unknown + #+sbcl + (sb-bsd-sockets:sockopt-broadcast socket) + #+scl + ())) ; TODO + +(defmethod (setf socket-option) (new-value (usocket datagram-usocket) + (option (eql :broadcast)) &key) + (declare (type boolean new-value) + (ignorable new-value option)) + (let ((socket (socket usocket))) + (declare (ignorable socket)) + #+abcl + () ; TODO + #+allegro + (socket:set-socket-options socket option new-value) + #+clisp + (socket:socket-options socket :so-broadcast (bool->int new-value)) + #+clozure + (set-socket-option-broadcast socket (bool->int new-value)) + #+cmu + () ; TODO + #+(or ecl clasp) + () ; TODO + #+lispworks + () ; TODO + #+mcl + () ; TODO + #+mocl + () ; unknown + #+sbcl + (setf (sb-bsd-sockets:sockopt-broadcast socket) new-value) + #+scl + () ; TODO + new-value)) + +;;; Socket option: TCP-NODELAY (TCP_NODELAY), for TCP client + +(defmethod socket-option ((usocket stream-usocket) + (option (eql :tcp-no-delay)) &key) + (declare (ignorable option)) + (socket-option usocket :tcp-nodelay)) + +(defmethod socket-option ((usocket stream-usocket) + (option (eql :tcp-nodelay)) &key) + (declare (ignorable option)) + (let ((socket (socket usocket))) + (declare (ignorable socket)) + #+abcl + () ; TODO + #+allegro + () ; TODO + #+clisp + (int->bool (socket:socket-options socket :tcp-nodelay)) + #+clozure + (int->bool (get-socket-option-tcp-nodelay socket)) + #+cmu + () + #+(or ecl clasp) + (sb-bsd-sockets::sockopt-tcp-nodelay socket) + #+lispworks + (int->bool (get-socket-tcp-nodelay socket)) + #+mcl + () ; TODO + #+mocl + () ; unknown + #+sbcl + (sb-bsd-sockets::sockopt-tcp-nodelay socket) + #+scl + ())) ; TODO + +(defmethod (setf socket-option) (new-value (usocket stream-usocket) + (option (eql :tcp-no-delay)) &key) + (declare (ignorable option)) + (setf (socket-option usocket :tcp-nodelay) new-value)) + +(defmethod (setf socket-option) (new-value (usocket stream-usocket) + (option (eql :tcp-nodelay)) &key) + (declare (type boolean new-value) + (ignorable new-value option)) + (let ((socket (socket usocket))) + (declare (ignorable socket)) + #+abcl + () ; TODO + #+allegro + (socket:set-socket-options socket :no-delay new-value) + #+clisp + (socket:socket-options socket :tcp-nodelay (bool->int new-value)) + #+clozure + (set-socket-option-tcp-nodelay socket (bool->int new-value)) + #+cmu + () + #+(or ecl clasp) + (setf (sb-bsd-sockets::sockopt-tcp-nodelay socket) new-value) + #+lispworks + (progn + #-(or lispworks4 lispworks5.0) + (comm::set-socket-tcp-nodelay socket new-value) + #+(or lispworks4 lispworks5.0) + (set-socket-tcp-nodelay socket (bool->int new-value))) + #+mcl + () ; TODO + #+mocl + () ; unknown + #+sbcl + (setf (sb-bsd-sockets::sockopt-tcp-nodelay socket) new-value) + #+scl + () ; TODO + new-value)) + +(eval-when (:load-toplevel :execute) + (export 'socket-option)) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/package.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/package.lisp new file mode 100644 index 0000000..4db895c --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/package.lisp @@ -0,0 +1,126 @@ +;;;; -*- Mode: LISP; Base: 10; Syntax: ANSI-Common-lisp; Package: CL-USER -*- +;;;; See the LICENSE file for licensing information. + +(defpackage :usocket + (:use #-genera :common-lisp + #+genera :future-common-lisp + #+abcl :java + :split-sequence) + (:export #:*version* + #:*wildcard-host* + #:*auto-port* + + #:+max-datagram-packet-size+ + + #:socket-connect ; socket constructors and methods + #:socket-listen + #:socket-accept + #:socket-close + #:socket-shutdown + #:get-local-address + #:get-peer-address + #:get-local-port + #:get-peer-port + #:get-local-name + #:get-peer-name + + #:socket-send ; udp function (send) + #:socket-receive ; udp function (receive) + + #:wait-for-input ; waiting for input-ready state (select() like) + #:make-wait-list + #:add-waiter + #:remove-waiter + #:remove-all-waiters + + #:with-connected-socket ; convenience macros + #:with-server-socket + #:with-client-socket + #:with-socket-listener + + #:usocket ; socket object and accessors + #:stream-usocket + #:stream-server-usocket + #:socket + #:socket-stream + #:datagram-usocket + #:socket-state ; 0.6.4 + + ;; predicates (for version 0.6 or 1.0 ?) + #:usocket-p + #:stream-usocket-p + #:stream-server-usocket-p + #:datagram-usocket-p + + #:host-byte-order ; IPv4 utility functions + #:hbo-to-dotted-quad + #:hbo-to-vector-quad + #:vector-quad-to-dotted-quad + #:dotted-quad-to-vector-quad + + #:vector-to-ipv6-host ; IPv6 utility functions + #:ipv6-host-to-vector + + #:ip= ; IPv4+IPv6 utility function + #:ip/= + + #:integer-to-octet-buffer ; Network utility functions + #:octet-buffer-to-integer + #:port-to-octet-buffer + #:port-from-octet-buffer + #:ip-to-octet-buffer + #:ip-from-octet-buffer + + #:with-mapped-conditions + + #:socket-condition ; conditions + #:ns-condition + #:socket-error ; errors + #:ns-error + #:unknown-condition + #:ns-unknown-condition + #:unknown-error + #:ns-unknown-error + #:socket-warning ; warnings (udp) + + #:insufficient-implementation ; conditions regarding usocket support level + #:unsupported + #:unimplemented + + #:socket-server + #:*remote-host* + #:*remote-port* + + ;; added in 0.7.1 + #:get-host-by-name + #:get-hosts-by-name + #:get-random-host-by-name + #:ns-host-not-found-error + #:ns-no-recovery-error + #:ns-try-again-condition + #:default-udp-handler + #:default-tcp-handler + #:echo-tcp-handler ;; server handlers + + ;; added in 0.8.0 + #:*backend* + #:*default-event-base* + #:host-to-hostname + + ;; these're socket-related conditions from IOlib + #:ADDRESS-NOT-AVAILABLE-ERROR #:HOST-DOWN-ERROR + #:OPERATION-NOT-SUPPORTED-ERROR #:SOCKET-OPTION + #:NETWORK-DOWN-ERROR #:INVALID-SOCKET-ERROR + #:SOCKET-TYPE-NOT-SUPPORTED-ERROR #:DEADLINE-TIMEOUT-ERROR + #:SHUTDOWN-ERROR #:HOST-UNREACHABLE-ERROR + #:NETWORK-UNREACHABLE-ERROR #:CONNECTION-ABORTED-ERROR + #:BAD-FILE-DESCRIPTOR-ERROR #:PROTOCOL-NOT-SUPPORTED-ERROR + #:CONNECTION-RESET-ERROR #:TIMEOUT-ERROR + #:ADDRESS-IN-USE-ERROR #:NO-BUFFERS-ERROR + #:INVALID-SOCKET-STREAM-ERROR #:INTERRUPTED-CONDITION + #:INVALID-ARGUMENT-ERROR #:OPERATION-NOT-PERMITTED-ERROR + #:NETWORK-RESET-ERROR #:CONNECTION-REFUSED-ERROR + + ;; added in 0.8.2 + #:host-or-ip + )) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/server.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/server.lisp new file mode 100644 index 0000000..9bd2076 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/server.lisp @@ -0,0 +1,112 @@ +;;;; See LICENSE for licensing information. + +(in-package :usocket) + +(defvar *server*) + +(defun socket-server (host port function &optional arguments + &key in-new-thread (protocol :stream) + ;; for udp + (timeout 1) (max-buffer-size +max-datagram-packet-size+) + ;; for tcp + element-type (reuse-address t) multi-threading + name) + (let* ((real-host (or host *wildcard-host*)) + (socket (ecase protocol + (:stream + (apply #'socket-listen + `(,real-host ,port + ,@(when element-type `(:element-type ,element-type)) + ,@(when reuse-address `(:reuse-address ,reuse-address))))) + (:datagram + (socket-connect nil nil :protocol :datagram + :local-host real-host + :local-port port))))) + (labels ((real-call () + (ecase protocol + (:stream + (tcp-event-loop socket function arguments + :element-type element-type + :multi-threading multi-threading)) + (:datagram + (udp-event-loop socket function arguments + :timeout timeout + :max-buffer-size max-buffer-size))))) + (if in-new-thread + (values (bt:make-thread #'real-call :name (or name "USOCKET Server")) socket) + (progn + (setq *server* socket) + (real-call)))))) + +(defvar *remote-host*) +(defvar *remote-port*) + +(defun default-udp-handler (buffer) ; echo + (declare (type (simple-array (unsigned-byte 8) *) buffer)) + buffer) + +(defun udp-event-loop (socket function &optional arguments + &key timeout max-buffer-size) + (let ((buffer (make-array max-buffer-size :element-type '(unsigned-byte 8) :initial-element 0)) + (sockets (list socket))) + (unwind-protect + (loop do + (multiple-value-bind (return-sockets real-time) + (wait-for-input sockets :timeout timeout) + (declare (ignore return-sockets)) + (when real-time + (multiple-value-bind (recv n *remote-host* *remote-port*) + (socket-receive socket buffer max-buffer-size) + (declare (ignore recv)) + (if (plusp n) + (progn + (let ((reply + (apply function (subseq buffer 0 n) arguments))) + (when reply + (replace buffer reply) + (let ((n (socket-send socket buffer (length reply) + :host *remote-host* + :port *remote-port*))) + (when (minusp n) + (error "send error: ~A~%" n)))))) + (error "receive error: ~A" n)))) + #+scl (when thread:*quitting-lisp* (return)) + #+(and cmu mp) (mp:process-yield))) + (socket-close socket) + (values)))) + +(defun default-tcp-handler (stream) ; null + (declare (type stream stream)) + (format stream "Hello world!~%")) + +(defun echo-tcp-handler (stream) + (loop + (when (listen stream) + (let ((line (read-line stream nil))) + (write-line line stream) + (force-output stream))))) + +(defun tcp-event-loop (socket function &optional arguments + &key element-type multi-threading) + (let ((real-function #'(lambda (client-socket &rest arguments) + (unwind-protect + (multiple-value-bind (*remote-host* *remote-port*) (get-peer-name client-socket) + (apply function (socket-stream client-socket) arguments)) + (close (socket-stream client-socket)) + (socket-close client-socket) + nil)))) + (unwind-protect + (loop do + (let* ((client-socket (apply #'socket-accept + `(,socket ,@(when element-type `(:element-type ,element-type))))) + (client-stream (socket-stream client-socket))) + (if multi-threading + (bt:make-thread (lambda () (apply real-function client-socket arguments)) + :name "USOCKET Client") + (prog1 (apply real-function client-socket arguments) + (close client-stream) + (socket-close client-socket))) + #+scl (when thread:*quitting-lisp* (return)) + #+(and cmu mp) (mp:process-yield))) + (socket-close socket) + (values)))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/test/package.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/test/package.lisp new file mode 100644 index 0000000..bef2a37 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/test/package.lisp @@ -0,0 +1,11 @@ +;;;; -*- Mode: LISP; Base: 10; Syntax: ANSI-Common-lisp; Package: CL-USER -*- +;;;; See the LICENSE file for licensing information. + +(in-package :cl-user) + +(defpackage :usocket-test + (:use :common-lisp + :usocket + :regression-test) + (:export #:do-tests + #:run-usocket-tests)) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/test/test-condition.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/test/test-condition.lisp new file mode 100644 index 0000000..c82ca70 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/test/test-condition.lisp @@ -0,0 +1,28 @@ +;;;; -*- Mode: LISP; Base: 10; Syntax: ANSI-Common-lisp; Package: USOCKET-TEST -*- +;;;; See LICENSE for licensing information. + +(in-package :usocket-test) + +(deftest ns-host-not-found-error.1 + (with-caught-conditions (usocket:ns-host-not-found-error nil) + (usocket:socket-connect "xxx" 123) + t) + nil) + +(deftest timeout-error.1 + (with-caught-conditions (usocket:timeout-error nil) + (usocket:socket-connect "common-lisp.net" 81 :timeout 0) + t) + nil) + +(deftest connection-refused-error.1 + (with-caught-conditions (usocket:connection-refused-error nil) + (usocket:socket-connect "common-lisp.net" 81) + t) + nil) + +(deftest operation-not-permitted-error.1 + (with-caught-conditions (usocket:operation-not-permitted-error nil) + (usocket:socket-listen "0.0.0.0" 81) + t) + nil) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/test/test-datagram.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/test/test-datagram.lisp new file mode 100644 index 0000000..4fb6330 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/test/test-datagram.lisp @@ -0,0 +1,124 @@ +;;;; -*- Mode: LISP; Base: 10; Syntax: ANSI-Common-lisp; Package: USOCKET-TEST -*- +;;;; See LICENSE for licensing information. + +(in-package :usocket-test) + +(defvar *echo-server*) +(defvar *echo-server-port*) + +(defun start-server () + (multiple-value-bind (thread socket) + (socket-server "127.0.0.1" 0 #'identity nil + :in-new-thread t + :protocol :datagram) + (setq *echo-server* thread + *echo-server-port* (get-local-port socket)))) + +(defparameter *max-buffer-size* 32) + +(defvar *send-buffer* + (make-array *max-buffer-size* :element-type '(unsigned-byte 8) :initial-element 0)) + +(defvar *receive-buffer* + (make-array *max-buffer-size* :element-type '(unsigned-byte 8) :initial-element 0)) + +(defun clean-buffers () + (fill *send-buffer* 0) + (fill *receive-buffer* 0)) + +;;; UDP Send Test #1: connected socket +(deftest udp-send.1 + (progn + (unless (and *echo-server* *echo-server-port*) + (start-server)) + (let ((s (socket-connect "127.0.0.1" *echo-server-port* :protocol :datagram))) + (clean-buffers) + (replace *send-buffer* #(1 2 3 4 5)) + (socket-send s *send-buffer* 5) + (wait-for-input s :timeout 3) + (multiple-value-bind (buffer size host port) + (socket-receive s *receive-buffer* *max-buffer-size*) + (declare (ignore buffer size host port)) + (reduce #'+ *receive-buffer* :start 0 :end 5)))) + 15) + +;;; UDP Send Test #2: unconnected socket +(deftest udp-send.2 + (progn + (unless (and *echo-server* *echo-server-port*) + (start-server)) + (let ((s (socket-connect nil nil :protocol :datagram))) + (clean-buffers) + (replace *send-buffer* #(1 2 3 4 5)) + (socket-send s *send-buffer* 5 :host "127.0.0.1" :port *echo-server-port*) + (wait-for-input s :timeout 3) + (multiple-value-bind (buffer size host port) + (socket-receive s *receive-buffer* *max-buffer-size*) + (declare (ignore buffer size host port)) + (reduce #'+ *receive-buffer* :start 0 :end 5)))) + 15) + +(deftest mark-h-david ; Mark H. David's remarkable UDP test code + (let* ((host "localhost") + (port 1111) + (server-sock + (socket-connect nil nil :protocol ':datagram :local-host host :local-port port)) + (client-sock + (socket-connect host port :protocol ':datagram)) + (octet-vector + (make-array 2 :element-type '(unsigned-byte 8) :initial-contents `(,(char-code #\O) ,(char-code #\K)))) + (recv-octet-vector + (make-array 2 :element-type '(unsigned-byte 8)))) + (socket-send client-sock octet-vector 2) + (socket-receive server-sock recv-octet-vector 2) + (prog1 (and (equalp octet-vector recv-octet-vector) + recv-octet-vector) + (socket-close server-sock) + (socket-close client-sock))) + #(79 75)) + +(deftest frank-james ; Frank James' test code for LispWorks/UDP + (with-caught-conditions (#+win32 CONNECTION-RESET-ERROR + #-win32 CONNECTION-REFUSED-ERROR + nil) + (let ((sock (socket-connect "localhost" 1234 + :protocol ':datagram :element-type '(unsigned-byte 8)))) + (unwind-protect + (progn + (socket-send sock (make-array 16 :element-type '(unsigned-byte 8) :initial-element 0) 16) + (let ((buffer (make-array 16 :element-type '(unsigned-byte 8) :initial-element 0))) + (socket-receive sock buffer 16))) + (socket-close sock)))) + nil) + +(defun frank-wfi-test () + (let ((s (socket-connect nil nil :protocol :datagram + :element-type '(unsigned-byte 8) + :local-port 8001))) + (unwind-protect + (do ((i 0 (1+ i)) + (buffer (make-array 1024 :element-type '(unsigned-byte 8) + :initial-element 0)) + (now (get-universal-time)) + (done nil)) + ((or done (= i 4)) + nil) + (format t "~Ds ~D Waiting state ~S~%" (- (get-universal-time) now) i (usocket::state s)) + (when (wait-for-input s :ready-only t :timeout 5) + (format t "~D state ~S~%" i (usocket::state s)) + (handler-bind + ((error (lambda (c) + (format t "socket-receive error: ~A~%" c) + (break) + nil))) + (multiple-value-bind (buffer count remote-host remote-port) + (socket-receive s buffer 1024) + (handler-bind + ((error (lambda (c) + (format t "socket-send error: ~A~%" c) + (break)))) + (when buffer + (socket-send s (subseq buffer 0 count) count + :host remote-host + :port remote-port))))))) + (socket-close s)))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/test/test-usocket.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/test/test-usocket.lisp new file mode 100644 index 0000000..ff03f7f --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/test/test-usocket.lisp @@ -0,0 +1,179 @@ +;;;; -*- Mode: LISP; Base: 10; Syntax: ANSI-Common-lisp; Package: USOCKET-TEST -*- +;;;; See LICENSE for licensing information. + +;;;; Usage: (usoct:run-usocket-tests) or (usoct:do-tests) + +(in-package :usocket-test) + +(defparameter +non-existing-host+ "1.2.3.4") +(defparameter +unused-local-port+ 15213) + +(defparameter *fake-usocket* + (usocket::make-stream-socket :socket :my-socket + :stream :my-stream)) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defvar *common-lisp-net* + (get-host-by-name "common-lisp.net"))) + +(defvar *local-ip*) + +(defmacro with-caught-conditions ((expect throw) &body body) + `(catch 'caught-error + (handler-case + (handler-bind ((unsupported + #'(lambda (c) + (declare (ignore c)) (continue)))) + (progn ,@body)) + (unknown-error (c) (if (typep c ',expect) + (throw 'caught-error ,throw) + (progn + (describe c) + (describe + (usocket::usocket-real-error c)) + c))) + (error (c) (if (typep c ',expect) + (throw 'caught-error ,throw) + (progn + (describe c) + c))) + (unknown-condition (c) (if (typep c ',expect) + (throw 'caught-error ,throw) + (progn + (describe c) + (describe + (usocket::usocket-real-condition c)) + c))) + (condition (c) (if (typep c ',expect) + (throw 'caught-error ,throw) + (progn + (describe c) + c)))))) + +(deftest make-socket.1 (socket *fake-usocket*) :my-socket) +(deftest make-socket.2 (socket-stream *fake-usocket*) :my-stream) + +(deftest socket-no-connect.1 + (with-caught-conditions (socket-error nil) + (socket-connect "127.0.0.1" +unused-local-port+ :timeout 1) + t) + nil) + +(deftest socket-no-connect.2 + (with-caught-conditions (socket-error nil) + (socket-connect #(127 0 0 1) +unused-local-port+ :timeout 1) + t) + nil) + +(deftest socket-no-connect.3 + (with-caught-conditions (socket-error nil) + (socket-connect 2130706433 +unused-local-port+ :timeout 1) ;; == #(127 0 0 1) + t) + nil) + +(deftest socket-failure.1 + (with-caught-conditions (timeout-error nil) + (socket-connect 2130706433 +unused-local-port+ :timeout 1) ;; == #(127 0 0 1) + :unreach) + nil) + +(deftest socket-failure.2 + (with-caught-conditions (timeout-error nil) + (socket-connect +non-existing-host+ 80 :timeout 1) ;; 80 = just a port + :unreach) + nil) + +;; let's hope c-l.net doesn't move soon, or that people start to +;; test usocket like crazy.. +(deftest socket-connect.1 + (with-caught-conditions (nil nil) + (let ((sock (socket-connect "common-lisp.net" 80))) + (unwind-protect + (when (typep sock 'usocket) t) + (socket-close sock)))) + t) + +(deftest socket-connect.2 + (with-caught-conditions (nil nil) + (let ((sock (socket-connect *common-lisp-net* 80))) + (unwind-protect + (when (typep sock 'usocket) t) + (socket-close sock)))) + t) + +(deftest socket-connect.3 + (with-caught-conditions (nil nil) + (let ((sock (socket-connect (usocket::host-byte-order *common-lisp-net*) 80))) + (unwind-protect + (when (typep sock 'usocket) t) + (socket-close sock)))) + t) + +;; let's hope c-l.net doesn't change its software any time soon +(deftest socket-stream.1 + (with-caught-conditions (nil nil) + (let ((sock (socket-connect "common-lisp.net" 80))) + (unwind-protect + (progn + (format (socket-stream sock) + "GET / HTTP/1.0~2%") + (force-output (socket-stream sock)) + (subseq (read-line (socket-stream sock)) 0 4)) + (socket-close sock)))) + "HTTP") + +(deftest socket-name.1 + (with-caught-conditions (nil nil) + (let ((sock (socket-connect *common-lisp-net* 80))) + (unwind-protect + (get-peer-address sock) + (socket-close sock)))) + #.*common-lisp-net*) + +(deftest socket-name.2 + (with-caught-conditions (nil nil) + (let ((sock (socket-connect *common-lisp-net* 80))) + (unwind-protect + (get-peer-port sock) + (socket-close sock)))) + 80) + +(deftest socket-name.3 + (with-caught-conditions (nil nil) + (let ((sock (socket-connect *common-lisp-net* 80))) + (unwind-protect + (get-peer-name sock) + (socket-close sock)))) + #.*common-lisp-net* 80) + +#+ignore +(deftest socket-name.4 + (with-caught-conditions (nil nil) + (let ((sock (socket-connect *common-lisp-net* 80))) + (unwind-protect + (equal (get-local-address sock) *local-ip*) + (socket-close sock)))) + t) + +(deftest socket-shutdown.1 + (with-caught-conditions (nil nil) + (let ((sock (socket-connect *common-lisp-net* 80))) + (unwind-protect + (usocket::ignore-unsupported-warnings + (socket-shutdown sock :input)) + (socket-close sock)) + t)) + t) + +(deftest socket-shutdown.2 + (with-caught-conditions (nil nil) + (let ((sock (socket-connect *common-lisp-net* 80))) + (unwind-protect + (usocket::ignore-unsupported-warnings + (socket-shutdown sock :output)) + (socket-close sock)) + t)) + t) + +(defun run-usocket-tests () + (do-tests)) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/test/udp-one-shot.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/test/udp-one-shot.lisp new file mode 100644 index 0000000..db09687 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/test/udp-one-shot.lisp @@ -0,0 +1,86 @@ +;;;; -*- Mode: LISP; Base: 10; Syntax: ANSI-Common-lisp; Package: USOCKET-TEST -*- + +(in-package :usocket-test) + +;; Test code from "INVALID-ARGUMENT-ERROR on socket-receive (#48)" + +;; Author: @4lph4-Ph4un +;; Environment: SBCL 1.4.16, WSL on Windows 10 + +(defun UDP-one-shot-V1 (&optional (port 1232)) + (let ((socket (usocket:socket-connect + nil + nil + :protocol :datagram + :element-type '(unsigned-byte 8) + :local-host "127.0.0.1" + :local-port port)) + (buffer (make-array 8 :element-type '(unsigned-byte 8)))) + (unwind-protect + (multiple-value-bind (received size remote-host remote-port) + ;; NOTE: An explicit buffer can be given. If the length + ;; is nil buffer's length will be used. + (usocket:socket-receive socket buffer 8) + (format t "~A~%" received) + (usocket:socket-send socket + (reverse received) + size + :host remote-host + :port remote-port)) + (usocket:socket-close socket)))) + +#| +Backtrace: + 0: (USOCKET::HANDLE-CONDITION # #) + Locals: + CONDITION = # + SOCKET = # + 1: (SB-KERNEL::%SIGNAL #) + Locals: + CONDITION = # + HANDLER-CLUSTERS = (((# . #)) ((# . #)) ..) + 2: (ERROR SB-BSD-SOCKETS:INVALID-ARGUMENT-ERROR :ERRNO 22 :SYSCALL "recvfrom") + Locals: + CONDITION = # + #:G8039 = SB-BSD-SOCKETS:INVALID-ARGUMENT-ERROR + SB-DEBUG::MORE = (:ERRNO 22 :SYSCALL "recvfrom") + 3: (SB-BSD-SOCKETS:SOCKET-ERROR "recvfrom" 22) + Locals: + ERRNO = 22 + WHERE = "recvfrom" + 4: ((FLET SB-BSD-SOCKETS::WITH-SOCKET-ADDR-THUNK :IN SB-BSD-SOCKETS:SOCKET-RECEIVE) # + SB-BSD-SOCKETS::SIZE = 16 + SB-BSD-SOCKETS::SOCKADDR = # + 5: (SB-BSD-SOCKETS::CALL-WITH-SOCKET-ADDR # NIL # + SOCKADDR-ARGS = NIL + SOCKET = # + THUNK = # + 6: ((:METHOD SB-BSD-SOCKETS:SOCKET-RECEIVE (SB-BSD-SOCKETS:SOCKET T T)) # #(0 0 0 0 0 0 ...) 8 :OOB NIL :PEEK NIL :WAITALL NIL :DONTWAIT NIL.. + Locals: + #:.DEFAULTING-TEMP. = (UNSIGNED-BYTE 8) + SB-BSD-SOCKETS::BUFFER = #(0 0 0 0 0 0 ...) + SB-BSD-SOCKETS::BUFFER#1 = #(0 0 0 0 0 0 ...) + SB-BSD-SOCKETS::DONTWAIT = NIL + SB-BSD-SOCKETS::ELEMENT-TYPE = (UNSIGNED-BYTE 8) + LENGTH = 8 + LENGTH#1 = 8 + SB-BSD-SOCKETS::OOB = NIL + SB-BSD-SOCKETS::PEEK = NIL + SB-BSD-SOCKETS:SOCKET = # + SB-BSD-SOCKETS::WAITALL = NIL + 7: ((:METHOD USOCKET:SOCKET-RECEIVE (USOCKET:DATAGRAM-USOCKET T T)) # #(0 0 0 0 0 0 ...) 8 :ELEMENT-TYPE (UNSIGNED-BYTE 8)) [fast-method] + Locals: + USOCKET::BUFFER = #(0 0 0 0 0 0 ...) + USOCKET::ELEMENT-TYPE = (UNSIGNED-BYTE 8) + LENGTH = 8 + USOCKET:SOCKET = # + 8: (MASTER-CLASS/SRC/SERVER-03:UDP-ONE-SHOT-V1 1232) + Locals: + PORT = 1232 + SOCKET = # +|# + diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/test/wait-for-input.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/test/wait-for-input.lisp new file mode 100644 index 0000000..dadd4ca --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/test/wait-for-input.lisp @@ -0,0 +1,140 @@ +;;;; -*- Mode: LISP; Base: 10; Syntax: ANSI-Common-lisp; Package: USOCKET-TEST -*- +;;;; See LICENSE for licensing information. + +(in-package :usocket-test) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defparameter *wait-for-input-timeout* 2)) + +(deftest wait-for-input.1 + (with-caught-conditions (nil nil) + (let ((sock (usocket:socket-connect *common-lisp-net* 80)) + (time (get-universal-time))) + (unwind-protect + (progn (usocket:wait-for-input sock :timeout *wait-for-input-timeout*) + (- (get-universal-time) time)) + (usocket:socket-close sock)))) + #.*wait-for-input-timeout*) + +(deftest wait-for-input.2 + (with-caught-conditions (nil nil) + (let ((sock (usocket:socket-connect *common-lisp-net* 80)) + (time (get-universal-time))) + (unwind-protect + (progn (usocket:wait-for-input sock :timeout *wait-for-input-timeout* :ready-only t) + (- (get-universal-time) time)) + (usocket:socket-close sock)))) + #.*wait-for-input-timeout*) + +(deftest wait-for-input.3 + (with-caught-conditions (nil nil) + (let ((sock (usocket:socket-connect *common-lisp-net* 80))) + (unwind-protect + (progn + (format (usocket:socket-stream sock) + "GET / HTTP/1.0~2%") + (force-output (usocket:socket-stream sock)) + (usocket:wait-for-input sock :timeout *wait-for-input-timeout*) + (subseq (read-line (usocket:socket-stream sock)) 0 4)) + (usocket:socket-close sock)))) + "HTTP") + +;;; Advanced W-F-I tests by Elliott Slaughter + +(defvar *socket-server-port* 0) +(defvar *socket-server-listen* nil) +(defvar *socket-server-connection*) +(defvar *socket-client-connection*) +(defvar *output-p* t) + +(defun stage-1 () + (unless *socket-server-listen* + (setf *socket-server-listen* + (socket-listen *wildcard-host* 0 :element-type '(unsigned-byte 8))) + (setf *socket-server-port* (get-local-port *socket-server-listen*))) + + (setf *socket-server-connection* + (when (wait-for-input *socket-server-listen* :timeout 0 :ready-only t) + (socket-accept *socket-server-listen*))) + + (when *output-p* ; should be NIL + (format t "First time (before client connects) is ~s.~%" + *socket-server-connection*)) + + *socket-server-connection*) + +;; TODO: original test code have addition (:TIMEOUT 0) when doing the SOCKET-CONNECT, +;; it seems cannot work on SBCL/Windows, need to investigate, but here we ignore it. + +(defun stage-2 () + (setf *socket-client-connection* + (socket-connect "localhost" *socket-server-port* :protocol :stream + :element-type '(unsigned-byte 8))) + (setf *socket-server-connection* + (when (wait-for-input *socket-server-listen* :timeout 0 :ready-only t) + #+(and win32 (or lispworks ecl sbcl)) + (when *output-p* + (format t "%READY-P: ~D~%" (usocket::%ready-p *socket-server-listen*))) + (socket-accept *socket-server-listen*))) + + (when *output-p* ; should be a usocket object + (format t "Second time (after client connects) is ~s.~%" + *socket-server-connection*)) + + *socket-server-connection*) + +(defun stage-3 () + (setf *socket-server-connection* + (when (wait-for-input *socket-server-listen* :timeout 0 :ready-only t) + #+(and win32 (or lispworks ecl sbcl)) + (when *output-p* + (format t "%READY-P: ~D~%" (usocket::%ready-p *socket-server-listen*))) + (socket-accept *socket-server-listen*))) + + (when *output-p* ; should be NIL again + (format t "Third time (before second client) is ~s.~%" + *socket-server-connection*)) + + *socket-server-connection*) + +(deftest elliott-slaughter.1 + (let ((*output-p* nil)) + (let* ((s-1 (stage-1)) (s-2 (stage-2)) (s-3 (stage-3))) + (prog1 (and (null s-1) (usocket::usocket-p s-2) (null s-3)) + (socket-close *socket-server-listen*) + (setf *socket-server-listen* nil)))) + t) + +#| + +Issue elliott-slaughter.2 (WAIT-FOR-INPUT/win32 on TCP socket) + +W-F-I correctly found the inputs, but :READY-ONLY didn't work. + +|# +(defun receive-each (connections) + (let ((ready (usocket:wait-for-input connections :timeout 0 :ready-only t))) + (loop for connection in ready + collect (read-line (usocket:socket-stream connection))))) + +(defun receive-all (connections) + (loop for messages = (receive-each connections) + then (receive-each connections) + while messages append messages)) + +(defun send (connection message) + (format (usocket:socket-stream connection) "~a~%" message) + (force-output (usocket:socket-stream connection))) + +(defun server () + (let* ((listen (usocket:socket-listen usocket:*wildcard-host* 12345)) + (connection (usocket:socket-accept listen))) + (loop for messages = (receive-all connection) then (receive-all connection) + do (format t "Got messages:~%~s~%" messages) + do (sleep 1/50)))) + +(defun client () + (let ((connection (usocket:socket-connect "localhost" 12345))) + (loop for i from 0 + do (send connection (format nil "This is message ~a." i)) + do (sleep 1/100)))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/usocket-server.asd b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/usocket-server.asd new file mode 100644 index 0000000..61d1c9d --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/usocket-server.asd @@ -0,0 +1,14 @@ +;;;; -*- Mode: Lisp -*- +;;;; +;;;; See the LICENSE file for licensing information. + +(in-package :asdf) + +(defsystem usocket-server + :name "usocket (server)" + :author "Chun Tian (binghe)" + :version (:read-file-form "version.sexp") + :licence "MIT" + :description "Universal socket library for Common Lisp (server side)" + :depends-on (:usocket :bordeaux-threads) + :components ((:file "server"))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/usocket-test.asd b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/usocket-test.asd new file mode 100644 index 0000000..58f5626 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/usocket-test.asd @@ -0,0 +1,23 @@ +;;;; -*- Mode: Lisp -*- + +;;;; See the LICENSE file for licensing information. + +(defsystem usocket-test + :name "usocket test" + :author "Erik Enge" + :maintainer "Chun Tian (binghe)" + :version (:read-file-form "version.sexp") + :licence "MIT" + :description "Tests for usocket" + :depends-on (:usocket-server + :rt) + :components ((:module "test" + :serial t + :components ((:file "package") + (:file "test-usocket") + (:file "test-condition") + (:file "test-datagram") + (:file "wait-for-input"))))) + +(defmethod perform ((op test-op) (c (eql (find-system :usocket-test)))) + (funcall (intern "DO-TESTS" "USOCKET-TEST"))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/usocket.asd b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/usocket.asd new file mode 100644 index 0000000..a4c184b --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/usocket.asd @@ -0,0 +1,58 @@ +;;;; -*- Mode: LISP; Base: 10; Syntax: ANSI-Common-lisp; -*- +;;;; +;;;; See the LICENSE file for licensing information. + +(in-package :asdf) + +;;; NOTE: the key "art" here is, no need to recompile any file when switching +;;; between a native backend and IOlib backend. -- Chun Tian (binghe) + +#+sample +(pushnew :usocket-iolib *features*) + +(defsystem usocket + :name "usocket (client, with server symbols)" + :author "Erik Enge & Erik Huelsmann" + :maintainer "Chun Tian (binghe) & Hans Huebner" + :version (:read-file-form "version.sexp") + :licence "MIT" + :description "Universal socket library for Common Lisp" + :depends-on (:split-sequence + #+(and (or sbcl ecl) + (not usocket-iolib)) :sb-bsd-sockets + #+usocket-iolib :iolib) + :components ((:file "package") + (:module "vendor" :depends-on ("package") + :components (#+mcl (:file "kqueue") + #+mcl (:file "OpenTransportUDP"))) + (:file "usocket" :depends-on ("vendor")) + (:file "condition" :depends-on ("usocket")) + #-usocket-iolib + (:module "backend" :depends-on ("condition") + :components (#+abcl (:file "abcl") + #+(or allegro cormanlisp) + (:file "allegro") + #+clisp (:file "clisp") + #+(or openmcl clozure) + (:file "openmcl") + #+clozure (:file "clozure" :depends-on ("openmcl")) + #+cmu (:file "cmucl") + #+(or sbcl ecl clasp) + (:file "sbcl") + #+ecl (:file "ecl" :depends-on ("sbcl")) + #+clasp (:file "clasp" :depends-on ("sbcl")) + #+lispworks (:file "lispworks") + #+mcl (:file "mcl") + #+mocl (:file "mocl") + #+scl (:file "scl") + #+genera (:file "genera") + #+mezzano (:file "mezzano"))) + #-usocket-iolib + (:file "option" :depends-on ("backend")) + #+usocket-iolib + (:module "backend" :depends-on ("condition") + :components ((:file "iolib"))))) + +(defmethod perform ((op test-op) (c (eql (find-system :usocket)))) + (oos 'load-op ':usocket-test) + (oos 'test-op ':usocket-test)) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/usocket.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/usocket.lisp new file mode 100644 index 0000000..20025e0 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/usocket.lisp @@ -0,0 +1,727 @@ +;;;; -*- Mode: LISP; Base: 10; Syntax: ANSI-Common-lisp; Package: USOCKET -*- +;;;; See LICENSE for licensing information. + +(in-package :usocket) + +(defparameter *wildcard-host* #(0 0 0 0) + "Hostname to pass when all interfaces in the current system are to + be bound. If this variable is passed to socket-listen, IPv6 capable + systems will also listen for IPv6 connections.") + +(defparameter *auto-port* 0 + "Port number to pass when an auto-assigned port number is wanted.") + +(defparameter *version* #.(asdf:component-version (asdf:find-system :usocket)) + "usocket version string") + +(defconstant +max-datagram-packet-size+ 65507 + "The theoretical maximum amount of data in a UDP datagram. + +The IPv4 UDP packets have a 16-bit length constraint, and IP+UDP header has 28-byte. + +IP_MAXPACKET = 65535, /* netinet/ip.h */ +sizeof(struct ip) = 20, /* netinet/ip.h */ +sizeof(struct udphdr) = 8, /* netinet/udp.h */ + +65535 - 20 - 8 = 65507 + +(But for UDP broadcast, the maximum message size is limited by the MTU size of the underlying link)") + +(defclass usocket () + ((socket + :initarg :socket + :accessor socket + :documentation "Implementation specific socket object instance.'") + (wait-list + :initform nil + :accessor wait-list + :documentation "WAIT-LIST the object is associated with.") + (state + :initform nil + :accessor state + :documentation "Per-socket return value for the `wait-for-input' function. + +The value stored in this slot can be any of + NIL - not ready + :READ - ready to read + :READ-WRITE - ready to read and write + :WRITE - ready to write + +The last two remain unused in the current version. +") + #+(and win32 (or sbcl ecl lispworks)) + (%ready-p + :initform nil + :accessor %ready-p + :documentation "Indicates whether the socket has been signalled +as ready for reading a new connection. + +The value will be set to T by `wait-for-input-internal' (given the +right conditions) and reset to NIL by `socket-accept'. + +Don't modify this slot or depend on it as it is really intended +to be internal only. + +Note: Accessed, but not used for 'stream-usocket'. +" + )) + (:documentation +"The main socket class. + +Sockets should be closed using the `socket-close' method.")) + +(defgeneric socket-state (socket) + (:documentation "NIL - not ready +:READ - ready to read +:READ-WRITE - ready to read and write +:WRITE - ready to write")) + +(defmethod socket-state ((socket usocket)) + (state socket)) + +(defclass stream-usocket (usocket) + ((stream + :initarg :stream + :accessor socket-stream + :documentation "Stream instance associated with the socket." +;; +;;Iff an external-format was passed to `socket-connect' or `socket-listen' +;;the stream is a flexi-stream. Otherwise the stream is implementation +;;specific." +)) + (:documentation +"Stream socket class. +' +Contrary to other sockets, these sockets may be closed either +with the `socket-close' method or by closing the associated stream +(which can be retrieved with the `socket-stream' accessor).")) + +(defclass stream-server-usocket (usocket) + ((element-type + :initarg :element-type + :initform #-lispworks 'character + #+lispworks 'base-char + :reader element-type + :documentation "Default element type for streams created by +`socket-accept'.")) + (:documentation "Socket which listens for stream connections to +be initiated from remote sockets.")) + +(defclass datagram-usocket (usocket) + ((connected-p :type boolean + :accessor connected-p + :initarg :connected-p) + #+(or cmu scl lispworks mcl + (and clisp ffi (not rawsock))) + (%open-p :type boolean + :accessor %open-p + :initform t + :documentation "Flag to indicate if usocket is open, +for GC on implementions operate on raw socket fd.") + #+(or lispworks mcl + (and clisp ffi (not rawsock))) + (recv-buffer :documentation "Private RECV buffer.") + #+(or lispworks mcl) + (send-buffer :documentation "Private SEND buffer.")) + (:documentation "UDP (inet-datagram) socket")) + +(defun usocket-p (socket) + (typep socket 'usocket)) + +(defun stream-usocket-p (socket) + (typep socket 'stream-usocket)) + +(defun stream-server-usocket-p (socket) + (typep socket 'stream-server-usocket)) + +(defun datagram-usocket-p (socket) + (typep socket 'datagram-usocket)) + +(defun make-socket (&key socket) + "Create a usocket socket type from implementation specific socket." + (unless socket + (error 'invalid-socket-error)) + (make-stream-socket :socket socket)) + +(defun make-stream-socket (&key socket stream) + "Create a usocket socket type from implementation specific socket +and stream objects. + +Sockets returned should be closed using the `socket-close' method or +by closing the stream associated with the socket. +" + (unless socket + (error 'invalid-socket-error)) + (unless stream + (error 'invalid-socket-stream-error)) + (make-instance 'stream-usocket + :socket socket + :stream stream)) + +(defun make-stream-server-socket (socket &key (element-type + #-lispworks 'character + #+lispworks 'base-char)) + "Create a usocket-server socket type from an +implementation-specific socket object. + +The returned value is a subtype of `stream-server-usocket'. +" + (unless socket + (error 'invalid-socket-error)) + (make-instance 'stream-server-usocket + :socket socket + :element-type element-type)) + +(defun make-datagram-socket (socket &key connected-p) + (unless socket + (error 'invalid-socket-error)) + (make-instance 'datagram-usocket + :socket socket + :connected-p connected-p)) + +(defgeneric socket-accept (socket &key element-type) + (:documentation + "Accepts a connection from `socket', returning a `stream-socket'. + +The stream associated with the socket returned has `element-type' when +explicitly specified, or the element-type passed to `socket-listen' otherwise.")) + +(defgeneric socket-close (usocket) + (:documentation "Close a previously opened `usocket'.")) + +(defmethod socket-close :before ((usocket usocket)) + (when (wait-list usocket) + (remove-waiter (wait-list usocket) usocket))) + +;; also see http://stackoverflow.com/questions/4160347/close-vs-shutdown-socket +(defgeneric socket-shutdown (usocket direction) + (:documentation "Shutdown communication on the socket in DIRECTION. + +After a shutdown no input and/or output of the indicated DIRECTION +can be performed on the `usocket'. + +DIRECTION should be either :INPUT or :OUTPUT or :IO")) + +(defgeneric socket-send (usocket buffer length &key host port) + (:documentation "Send packets through a previously opend `usocket'.")) + +(defgeneric socket-receive (usocket buffer length &key) + (:documentation "Receive packets from a previously opend `usocket'. + +Returns 4 values: (values buffer size host port)")) + +(defgeneric get-local-address (socket) + (:documentation "Returns the IP address of the socket.")) + +(defgeneric get-peer-address (socket) + (:documentation + "Returns the IP address of the peer the socket is connected to.")) + +(defgeneric get-local-port (socket) + (:documentation "Returns the IP port of the socket. + +This function applies to both `stream-usocket' and `server-stream-usocket' +type objects.")) + +(defgeneric get-peer-port (socket) + (:documentation "Returns the IP port of the peer the socket to.")) + +(defgeneric get-local-name (socket) + (:documentation "Returns the IP address and port of the socket as values. + +This function applies to both `stream-usocket' and `server-stream-usocket' +type objects.")) + +(defgeneric get-peer-name (socket) + (:documentation + "Returns the IP address and port of the peer +the socket is connected to as values.")) + +(defmacro with-connected-socket ((var socket) &body body) + "Bind `socket' to `var', ensuring socket destruction on exit. + +`body' is only evaluated when `var' is bound to a non-null value. + +The `body' is an implied progn form." + `(let ((,var ,socket)) + (unwind-protect + (when ,var + (with-mapped-conditions (,var) + ,@body)) + (when ,var + (socket-close ,var))))) + +(defmacro with-client-socket ((socket-var stream-var &rest socket-connect-args) + &body body) + "Bind the socket resulting from a call to `socket-connect' with +the arguments `socket-connect-args' to `socket-var' and if `stream-var' is +non-nil, bind the associated socket stream to it." + `(with-connected-socket (,socket-var (socket-connect ,@socket-connect-args)) + ,(if (null stream-var) + `(progn ,@body) + `(let ((,stream-var (socket-stream ,socket-var))) + ,@body)))) + +(defmacro with-server-socket ((var server-socket) &body body) + "Bind `server-socket' to `var', ensuring socket destruction on exit. + +`body' is only evaluated when `var' is bound to a non-null value. + +The `body' is an implied progn form." + `(with-connected-socket (,var ,server-socket) + ,@body)) + +(defmacro with-socket-listener ((socket-var &rest socket-listen-args) + &body body) + "Bind the socket resulting from a call to `socket-listen' with arguments +`socket-listen-args' to `socket-var'." + `(with-server-socket (,socket-var (socket-listen ,@socket-listen-args)) + ,@body)) + +(defstruct (wait-list (:constructor %make-wait-list)) + %wait ;; implementation specific + waiters ;; the list of all usockets + map) ;; maps implementation sockets to usockets + +;; Implementation specific: +;; +;; %setup-wait-list +;; %add-waiter +;; %remove-waiter + +(defun make-wait-list (waiters) + (let ((wl (%make-wait-list))) + (setf (wait-list-map wl) (make-hash-table)) + (%setup-wait-list wl) + (dolist (x waiters wl) ; wl is returned + (add-waiter wl x)))) + +(defun add-waiter (wait-list input) + (setf (gethash (socket input) (wait-list-map wait-list)) input + (wait-list input) wait-list) + (pushnew input (wait-list-waiters wait-list)) + (%add-waiter wait-list input)) + +(defun remove-waiter (wait-list input) + (%remove-waiter wait-list input) + (setf (wait-list-waiters wait-list) + (remove input (wait-list-waiters wait-list)) + (wait-list input) nil) + (remhash (socket input) (wait-list-map wait-list))) + +(defun remove-all-waiters (wait-list) + (dolist (waiter (wait-list-waiters wait-list)) + (%remove-waiter wait-list waiter)) + (setf (wait-list-waiters wait-list) nil) + (clrhash (wait-list-map wait-list))) + +(defun wait-for-input (socket-or-sockets &key timeout ready-only + &aux (single-socket-p + (usocket-p socket-or-sockets))) + "Waits for one or more streams to become ready for reading from +the socket. When `timeout' (a non-negative real number) is +specified, wait `timeout' seconds, or wait indefinitely when +it isn't specified. A `timeout' value of 0 (zero) means polling. + +Returns two values: the first value is the list of streams which +are readable (or in case of server streams acceptable). NIL may +be returned for this value either when waiting timed out or when +it was interrupted (EINTR). The second value is a real number +indicating the time remaining within the timeout period or NIL if +none. + +Without the READY-ONLY arg, WAIT-FOR-INPUT will return all sockets in +the original list you passed it. This prevents a new list from being +consed up. Some users of USOCKET were reluctant to use it if it +wouldn't behave that way, expecting it to cost significant performance +to do the associated garbage collection. + +Without the READY-ONLY arg, you need to check the socket STATE slot for +the values documented in usocket.lisp in the usocket class." + + ;; for NULL sockets, return NIL with respect of TIMEOUT. + (when (null socket-or-sockets) + (when timeout + (sleep timeout)) + (return-from wait-for-input nil)) + + ;; create a new wait-list if it's not created by the caller. + (unless (wait-list-p socket-or-sockets) + ;; OPTIMIZATION: in case socket-or-sockets is an atom, create the wait-list + ;; only once and store it into the usocket itself. + (let ((wl (if (and single-socket-p + (wait-list socket-or-sockets)) + (wait-list socket-or-sockets) ; reuse the per-usocket wait-list + (make-wait-list (if (listp socket-or-sockets) + socket-or-sockets (list socket-or-sockets)))))) + (multiple-value-bind (sockets to-result) + (wait-for-input wl :timeout timeout :ready-only ready-only) + ;; in case of single socket, keep the wait-list + (unless single-socket-p + (remove-all-waiters wl)) + (return-from wait-for-input + (values (if ready-only sockets socket-or-sockets) to-result))))) + + (let* ((start (get-internal-real-time)) + (sockets-ready 0)) + (dolist (x (wait-list-waiters socket-or-sockets)) + (when (setf (state x) + #+(and win32 (or sbcl ecl)) nil ; they cannot rely on LISTEN + #-(and win32 (or sbcl ecl)) + (if (and (stream-usocket-p x) + (listen (socket-stream x))) + :read + nil)) + (incf sockets-ready))) + ;; the internal routine is responsibe for + ;; making sure the wait doesn't block on socket-streams of + ;; which theready- socket isn't ready, but there's space left in the + ;; buffer. socket-or-sockets is not destructed. + (wait-for-input-internal socket-or-sockets + :timeout (if (zerop sockets-ready) timeout 0)) + (let ((to-result (when timeout + (let ((elapsed (/ (- (get-internal-real-time) start) + internal-time-units-per-second))) + (when (< elapsed timeout) + (- timeout elapsed)))))) + ;; two return values: + ;; 1) the original wait-list, or available sockets (ready-only) + ;; 2) remaining timeout + (values (cond (ready-only + (cond (single-socket-p + (if (null (state (car (wait-list-waiters socket-or-sockets)))) + nil ; nothing left if the only socket is not waiting + (wait-list-waiters socket-or-sockets))) + (t (remove-if #'null (wait-list-waiters socket-or-sockets) :key #'state)))) + (t socket-or-sockets)) + to-result)))) + +;; +;; Data utility functions +;; + +(defun integer-to-octet-buffer (integer buffer octets &key (start 0)) + (do ((b start (1+ b)) + (i (ash (1- octets) 3) ;; * 8 + (- i 8))) + ((> 0 i) buffer) + (setf (aref buffer b) + (ldb (byte 8 i) integer)))) + +(defun octet-buffer-to-integer (buffer octets &key (start 0)) + (let ((integer 0)) + (do ((b start (1+ b)) + (i (ash (1- octets) 3) ;; * 8 + (- i 8))) + ((> 0 i) + integer) + (setf (ldb (byte 8 i) integer) + (aref buffer b))))) + +(defmacro port-to-octet-buffer (port buffer &key (start 0)) + `(integer-to-octet-buffer ,port ,buffer 2 :start ,start)) + +(defmacro ip-to-octet-buffer (ip buffer &key (start 0)) + `(integer-to-octet-buffer (host-byte-order ,ip) ,buffer 4 :start ,start)) + +(defmacro port-from-octet-buffer (buffer &key (start 0)) + `(octet-buffer-to-integer ,buffer 2 :start ,start)) + +(defmacro ip-from-octet-buffer (buffer &key (start 0)) + `(octet-buffer-to-integer ,buffer 4 :start ,start)) + +;; +;; IPv4 utility functions +;; + +(defun list-of-strings-to-integers (list) + "Take a list of strings and return a new list of integers (from +parse-integer) on each of the string elements." + (let ((new-list nil)) + (dolist (element (reverse list)) + (push (parse-integer element) new-list)) + new-list)) + +(defun ip-address-string-p (string) + "Return a true value if the given string could be an IP address." + (every (lambda (char) + (or (digit-char-p char) + (eql char #\.))) + string)) + +(defun hbo-to-dotted-quad (integer) ; exported + "Host-byte-order integer to dotted-quad string conversion utility." + (let ((first (ldb (byte 8 24) integer)) + (second (ldb (byte 8 16) integer)) + (third (ldb (byte 8 8) integer)) + (fourth (ldb (byte 8 0) integer))) + (format nil "~A.~A.~A.~A" first second third fourth))) + +(defun hbo-to-vector-quad (integer) ; exported + "Host-byte-order integer to dotted-quad string conversion utility." + (let ((first (ldb (byte 8 24) integer)) + (second (ldb (byte 8 16) integer)) + (third (ldb (byte 8 8) integer)) + (fourth (ldb (byte 8 0) integer))) + (vector first second third fourth))) + +(defun vector-quad-to-dotted-quad (vector) ; exported + (format nil "~A.~A.~A.~A" + (aref vector 0) + (aref vector 1) + (aref vector 2) + (aref vector 3))) + +(defun dotted-quad-to-vector-quad (string) ; exported + (let ((list (list-of-strings-to-integers (split-sequence #\. string)))) + (vector (first list) (second list) (third list) (fourth list)))) + +(defgeneric host-byte-order (address)) ; exported + +(defmethod host-byte-order ((string string)) + "Convert a string, such as 192.168.1.1, to host-byte-order, +such as 3232235777." + (let ((list (list-of-strings-to-integers (split-sequence #\. string)))) + (+ (* (first list) 256 256 256) (* (second list) 256 256) + (* (third list) 256) (fourth list)))) + +(defmethod host-byte-order ((vector vector)) ; IPv4 only + "Convert a vector, such as #(192 168 1 1), to host-byte-order, such as +3232235777." + (+ (* (aref vector 0) 256 256 256) (* (aref vector 1) 256 256) + (* (aref vector 2) 256) (aref vector 3))) + +(defmethod host-byte-order ((int integer)) + int) ; this assume input integer is already host-byte-order + +;; +;; IPv6 utility functions +;; + +(defun vector-to-ipv6-host (vector) ; exported + (with-output-to-string (*standard-output*) + (loop with zeros-collapsed-p + with collapsing-zeros-p + for i below 16 by 2 + for word = (+ (ash (aref vector i) 8) + (aref vector (1+ i))) + do (cond + ((and (zerop word) + (not collapsing-zeros-p) + (not zeros-collapsed-p)) + (setf collapsing-zeros-p t)) + ((or (not (zerop word)) + zeros-collapsed-p) + (when collapsing-zeros-p + (write-string ":") + (setf collapsing-zeros-p nil + zeros-collapsed-p t)) + (format t "~:[~;:~]~X" (plusp i) word))) + finally (when collapsing-zeros-p + (write-string "::"))))) + +(defun split-ipv6-address (string) + (let ((pos 0) + word + double-colon-seen-p + words-before-double-colon + words-after-double-colon) + (loop + (multiple-value-setq (word pos) (parse-integer string :radix 16 :junk-allowed t :start pos)) + (labels ((at-end-p () + (= pos (length string))) + (looking-at-colon-p () + (char= (char string pos) #\:)) + (ensure-colon () + (unless (looking-at-colon-p) + (error "unsyntactic IPv6 address string ~S, expected a colon at position ~D" + string pos)) + (incf pos))) + (cond + ((null word) + (when double-colon-seen-p + (error "unsyntactic IPv6 address string ~S, can only have one double-colon filler mark" + string)) + (setf double-colon-seen-p t)) + (double-colon-seen-p + (push word words-after-double-colon)) + (t + (push word words-before-double-colon))) + (if (at-end-p) + (return (list (nreverse words-before-double-colon) (nreverse words-after-double-colon))) + (ensure-colon)))))) + +(defun ipv6-host-to-vector (string) ; exported + (assert (> (length string) 2) () + "Unsyntactic IPv6 address literal ~S, expected at least three characters" string) + (destructuring-bind (words-before-double-colon words-after-double-colon) + (split-ipv6-address (concatenate 'string + (when (eql (char string 0) #\:) + "0") + string + (when (eql (char string (1- (length string))) #\:) + "0"))) + (let ((number-of-words-specified (+ (length words-before-double-colon) (length words-after-double-colon)))) + (assert (<= number-of-words-specified 8) () + "Unsyntactic IPv6 address literal ~S, too many colon separated address components" string) + (assert (or (= number-of-words-specified 8) words-after-double-colon) () + "Unsyntactic IPv6 address literal ~S, too few address components and no double-colon filler found" string) + (loop with vector = (make-array 16 :element-type '(unsigned-byte 8)) + for i below 16 by 2 + for word in (append words-before-double-colon + (make-list (- 8 number-of-words-specified) :initial-element 0) + words-after-double-colon) + do (setf (aref vector i) (ldb (byte 8 8) word) + (aref vector (1+ i)) (ldb (byte 8 0) word)) + finally (return vector))))) + +;; exported since 0.8.0 +(defun host-to-hostname (host) ; host -> string + "Translate a string, vector quad or 16 byte IPv6 address to a +stringified hostname." + (etypecase host + (string host) ; IPv4 or IPv6 + ((or (vector t 4) ; IPv4 + (array (unsigned-byte 8) (4))) + (vector-quad-to-dotted-quad host)) + ((or (vector t 16) ; IPv6 + (array (unsigned-byte 8) (16))) + (vector-to-ipv6-host host)) + (integer (hbo-to-dotted-quad host)) ; integer input is IPv4 only + (null "0.0.0.0"))) ; null is IPv4 + +(defun ip= (ip1 ip2) ; exported + (etypecase ip1 + (string (string= ip1 ; IPv4 or IPv6 + (host-to-hostname ip2))) + ((or (vector t 4) ; IPv4 + (array (unsigned-byte 8) (4)) ; IPv4 + (vector t 16) ; IPv6 + (array (unsigned-byte 8) (16))) ; IPv6 + (equalp ip1 ip2)) + (integer (= ip1 ; IPv4 only + (host-byte-order ip2))))) ; convert ip2 to integer (hbo) + +(defun ip/= (ip1 ip2) ; exported + (not (ip= ip1 ip2))) + +;; +;; DNS helper functions +;; + +(defun get-host-by-name (name) + "0.7.1+: if there're IPv4 addresses, return the first IPv4 address." + (let* ((hosts (get-hosts-by-name name)) + (pos (position-if #'(lambda (ip) (= 4 (length ip))) hosts))) + (if pos (elt hosts pos) + (car hosts)))) + +(defun get-random-host-by-name (name) + "0.7.1+: if there're IPv4 addresses, only return a random IPv4 address." + (let* ((hosts (get-hosts-by-name name)) + (ipv4-hosts (remove-if-not #'(lambda (ip) (= 4 (length ip))) hosts))) + (cond (ipv4-hosts + (elt ipv4-hosts (random (length ipv4-hosts)))) + (hosts + (elt hosts (random (length hosts))))))) + +(defun host-to-vector-quad (host) ; internal + "Translate a host specification (vector quad, dotted quad or domain name) +to a vector quad." + (etypecase host + (string (let* ((ip (when (ip-address-string-p host) + (dotted-quad-to-vector-quad host)))) + (if (and ip (= 4 (length ip))) + ;; valid IP dotted quad? not sure + ip + (get-random-host-by-name host)))) + ((or (vector t 4) + (array (unsigned-byte 8) (4))) + host) + (integer (hbo-to-vector-quad host)))) + +(defun host-to-hbo (host) ; internal + (etypecase host + (string (let ((ip (when (ip-address-string-p host) + (dotted-quad-to-vector-quad host)))) + (if (and ip (= 4 (length ip))) + (host-byte-order ip) + (host-to-hbo (get-host-by-name host))))) + ((or (vector t 4) + (array (unsigned-byte 8) (4))) + (host-byte-order host)) + (integer host))) + +;; +;; Other utility functions +;; + +(defun split-timeout (timeout &optional (fractional 1000000)) + "Split real value timeout into seconds and microseconds. +Optionally, a different fractional part can be specified." + (multiple-value-bind + (secs sec-frac) + (truncate timeout 1) + (values secs + (truncate (* fractional sec-frac) 1)))) + +;; +;; Setting of documentation for backend defined functions +;; + +;; Documentation for the function +;; +;; (defun SOCKET-CONNECT (host port &key element-type nodelay some-other-keys...) ..) +;; +(setf (documentation 'socket-connect 'function) + "Connect to `host' on `port'. `host' is assumed to be a string or +an IP address represented in vector notation, such as #(192 168 1 1). +`port' is assumed to be an integer. + +`element-type' specifies the element type to use when constructing the +stream associated with the socket. The default is 'character. + +`nodelay' Allows to disable/enable Nagle's algorithm (http://en.wikipedia.org/wiki/Nagle%27s_algorithm). +If this parameter is omitted, the behaviour is inherited from the +CL implementation (in most cases, Nagle's algorithm is +enabled by default, but for example in ACL it is disabled). +If the parameter is specified, one of these three values is possible: + T - Disable Nagle's algorithm; signals an UNSUPPORTED + condition if the implementation does not support explicit + manipulation with that option. + NIL - Leave Nagle's algorithm enabled on the socket; + signals an UNSUPPORTED condition if the implementation does + not support explicit manipulation with that option. + :IF-SUPPORTED - Disables Nagle's algorithm if the implementation + allows this, otherwises just ignore this option. + +Returns a usocket object.") + +;; Documentation for the function +;; +;; (defun SOCKET-LISTEN (host port &key reuseaddress backlog element-type) ..) +;;###FIXME: extend with default-element-type +(setf (documentation 'socket-listen 'function) + "Bind to interface `host' on `port'. `host' should be the +representation of an ready-interface address. The implementation is +not required to do an address lookup, making no guarantees that +hostnames will be correctly resolved. If `*wildcard-host*' or NIL is +passed for `host', the socket will be bound to all available +interfaces for the system. `port' can be selected by the IP stack by +passing `*auto-port*'. + +Returns an object of type `stream-server-usocket'. + +`reuse-address' and `backlog' are advisory parameters for setting socket +options at creation time. `element-type' is the element type of the +streams to be created by `socket-accept'. `reuseaddress' is supported for +backward compatibility (but deprecated); when both `reuseaddress' and +`reuse-address' have been specified, the latter takes precedence. +") + +;;; Small utility functions mapping true/false to 1/0, moved here from option.lisp + +(proclaim '(inline bool->int int->bool)) + +(defun bool->int (bool) (if bool 1 0)) +(defun int->bool (int) (= 1 int)) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/vendor/OpenTransportUDP.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/vendor/OpenTransportUDP.lisp new file mode 100644 index 0000000..5dc3cdc --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/vendor/OpenTransportUDP.lisp @@ -0,0 +1,146 @@ +;;;-*-Mode: LISP; Package: CCL -*- +;; +;;; OpenTransportUDP.lisp +;;; Copyright 2012 Chun Tian (binghe) + +;;; UDP extension to OpenTransport.lisp (with some TCP patches) + +(in-package "CCL") + +(eval-when (:compile-toplevel :load-toplevel :execute) + (require :opentransport)) + +;; MCL Issue 28: Passive TCP streams should be able to listen to the loopback interface +;; see http://code.google.com/p/mcl/issues/detail?id=28 for details + +(defparameter *passive-interface-address* NIL + "Address to use for passive connections - optionally bind to loopback address while opening a tcp stream") + +(advise local-interface-ip-address + (or *passive-interface-address* (:do-it)) + :when :around :name 'override-local-interface-ip-address) + +;; MCL Issue 29: Passive TCP connections on OS assigned ports +;; see http://code.google.com/p/mcl/issues/detail?id=29 for details +(advise ot-conn-tcp-passive-connect + (destructuring-bind (conn port &optional (allow-reuse t)) arglist + (declare (ignore allow-reuse)) + (if (eql port #$kOTAnyInetAddress) + ;; Avoids registering a proxy for port 0 but instead registers one for the true port: + (multiple-value-bind (proxy result) + (let* ((*opentransport-class-proxies* NIL) ; makes ot-find-proxy return NIL + (result (:do-it)) ;; pushes onto *opentransport-class-proxies* + (proxy (prog1 + (pop *opentransport-class-proxies*) + (assert (not *opentransport-class-proxies*)))) + (context (cdr proxy)) + (tmpconn (make-ot-conn :context context + :endpoint (pref context :ot-context.ref))) + (localaddress (ot-conn-tcp-get-addresses tmpconn))) + (declare (dynamic-extent tmpconn)) + ;; replace original set in body of function + (setf (ot-conn-local-address conn) localaddress) + (values + (cons localaddress context) + result)) + ;; need to be outside local binding of *opentransport-class-proxies* + (without-interrupts + (push proxy *opentransport-class-proxies*)) + result) + (:do-it))) + :when :around :name 'ot-conn-tcp-passive-connect-any-address) + +(defun open-udp-socket (&key local-address local-port) + (init-opentransport) + (let (endpoint ; TODO: opentransport-alloc-endpoint-from-freelist + (err #$kOTNoError) + (configptr (ot-cloned-configuration traps::$kUDPName))) + (rlet ((errP :osstatus)) + (setq endpoint #+carbon-compat (#_OTOpenEndpointInContext configptr 0 (%null-ptr) errP *null-ptr*) + #-carbon-compat (#_OTOpenEndpoint configptr 0 (%null-ptr) errP) + err (pref errP :osstatus)) + (if (eql err #$kOTNoError) + (let* ((context (ot-make-endpoint-context endpoint nil nil)) ; no notifier, not minimal + (conn (make-ot-conn :context context :endpoint endpoint))) + (macrolet ((check-ot-error-return (error-context) + `(unless (eql (setq err (pref errP :osstatus)) #$kOTNoError) + (values (ot-error err ,error-context))))) + (setf (ot-conn-bindreq conn) + #-carbon-compat (#_OTAlloc endpoint #$T_BIND #$T_ADDR errP) + #+carbon-compat (#_OTAllocInContext endpoint #$T_BIND #$T_ADDR errP *null-ptr*) + ) + (check-ot-error-return :alloc) + (setf (ot-conn-bindret conn) + #-carbon-compat (#_OTAlloc endpoint #$T_BIND #$T_ADDR errP) + #+carbon-compat (#_OTAllocInContext endpoint #$T_BIND #$T_ADDR errP *null-ptr*) + ) + (check-ot-error-return :alloc) + (setf (ot-conn-options conn) + #-carbon-compat (#_OTAlloc endpoint #$T_OPTMGMT #$T_OPT errP) + #+carbon-compat (#_OTAllocInContext endpoint #$T_OPTMGMT #$T_OPT errP *null-ptr*) + ) + (check-ot-error-return :alloc)) + ;; BIND to local address (for UDP server) + (when local-port ; local-address + (let* ((host (or local-address (local-interface-ip-address))) + (port (tcp-service-port-number local-port)) + (localaddress `(:tcp ,host ,port)) + (bindreq (ot-conn-bindreq conn)) + (bindret (ot-conn-bindret conn))) + (let* ((netbuf (pref bindreq :tbind.addr))) + (declare (dynamic-extent netbuf)) + (setf (pref netbuf :tnetbuf.len) (record-length :inetaddress) + (pref bindreq :tbind.qlen) 5) ; arbitrary qlen + (#_OTInitInetAddress (pref netbuf :tnetbuf.buf) port host) + (setf (pref context :ot-context.completed) nil) + (unless (= (setq err (#_OTBind endpoint bindreq bindret)) #$kOTNoError) + (ot-error err :bind))) + (setf (ot-conn-local-address conn) localaddress))) + conn) + (ot-error err :create))))) + +(defun make-TUnitData (endpoint) + "create the send/recv buffer for UDP sockets" + (let ((err #$kOTNoError)) + (rlet ((errP :osstatus)) + (macrolet ((check-ot-error-return (error-context) + `(unless (eql (setq err (pref errP :osstatus)) #$kOTNoError) + (values (ot-error err ,error-context))))) + (let ((udata #-carbon-compat (#_OTAlloc endpoint #$T_UNITDATA #$T_ALL errP) + #+carbon-compat (#_OTAllocInContext endpoint #$T_UNITDATA #$T_ALL errP *null-ptr*))) + (check-ot-error-return :alloc) + udata))))) + +(defun send-message (conn data buffer size host port &optional (offset 0)) + ;; prepare dest address + (let ((addr (pref data :tunitdata.addr))) + (declare (dynamic-extent addr)) + (setf (pref addr :tnetbuf.len) (record-length :inetaddress)) + (#_OTInitInetAddress (pref addr :tnetbuf.buf) port host)) + ;; prepare data buffer + (let* ((udata (pref data :tunitdata.udata)) + (outptr (pref udata :tnetbuf.buf))) + (declare (dynamic-extent udata)) + (%copy-ivector-to-ptr buffer offset outptr 0 size) + (setf (pref udata :tnetbuf.len) size)) + ;; send the packet + (let* ((endpoint (ot-conn-endpoint conn)) + (result (#_OTSndUData endpoint data))) + (the fixnum result))) + +(defun receive-message (conn data buffer length) + (let* ((endpoint (ot-conn-endpoint conn)) + (err (#_OTRcvUData endpoint data *null-ptr*))) + (if (eql err #$kOTNoError) + (let* (;(addr (pref data :tunitdata.addr)) + (udata (pref data :tunitdata.udata)) + (inptr (pref udata :tnetbuf.buf)) + (read-bytes (pref udata :tnetbuf.len)) + (buffer (or buffer (make-array read-bytes :element-type '(unsigned-byte 8)))) + (length (or length (length buffer))) + (actual-size (min read-bytes length))) + (%copy-ptr-to-ivector inptr 0 buffer 0 actual-size) + (values buffer + actual-size + 0 0)) ; TODO: retrieve address and port + (ot-error err :receive)))) ; TODO: use OTRcvUDErr instead diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/vendor/kqueue.lisp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/vendor/kqueue.lisp new file mode 100644 index 0000000..72d370f --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/vendor/kqueue.lisp @@ -0,0 +1,506 @@ +;;;-*-Mode: LISP; Package: CCL -*- +;; +;; KQUEUE.LISP +;; +;; KQUEUE - BSD kernel event notification mechanism support for Common LISP. +;; Copyright (C) 2007 Terje Norderhaug +;; Released under LGPL - see . +;; Alternative licensing available upon request. +;; +;; DISCLAIMER: The user of this module should understand that executing code is a potentially hazardous +;; activity, and that many dangers and obstacles, marked or unmarked, may exist within this code. +;; As a condition of your use of the module, you assume all risk of personal injury, death, or property +;; loss, and all other bad things that may happen, even if caused by negligence, ignorance or stupidity. +;; The author is is no way responsible, and besides, does not have "deep pockets" nor any spare change. +;; +;; Version: 0.20 alpha (July 26, 2009) - subject to major revisions, so consider yourself warned. +;; Tested with Macintosh Common LISP 5.1 and 5.2, but is intended to be platform and system independent in the future. +;; +;; Email feedback and improvements to . +;; Updated versions will be available from . +;; +;; RELATED IMPLEMENTATIONS +;; There is another kevent.lisp for other platforms by Risto Laakso (merge?). +;; Also a Scheme kevent.ss by Jose Antonio Ortega. +;; +;; SEE ALSO: +;; http://people.freebsd.org/~jlemon/papers/kqueue.pdf +;; http://developer.apple.com/samplecode/FileNotification/index.html +;; The Man page for kqueue() or kevent(). +;; PyKQueue - Python OO interface to KQueue. +;; LibEvent - an event notification library in C by Niels Provos. +;; Liboop - another abstract library in C on top of kevent or other kernel notification. + +#| HISTORY: + +2007-Oct-18 terje version 0.1 released on the Info-MCL mailing list. +2008-Aug-21 terje load-framework-bundle is not needed under MCL 5.2 +2008-Aug-21 terje rename get-addr to lookup-function-in-bundle (only for pre MCL 5.2) +2009-Jul-19 terje uses kevent-error condition and strerror. +2009-Jul-24 terje reports errors unless nil-if-not-found in lookup-function-in-bundle. +2009-Jul-24 terje kevent :variant for C's intptr_t type for 64bit (and osx 10.5) compatibility. +2009-Jul-25 terje 64bit support, dynamically determined for PPC. Kudos to Glen Foy for helping out. +2009-Jul-25 terje make-kevent function. +|# + +#| IMPLEMENTATION NOTES: + +kevents are copied into and from the kernel, so the records don't have to be kept in the app! +kevents does not work in OSX before 10.3. +*kevent-record* has to be explcitly set to :kevent64 to work on 64bit intel macs. +Consider using sysctlbyname() to test for 64bit, + combining hw.cpu64bit_capable, hw.optional.x86_64 and hw.optional.64bitops +|# + +(in-package :ccl) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +#-ccl-5.2 ; has been added to MCL 5.2 +(defmethod load-framework-bundle ((framework-name string) &key (load-executable t)) + ;; FRAMWORK CALL FUNCTIONALITY FROM BSD.LISP + ;; (C) 2003 Brendan Burns + ;; Released under LGPL. + (with-cfstrs ((framework framework-name)) + (let ((err 0) + (baseURL nil) + (bundleURL nil) + (result nil)) + (rlet ((folder :fsref)) + ;; Find the folder holding the bundle + (setf err (#_FSFindFolder #$kOnAppropriateDisk #$kFrameworksFolderType + t folder)) + + ;; if everything's cool, make a URL for it + (when (zerop err) + (setf baseURL (#_CFURLCreateFromFSRef (%null-ptr) folder)) + (if (%null-ptr-p baseURL) + (setf err #$coreFoundationUnknownErr))) + + ;; if everything's cool, make a URL for the bundle + (when (zerop err) + (setf bundleURL (#_CFURLCreateCopyAppendingPathComponent (%null-ptr) + baseURL framework nil)) + (if (%null-ptr-p bundleURL) + (setf err #$coreFoundationUnknownErr))) + + ;; if everything's cool, load it + (when (zerop err) + (setf result (#_CFBundleCreate (%null-ptr) bundleURL)) + (if (%null-ptr-p result) + (setf err #$coreFoundationUnknownErr))) + + ;; if everything's cool, and the user wants it loaded, load it + (when (and load-executable (zerop err)) + (if (not (#_CFBundleLoadExecutable result)) + (setf err #$coreFoundationUnknownErr))) + + ;; if there's an error, but we've got a pointer, free it and clear result + (when (and (not (zerop err)) (not (%null-ptr-p result))) + (#_CFRelease result) + (setf result nil)) + + ;; free the URLs if there non-null + (when (not (%null-ptr-p bundleURL)) + (#_CFRelease bundleURL)) + (when (not (%null-ptr-p baseURL)) + (#_CFRelease baseURL)) + + ;; return pointer + error value + (values result err))))) + +#+ignore +(defun get-addr (bundle name) + (let* ((addr (#_CFBundleGetFunctionPointerForName bundle name))) + (rlet ((buf :long)) + (setf (%get-ptr buf) addr) + (ash (%get-signed-long buf) -2)))) + +#-ccl-5.2 +(defun lookup-function-in-bundle (name bundle &optional nil-if-not-found) + (with-cfstrs ((str name)) + (let* ((addr (#_CFBundleGetFunctionPointerForName bundle str))) + (if (%null-ptr-p addr) + (unless nil-if-not-found + (error "Couldn't resolve address of foreign function ~s" name)) + (rlet ((buf :long)) ;; mcl 5.2 uses %fixnum-from-macptr here + (setf (%get-ptr buf) addr) + (ash (%get-signed-long buf) -2)))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Convenient way to declare BSD system calls + +#+ignore +(defparameter *system-bundle* + #+ccl-5.2 (get-bundle-for-framework-name "System.framework") + #-ccl-5.2 + (let ((bundle (load-framework-bundle "System.framework"))) + (terminate-when-unreachable bundle (lambda (b)(#_CFRelease b))) + bundle)) + +(defmacro declare-bundle-ff (name name-string &rest arglist &aux (fn (gensym (format nil "ff_~A_" (string name))))) + ;; Is there an existing define-trap like macro for this? or could one be modified for use with bundles? + `(progn + (defloadvar ,fn + (let* ((bundle #+ccl-5.2 (get-bundle-for-framework-name "System.framework") + #-ccl-5.2 + (let ((bundle (load-framework-bundle "System.framework"))) + (terminate-when-unreachable bundle (lambda (b)(#_CFRelease b))) + bundle))) + (lookup-function-in-bundle ,name-string bundle))) + ,(let ((args (do ((arglist arglist (cddr arglist)) + (result)) + ((not (cdr arglist)) (nreverse result)) + (push (second arglist) result)))) + `(defun ,name ,args + (ppc-ff-call ,fn ,@arglist))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(declare-bundle-ff %system-kqueue "kqueue" + :signed-fullword) ;; returns a file descriptor no! + +(defun system-kqueue () + (let ((kq (%system-kqueue))) + (if (= kq -1) + (ecase (%system-errno) + (12 (error "The kernel failed to allocate enough memory for the kernel queue")) ; ENOMEM + (24 (error "The per-process descriptor table is full")) ; EMFILE + (23 (error "The system file table is full"))) ; ENFILE + kq))) + +(declare-bundle-ff %system-kevent "kevent" + :unsigned-fullword kq + :address ke + :unsigned-fullword nke + :address ko + :unsigned-fullword nko + :address timeout + :signed-fullword) + +(declare-bundle-ff %system-open "open" + :address name + :unsigned-fullword mode + :unsigned-fullword arg + :signed-fullword) + +(declare-bundle-ff %system-close "close" + :unsigned-fullword fd + :signed-fullword) + +(declare-bundle-ff %system-errno* "__error" + :signed-fullword) + +(declare-bundle-ff %system-strerror "strerror" + :signed-fullword errno + :address) + +(defun %system-errno () + (%get-fixnum (%int-to-ptr (%system-errno*)))) + +; (%system-errno) + +(defconstant $O-EVTONLY #x8000) +; (defconstant $O-NONBLOCK #x800 "Non blocking mode") + +(defun system-open (posix-namestring) + "Low level open function, as in C, returns an fd number" + (with-cstrs ((name posix-namestring)) + (%system-open name $O-EVTONLY 0))) + +(defun system-close (fd) + (%system-close fd)) + +(defrecord timespec + (sec :unsigned-long) + (usec :unsigned-long)) + +(defVar *kevent-record* nil) + +(def-ccl-pointers determine-64bit-kevents () + (setf *kevent-record* + (if (ccl::gestalt #$gestaltPowerPCProcessorFeatures + #+ccl-5.2 #$gestaltPowerPCHas64BitSupport #-ccl-5.2 6) + :kevent32 + :kevent64))) + +(defrecord :kevent32 + (ident :unsigned-long) ; uintptr_t + (filter :short) + (flags :unsigned-short) + (fflags :unsigned-long) + (data :long) ; intptr_t + (udata :pointer)) + +(defrecord :kevent64 + (:variant ; uintptr_t + ((ident64 :uint64)) + ((ident :unsigned-long))) + (filter :short) + (flags :unsigned-short) + (fflags :unsigned-long) + (:variant ; intptr_t + ((data64 :sint64)) + ((data :long))) + (:variant ; RMCL :pointer is 32bit + ((udata64 :uint64)) + ((udata :pointer)))) + +(defun make-kevent (&key (ident 0) (filter 0) (flags 0) (fflags 0) (data 0) (udata *null-ptr*)) + (ecase *kevent-record* + (:kevent64 + (make-record kevent64 + :ident ident + :filter filter + :flags flags + :fflags fflags + :data data + :udata udata)) + (:kevent32 + (make-record kevent32 + :ident ident + :filter filter + :flags flags + :fflags fflags + :data data + :udata udata)))) + +(defun kevent-rref (ke field) + (ecase *kevent-record* + (:kevent32 + (ecase field + (:ident (rref ke :kevent32.ident)) + (:filter (rref ke :kevent32.filter)) + (:flags (rref ke :kevent32.flags)) + (:fflags (rref ke :kevent32.fflags)) + (:data (rref ke :kevent32.data)) + (:udata (rref ke :kevent32.udata)))) + (:kevent64 + (ecase field + (:ident (rref ke :kevent64.ident)) + (:filter (rref ke :kevent64.filter)) + (:flags (rref ke :kevent64.flags)) + (:fflags (rref ke :kevent64.fflags)) + (:data (rref ke :kevent64.data)) + (:udata (rref ke :kevent64.udata)))))) + +(defun kevent-filter (ke) + (kevent-rref ke :filter)) + +(defun kevent-flags (ke) + (kevent-rref ke :flags)) + +(defun kevent-data (ke) + (kevent-rref ke :data)) + + +;; FILTER TYPES: + +(eval-when (:compile-toplevel :load-toplevel :execute) ; added by binghe + +(defconstant $kevent-read-filter -1 "Data available to read") +(defconstant $kevent-write-filter -2 "Writing is possible") +(defconstant $kevent-aio-filter -3 "AIO system call has been made") +(defconstant $kevent-vnode-filter -4 "Event occured on a file descriptor") +(defconstant $kevent-proc-filter -5 "Process performed one or more of the requested events") +(defconstant $kevent-signal-filter -6 "Attempted to deliver a signal to a process") +(defconstant $kevent-timer-filter -7 "Establishes an arbitrary timer") +(defconstant $kevent-netdev-filter -8 "Event occured on a network device") +(defconstant $kevent-filesystem-filter -9) + +) ; eval-when + +; FLAGS: + +(defconstant $kevent-add #x01) +(defconstant $kevent-delete #x02) +(defconstant $kevent-enable #x04) +(defconstant $kevent-disable #x08) +(defconstant $kevent-oneshot #x10) +(defconstant $kevent-clear #x20) +(defconstant $kevent-error #x4000) +(defconstant $kevent-eof #x8000 "EV_EOF") + +;; FFLAGS: + +(defconstant $kevent-file-delete #x01 "The file was unlinked from the file system") +(defconstant $kevent-file-write #x02 "A write occurred on the file") +(defconstant $kevent-file-extend #x04 "The file was extended") +(defconstant $kevent-file-attrib #x08 "The file had its attributes changed") +(defconstant $kevent-file-link #x10 "The link count on the file changed") +(defconstant $kevent-file-rename #x20 "The file was renamed") +(defconstant $kevent-file-revoke #x40 "Access to the file was revoked or the file system was unmounted") +(defconstant $kevent-file-all (logior $kevent-file-delete $kevent-file-write $kevent-file-extend + $kevent-file-attrib $kevent-file-link $kevent-file-rename $kevent-file-revoke)) + + +(defconstant $kevent-net-linkup #x01 "Link is up") +(defconstant $kevent-net-linkdown #x02 "Link is down") +(defconstant $kevent-net-linkinvalid #x04 "Link state is invalid") +(defconstant $kevent-net-added #x08 "IP adress added") +(defconstant $kevent-net-deleted #x10 "IP adress deleted") + +(define-condition kevent-error (simple-error) + ((errno :initform NIL :initarg :errno) + (ko :initform nil :type (or null kevent) :initarg :ko) + (syserr :initform (%system-errno))) + (:report + (lambda (c s) + (with-slots (errno ko syserr) c + (format s "kevent system call error ~A [~A]" errno syserr) + (when errno + (format s "(~A)" (%get-cstring (%system-strerror errno)))) + (when ko + (format s " for ") + (let ((*standard-output* s)) + (print-record ko *kevent-record*))))))) + +(defun %kevent (kq &optional ke ko (timeout 0)) + (check-type kq integer) + (rlet ((&timeout :timespec :sec timeout :usec 1)) + (let ((num (with-timer ;; does not seem to make a difference... + (%system-kevent kq (or ke (%null-ptr))(if ke 1 0)(or ko (%null-ptr))(if ko 1 0) &timeout)))) + ; "If an error occurs while processing an element of the changelist and there + ; is enough room in the eventlist, then the event will be placed in the eventlist with + ; EV_ERROR set in flags and the system error in data." + (when (and ko (plusp (logand $kevent-error (kevent-flags ko)))) + (error 'kevent-error + :errno (kevent-data ko) + :ko ko)) + ; "Otherwise, -1 will be returned, and errno will be set to indicate the error condition." + (when (= num -1) + ;; hack - opentransport provides the constants for the errors documented for the call + (case (%system-errno) + (0 (error "kevent system call failed with an unspecified error")) ;; should not happen! + (13 (error "The process does not have permission to register a filter")) + (14 (error "There was an error reading or writing the kevent structure")) ; EFAULT + (9 (error "The specified descriptor is invalid")) ; EBADF + (4 (error "A signal was delivered before the timeout expired and before any events were placed on the kqueue for return.")) ; EINTR + (22 (error "The specified time limit or filter is invalid")) ; EINVAL + (2 (error "The event could not be found to be modified or deleted")) ; ENOENT + (12 (error "No memory was available to register the event")) ; ENOMEM + (78 (error "The specified process to attach to does not exist"))) ; ESRCH + ;; shouldn't get here... + (errchk (%system-errno)) + (error "error ~A" (%system-errno))) + (unless (zerop num) + (values ko num))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; CLOS INTERFACE + +(defclass kqueue () + ((kq :initform (system-kqueue) + :documentation "file descriptor referencing the kqueue") + (fds :initform NIL)) ;; ## better if kept on top level, perhaps as a hash table... + (:documentation "A kernal event notification channel")) + +(defmethod initialize-instance :after ((q kqueue) &rest rest) + (declare (ignore rest)) + (terminate-when-unreachable q 'kqueue-close)) + +(defmethod kqueue-close ((q kqueue)) + (with-slots (kq fds) q + (when (or kq fds) ;; allow repeated close + (system-close kq) + (setf fds NIL) + (setf kq NIL)))) + +(defmethod kqueue-poll ((q kqueue)) + "Polls a kqueue for kevents" + ;; may not have to be cleared, but just in case: + (flet ((kqueue-poll2 (ko) + (let ((result (with-slots (kq) q + (without-interrupts + (%kevent kq NIL ko))))) + (when result + (let ((type (kevent-filter result))) + (ecase type + (0 (values)) + (#.$kevent-read-filter + (values + :read + (kevent-rref result :ident) + (kevent-rref result :flags) + (kevent-rref result :fflags) + (kevent-rref result :data) + (kevent-rref result :udata))) + (#.$kevent-write-filter :write) + (#.$kevent-aio-filter :aio) + (#.$kevent-vnode-filter + (values + :vnode + (cdr (assoc (kevent-rref result :ident) (slot-value q 'fds))) + (kevent-rref result :flags) + (kevent-rref result :fflags) + (kevent-rref result :data) + (kevent-rref result :udata))) + (#.$kevent-filesystem-filter :filesystem))))))) + (ecase *kevent-record* + (:kevent64 + (rlet ((ko :kevent64 :ident 0 :filter 0 :flags 0 :fflags 0 :data 0 :udata (%null-ptr))) + (kqueue-poll2 ko))) + (:kevent32 + (rlet ((ko :kevent32 :ident 0 :filter 0 :flags 0 :fflags 0 :data 0 :udata (%null-ptr))) + (kqueue-poll2 ko)))))) + +(defmethod kqueue-subscribe ((q kqueue) &key ident filter (flags 0) (fflags 0) (data 0) (udata (%null-ptr))) + (let ((ke (make-kevent :ident ident + :filter filter + :flags flags + :fflags fflags + :data data + :udata udata))) + (with-slots (kq) q + (without-interrupts + (%kevent kq ke))))) + +(defmethod kqueue-vnode-subscribe ((q kqueue) pathname) + "Makes the queue report an event when there is a change to a directory or file" + (let* ((namestring (posix-namestring (full-pathname pathname))) + (fd (system-open namestring))) + (with-slots (fds) q + (push (cons fd pathname) fds)) + (kqueue-subscribe q + :ident fd + :filter $kevent-vnode-filter + :flags (logior $kevent-add $kevent-clear) + :fflags $kevent-file-all) + namestring)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +#+test +(defun kevent-d (pathname &optional (*standard-output* (fred))) + "Report changes to a file or directory" + (loop + with kqueue = (make-instance 'kqueue) + with sub = (kqueue-vnode-subscribe kqueue pathname) + for i from 1 to 60 + for result = (multiple-value-list (kqueue-poll kqueue)) + unless (equal result '(NIL)) + do (progn + (format T "~A~%" result) + (force-output)) + ; do (process-allow-schedule) + do (sleep 1) + finally (write-line "Done") + )) + +#| + +; Report changes to this file in a fred window (save this document to see what happens): + +(process-run-function "kevent-d" #'kevent-d *loading-file-source-file* + (fred)) + +; Reports files added or removed from the directory of this file: + +(process-run-function "kevent-d" #'kevent-d + (make-pathname :directory (pathname-directory *loading-file-source-file*)) + (fred)) +|# + + + + diff --git a/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/version.sexp b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/version.sexp new file mode 100644 index 0000000..b33445a --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/usocket-0.8.3/version.sexp @@ -0,0 +1 @@ +"0.8.3" diff --git a/sbcl/.quicklisp/dists/quicklisp/software/vom-20160825-git/LICENSE b/sbcl/.quicklisp/dists/quicklisp/software/vom-20160825-git/LICENSE new file mode 100644 index 0000000..3d15c9c --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/vom-20160825-git/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2014 Lyon Bros. Enterprises, LLC + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/sbcl/.quicklisp/dists/quicklisp/software/vom-20160825-git/README.md b/sbcl/.quicklisp/dists/quicklisp/software/vom-20160825-git/README.md new file mode 100644 index 0000000..71cc47c --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/vom-20160825-git/README.md @@ -0,0 +1,82 @@ +Vom - A tiny logging library for Common Lisp +============================================ + +Vom is a logging library for lisp. It's goal is to be useful and small. It does +not provide a lot of features as other loggers do, but has a small codebase +that's easy to understand and use. + +## Documentation + +Logging is done by calling one of the logging macros: + +- emerg +- alert +- crit +- error +- warn +- notice +- info +- debug +- debug1 +- debug2 +- debug3 +- debug4 + +Each of these is a macro defined as such: + +```lisp +(defmacro notice (format-str &rest args) ...) +``` + +They are used almost exactly like `format` (but without specifying the stream): + +```lisp +(vom:error "there was a problem setting up your database: ~a" error) +``` + +### Configuration + +You can set a global logging level: + +```lisp +;; set the default loglevel such that only errors (or higher) get logged +(vom:config t :error) +``` + +or you can set per-package loglevels: + +```lisp +(vom:config :my-package :notice) +``` + +In the above examples, any unconfigured package will have the loglevel of +`:error`, but the package `my-package` will log anything that's a `:notice` or +above. + +### \*log-stream\* + +The stream that vom logs to by default. This defaults to `t` (aka +`*standard-output*`) + +### \*log-hook\* + +This is a function of 3 arguments that takes a log level, a package keyword +name, and that package's configured log level and returns one or more streams as +multiple values that the log entry will be logged to: + +```lisp +;; example: this hook logs the request to multiple streams if we're getting a +;; log entry from the "particle-accelerator" package +(setf vom:*log-hook* + (lambda (level package package-level) + (declare (ignore level package-level)) + (if (eq package :particle-accelerator) + (values t *my-file-log-stream* *another-stream*) + t))) +``` + +## License + +MIT. Do what you want with it. Just give me credit. Or I'll come to your house +for two weeks and eat your food and sleep on your couch and use your toothbrush. + diff --git a/sbcl/.quicklisp/dists/quicklisp/software/vom-20160825-git/vom.asd b/sbcl/.quicklisp/dists/quicklisp/software/vom-20160825-git/vom.asd new file mode 100644 index 0000000..614b37e --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/vom-20160825-git/vom.asd @@ -0,0 +1,6 @@ +(asdf:defsystem vom + :author "Andrew Danger Lyon " + :license "MIT" + :version "0.1.4" + :description "A tiny logging utility." + :components ((:file "vom"))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/vom-20160825-git/vom.lisp b/sbcl/.quicklisp/dists/quicklisp/software/vom-20160825-git/vom.lisp new file mode 100644 index 0000000..aafd501 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/vom-20160825-git/vom.lisp @@ -0,0 +1,204 @@ +(defpackage :vom + ;; DON'T use :cl, otherwise most of the implementations bitch about using + ;; error and warn functions + (:use) + ;; import everything from cl that we actually need. while obnoxious, it makes + ;; sure vom runs smoothly on most (all?) implementations. + (:import-from #:cl + #:t #:nil + #:defpackage #:in-package #:*package* #:package-name #:find-package + #:eval-when + #:eval + #:lambda #:defun #:multiple-value-list #:defmacro + #:return-from + #:defvar #:defparameter + #:declare #:optimize #:type #:ignore + #:keyword #:integer + #:assert + #:member + #:macro-function + #:documentation + #:let #:let* #:progn #:multiple-value-bind + #:&rest #:&key + #:if #:when #:unless #:cond + #:loop #:dolist + #:car #:cdr #:cddr + #:write-sequence #:format + #:get-universal-time + #:get-decoded-time + #:string #:string-downcase #:make-string #:concatenate + #:symbolp + #:intern + #:setf #:getf + #:max #:min + #:eq + #:+ #:- #:> #:< #:<= #:>= + #:apply #:funcall + #:append #:list #:length + #:make-synonym-stream) + (:shadow #:error + #:warn + #:debug) + (:export #:config + #:*log-stream* + #:*log-hook* + #:*config* + #:*time-formatter* + #:*log-formatter* + + #:emerg + #:alert + #:crit + #:error + #:warn + #:notice + #:info + #:debug + #:debug1 + #:debug2 + #:debug3 + #:debug4)) +(in-package :vom) + +;; define our *levels* and *max-level-name-length* before the define-level macro +;; is defined (so it can access them) +(eval-when (:load-toplevel :compile-toplevel) + (defparameter *levels* '(:off 0) + "Holds the log level mappings (keyword -> value).") + + (defparameter *max-level-name-length* 0 + "Holds the number of characters in the longest log-level name.")) + +(defvar *config* '(t :warn) + "Holds the logging config as a plist. Holds package -> level mappings, using + T as the default (used if logging from a package that hasn't been + configured).") + +(defvar *log-stream* (make-synonym-stream 'cl:*standard-output*) + "Holds the default stream we're logging to.") + +(defvar *log-hook* + (lambda (log-level package-keyword package-log-level) + (declare (ignore log-level package-keyword package-log-level)) + *log-stream*) + "Holds a function that, given a log-level, a package name, and the effective + log-level for that package, returns one or more (via (values ...)) streams + that this log will be sent to.") + +(defvar *package-level-cache* nil + "A cache that holds package alias -> package loglevel values for quick lookup.") + +(defparameter *time-formatter* + (lambda () + (multiple-value-bind (second minute hour) + (get-decoded-time) + (format nil "~2,'0D:~2,'0D:~2,'0D" hour minute second))) + "A function of 0 args that returns the current time in the desired format.") + +(defparameter *log-formatter* + (lambda (format-str level-str package-keyword args) + (let* ((format-str (concatenate 'string "~a<~a> [~a] ~a - " format-str "~%"))) + (apply 'format + (append (list + nil + format-str) + (list + (make-string (- *max-level-name-length* (length level-str)) + :initial-element #\space) + level-str + (funcall *time-formatter*) + (string-downcase (string package-keyword))) + args)))) + "A function that takes a format string (user-supplied), a level string (eg + 'notice' or 'error'), a keyword of the current package, and a list of args + the user supplied with the format string and returns a string of the log line + we want logged.") + +(defun config (package-keyword level-name) + "Configure the log level for a package (or use t for the package name to set + the default log level). The log level is given as a keyword." + (assert (member level-name *levels*)) + (clear-level-cache) + (cond ((eq package-keyword t) + (setf (getf *config* t) level-name)) + ((symbolp package-keyword) + (let* ((name (find-package package-keyword)) + (package-name (string (if name + (package-name name) + package-keyword)))) + (setf (getf *config* (intern package-name :keyword)) level-name))))) + +(defun find-package-level (package-keyword) + "Given package keyword (doesn't have to be an exact match, can be an alias), + find the configured loglevel of that package. + + This caches the package->level connection in *package-level-cache*." + (declare (optimize (cl:speed 3) (cl:safety 0) (cl:debug 0)) + (type keyword package-keyword)) + (let ((cached (getf *package-level-cache* package-keyword))) + (when cached (return-from find-package-level cached)) + (let* ((package (find-package package-keyword)) + (package-name (when package + (intern (package-name package) :keyword))) + (package-level (getf *config* package-name)) + (package-level (if package-level + package-level + (getf *config* t))) + (package-level-value (getf *levels* package-level 0))) + (setf (getf *package-level-cache* package-keyword) package-level-value) + package-level-value))) + +(defun clear-level-cache () + "Clears the package loglevel cache." + (setf *package-level-cache* nil)) + +(defun do-log (level-name log-level package-keyword format-str &rest args) + "The given data to the current *log-stream* stream." + (declare (optimize (cl:speed 3) (cl:safety 0) (cl:debug 0)) + (type keyword level-name package-keyword) + (type integer log-level) + (type string format-str) + (type list args)) + (let* ((package-level-value (find-package-level package-keyword))) + (when (<= log-level package-level-value) + (let* ((level-str (string level-name)) + (logline (funcall *log-formatter* format-str level-str package-keyword args)) + (log-streams (multiple-value-list + (funcall *log-hook* + log-level + package-keyword + package-level-value)))) + (dolist (stream log-streams) + (write-sequence logline (if (eq stream t) + cl:*standard-output* + stream)) + (cl:finish-output stream)))))) + +(defmacro define-level (name level-value) + "Define a log level." + (let ((macro-name (intern (format nil "LOG-~a" (string name)))) + (log-sym (intern (string name)))) + `(progn + (setf (getf *levels* ,name) ,level-value) + (defmacro ,macro-name (format-str &rest args) + ,(format nil "Log output to the ~s log level (~a)" name level-value) + (let ((pkg (intern (package-name *package*) :keyword))) + `(do-log ,,name ,,level-value ,pkg ,format-str ,@args))) + (setf (documentation ',log-sym 'cl:function) (documentation ',macro-name 'cl:function)) + (setf (macro-function ',log-sym) (macro-function ',macro-name)) + (setf *max-level-name-length* (max *max-level-name-length* + (length (string ,name))))))) + +(define-level :emerg 1) +(define-level :alert 2) +(define-level :crit 3) +(define-level :error 4) +(define-level :warn 5) +(define-level :notice 6) +(define-level :info 7) +(define-level :debug 8) +(define-level :debug1 9) +(define-level :debug2 10) +(define-level :debug3 11) +(define-level :debug4 12) + diff --git a/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/.gitignore b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/.gitignore new file mode 100644 index 0000000..df0e0a3 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/.gitignore @@ -0,0 +1 @@ +*.*f*sl diff --git a/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/.pre-release.sh b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/.pre-release.sh new file mode 100644 index 0000000..32d1ce7 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/.pre-release.sh @@ -0,0 +1 @@ +sh render-doc.sh diff --git a/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/CHANGELOG b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/CHANGELOG new file mode 100644 index 0000000..157d6cf --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/CHANGELOG @@ -0,0 +1,28 @@ +Version 0.7.6 +2016-01-26 +Revert Rick's changes for alist/plist behavior (Hans Huebner) + +Version 0.7.5 +2015-06-14 +Fixed release script (Hans Huebner) + +Version 0.7.4 +2015-06-14 +Remove post-release.sh that updated c-l.net (Hans Huebner) + +Version 0.7.3 +2015-06-14 +Fix #28 Add ENCODE-OBJECT-SLOTS (Thayne McCombs) +Update html documentation (Hans Huebner) +update documentation link (Hans Huebner) +Documentation work (Hans Huebner) + +Version 0.7.2 +2014-12-05 +Avoid using e notation because Lisp, JS and JSON numeral syntaxes are incompatible. (Grim Schjetne) +readd encode-object/encode-slots API with proper documentation (Philipp Matthias Schaefer) + +Version 0.7.1 +2014-11-04 +Remove unused ENCODE-SLOTS and ENCODE-OBJECT stubs + diff --git a/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/LICENSE b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/LICENSE new file mode 100644 index 0000000..244beda --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2008-2019 Hans Huebner and contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + - Neither the name BKNR nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/README.md b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/README.md new file mode 100644 index 0000000..7d0a880 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/README.md @@ -0,0 +1,13 @@ +YASON +===== + +> YASON is a Common Lisp library for encoding and decoding data in the +> [JSON](https://raw.github.com/phmarek/clixdoc/master/clixdoc.xsl) +> interchange format. JSON is used as a lightweight alternative to +> XML. YASON has the sole purpose of encoding and decoding data and +> does not impose any object model on the Common Lisp application that +> uses it. + +Please proceed to the [Documentation](http://phmarek.github.io/yason) + +This project was maintained by https://github.com/hanshuebner/ until 2019. diff --git a/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/clixdoc.xsl b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/clixdoc.xsl new file mode 100644 index 0000000..308a20c --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/clixdoc.xsl @@ -0,0 +1,411 @@ + + + + + + + + + + + + + + + <xsl:value-of select="clix:title"/> + + + + + + + + + + +

+
+ + + +

+ + [Generic function] + [Method] + [Macro] + [Function] + +
+ + + + + + + + + => + + + +

+ +
+

+
+ + +

+ + [Generic reader] + [Specialized reader] + [Reader] + +
+ + + + + + + + + => + + + +

+ +
+

+
+ + +

+ + [Generic writer] + [Specialized writer] + [Writer] + +
+ + + + + (setf ( + + ) new-value) + + => + + + +

+ +
+

+
+ + +

+ + [Generic accessor] + [Specialized accessor] + [Accessor] + +
+ + + + + + + + => + +
+ (setf ( + + ) new-value) +
+

+ +
+

+
+ + +

+ [Special variable]
+ + + + + + +

+ +
+

+
+ + +

+ [Standard class]
+ + + + + + +

+ +
+

+
+ + +

+ [Condition type]
+ + + + + + +

+ +
+

+
+ + +

+ [Symbol]
+ + + + + + +

+ +
+

+
+ + +

+ [Constant]
+ + + + + + +

+ +
+

+
+ + + + + + +
+
+ + + +

+ [Constants]
+ +

+ +
+

+
+ + +

+ [Logical Pathname Host]
+ + + + + + +

+ +
+

+
+ + + + + + + + + & + + + + + + + + + + + + + + # + + + + + + + + + + + + + + + http://www.lispworks.com/documentation/HyperSpec/Body/ + + + + + +

+ + + + +

+ +
+ + +

+ + + + +

+ +
+ + +

Abstract

+
+ +
+
+ + +

Contents

+
    + +
  1. + + # + + + +
      + +
    1. + + # + + +
    2. +
      +
    +
    +
  2. +
    +
+
+ + +
    + + +
  • + + + +
  • +
    +
+
+ + + + + + + + +
diff --git a/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/doc.xml b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/doc.xml new file mode 100644 index 0000000..b426bb4 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/doc.xml @@ -0,0 +1,748 @@ + + + + + + YASON - A JSON encoder/decoder for Common Lisp + + + YASON is a JSON encoding and decoding library for Common Lisp. It + provides for functions to read JSON strings into Lisp data + structures and for serializing Lisp data structures as JSON + strings. + + + + YASON is a Common Lisp library for encoding and decoding data in + the JSON interchange format. JSON + is used as a lightweight alternative to XML. YASON has the sole + purpose of encoding and decoding data and does not impose any + object model on the Common Lisp application that uses it. + + + + + +

+ JSON is an established + alternative to XML as a data interchange format for web + applications. YASON implements reading and writing of JSON + formatted data in Common Lisp. It does not attempt to provide a + mapping between CLOS objects and YASON, but can be used to + implement such mappings. +

+

+ CL-JSON is + another Common Lisp package that can be used to work with JSON + encoded data. It takes a more integrated approach, providing + for library internal mappings between JSON objects and CLOS + objects. YASON was created as a lightweight, documented + alternative with a minimalistic approach and extensibilty. +

+
+ + +

+ YASON has its permanent home at GitHub. + It can be obtained by downloading the release + tarball. The current release is . +

+

+ You may also check out the current development version from its + git + repository. If you have suggestions regarding YASON, please + email me at hans.huebner@gmail.com. +

+

+ YASON is written in ANSI Common Lisp. It depends on UNIT-TEST, + TRIVIAL-GRAY-STREAMS and ALEXANDRIA open source libraries. The + recommended way to install YASON and its dependencies is through + the excellent Quicklisp + library management system. +

+

+ YASON lives in the :yason package and creates a package + nickname :json. Applications will not normally + :use this package, but rather use qualified names to + access YASON's symbols. For that reason, YASON's symbols do not + contain the string "JSON" themselves. See below for usage + samples. +

+
+ + + Versions of YASON preceding the v0.6.0 release provided a package + nickname "JSON" for the "YASON" package. This made it impossible + to load both YASON and CL-JSON into the same image, because + CL-JSON uses the "JSON" package name as well. + +

+ As CL-JSON's use of "JSON" as package name has a much longer + history and loading of both CL-JSON and YASON into the same + image has become more common, the "JSON" nickname was removed + from the YASON package with the v0.6.0 release. Users will need + to change their applications so that the "JSON" nickname is no + longer used to refer to the "YASON" package. It is understood + that this is a disruptive change, but as there is no + all-encompassing workaround, this step was felt to be the right + one to make +

+
+ + + By default, YASON performs the following mappings between JSON and + CL datatypes: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
JSON
datatype
CL
datatype
Notes
objecthash-table
:test #'equal
+ Keys are strings by default (see + *parse-object-key-fn*). Set + *parse-object-as* to :alist in + order to have YASON parse objects as alists or to + :plist to parse them as plists. When using plists, + you probably want to also set + *parse-object-key-fn* to a function + that interns the object's keys to symbols. +
arraylist + Can be changed to read to vectors (see + *parse-json-arrays-as-vectors*). +
stringstring + JSON escape characters are recognized upon reading. Upon + writing, known escape characters are used, but non-ASCII + Unicode characters are written as is. +
numbernumber + Parsed with READ, printed with PRINC. This is not a + faithful implementation of the specification. +
truet + Can be changed to read as TRUE (see + *parse-json-booleans-as-symbols*). +
falsenil + Can be changed to read as FALSE (see + *parse-json-booleans-as-symbols*). +
nullnil
+
+ + +

+ JSON data is always completely parsed into an equivalent + in-memory representation. Upon reading, some translations are + performed by default to make it easier for the Common Lisp + program to work with the data; see mapping + for details. If desired, the parser can be configured to + preserve the full semantics of the JSON data read. +

+ + For example + +
CL-USER> (defvar *json-string* "[{\"foo\":1,\"bar\":[7,8,9]},2,3,4,[5,6,7],true,null]")
+*JSON-STRING*
+CL-USER> (let* ((result (yason:parse *json-string*)))
+           (print result)
+           (alexandria:hash-table-plist (first result)))
+
+(#<HASH-TABLE :TEST EQUAL :COUNT 2 {5A4420F1}> 2 3 4 (5 6 7) T NIL)
+("bar" (7 8 9) "foo" 1)
+CL-USER> (defun maybe-convert-to-keyword (js-name)
+           (or (find-symbol (string-upcase js-name) :keyword)
+               js-name))
+MAYBE-CONVERT-TO-KEYWORD
+CL-USER> :FOO ; intern the :FOO keyword
+:FOO
+CL-USER> (let* ((yason:*parse-json-arrays-as-vectors* t)
+                (yason:*parse-json-booleans-as-symbols* t)
+                (yason:*parse-object-key-fn* #'maybe-convert-to-keyword)
+                (result (yason:parse *json-string*)))
+           (print result)
+           (alexandria:hash-table-plist (aref result 0)))
+
+#(#<HASH-TABLE :TEST EQUAL :COUNT 2 {59B4EAD1}> 2 3 4 #(5 6 7) YASON:TRUE NIL)
+("bar" #(7 8 9) :FOO 1)
+ +

+ The second example modifies the parser's behaviour so that JSON + arrays are read as CL vectors, JSON booleans will be read as the + symbols TRUE and FALSE and JSON object keys will be looked up in + the :keyword package. Interning strings coming from an + external source is not recommended practice. +

+ + + + input &key (object-key-fn + *parse-object-as-key-fn*) (object-as *parse-object-as*) + (json-arrays-as-vectors *parse-json-arrays-as-vectors*) + (json-booleans-as-symbols *parse-json-booleans-as-symbols*) + (json-nulls-as-keyword *parse-json-null-as-keyword*) + object + + Parse input, which must be a string or + a stream, as JSON. Returns the Lisp representation of the + JSON structure parsed. +

+ The keyword arguments object-key-fn, + object-as, + json-arrays-as-vectors, + json-booleans-as-symbols, and + json-null-as-keyword may be used + to specify different values for the parsing parameters + from the current bindings of the respective special + variables. +

+
+
+ + + + If set to a true value, JSON arrays will be parsed as + vectors, not as lists. NIL is the default. + + + + + + Can be set to :hash-table to parse objects as hash + tables, :alist to parse them as alists or + :plist to parse them as plists. :hash-table + is the default. + + + + + + If set to a true value, JSON booleans will be read as the + symbols TRUE and FALSE instead of T and NIL, respectively. + NIL is the default. + + + + + + If set to a true value, JSON null will be read as the + keyword :NULL, instead of NIL. + NIL is the default. + + + + + + Function to call to convert a key string in a JSON object to + a key in the CL hash produced. IDENTITY is the default. + + + +
+
+ + + YASON provides two distinct modes to encode JSON data: + applications can either create an in-memory representation of the + data to be serialized, then have YASON convert it to JSON in one + go, or they can use a set of macros to serialze the JSON data + element-by-element, allowing fine-grained control over the layout + of the generated data. + +

+ Optionally, the JSON that is produced can be indented. + Indentation requires the use of a + JSON-OUTPUT-STREAM as serialization target. + With the stream serializer, such a stream is automatically used. + If indentation is desired with the DOM serializer, such a stream + can be obtained by calling the + MAKE-JSON-OUTPUT-STREAM function with the + target output string as argument. Please be aware that indented + output not requires more space, but is also slower and should + not be enabled in performance critical applications. +

+ + +

+ In this mode, an in-memory structure is encoded in JSON + format. The structure must consist of objects that are + serializable using the ENCODE function. + YASON defines a number of encoders for standard data types + (see MAPPING), but the application can + define additional methods (e.g. for encoding CLOS objects). +

+ For example: +
CL-USER> (yason:encode
+          (list (alexandria:plist-hash-table
+                 '("foo" 1 "bar" (7 8 9))
+                 :test #'equal)
+                2 3 4
+                '(5 6 7)
+                t nil)
+          *standard-output*)
+[{"foo":1,"bar":[7,8,9]},2,3,4,[5,6,7],true,null]
+(#<HASH-TABLE :TEST EQUAL :COUNT 2 {59942D21}> 2 3 4 (5 6 7) T NIL)
+ + + + object &optional + stream + object + + Encode object in JSON format and + write to stream. May be specialized + by applications to perform specific rendering. Stream + defaults to *STANDARD-OUTPUT*. + + + + + object &optional (stream + *standard-output*) + object + + Encodes object, an alist, in JSON + format and write to stream. + + + + + object &optional (stream + *standard-output*) + object + + Encodes object, a plist, in JSON + format and write to stream. + + + + + stream &key (indent t) + stream + + Creates a json-output-stream instance + that wraps the supplied stream and + optionally performs indentation of the generated JSON + data. The indent argument is + described in WITH-OUTPUT. Note that + if the indent argument is NIL, the + original stream is returned in order to avoid the + performance penalty of the indentation algorithm. + + + + + + Function to call to translate a CL list into JSON data. + 'YASON:ENCODE-PLAIN-LIST-TO-ARRAY is the default; + 'YASON:ENCODE-PLIST and + 'YASON:ENCODE-ALIST are available to produce + JSON objects. +

+ This is useful to translate a deeply recursive structure in a single + YASON:ENCODE call. +

+
+
+ + + + + Defines the policy to encode symbols as keys (eg. in hash tables). + The default is to error out, to provide backwards-compatible behaviour. +

+ A useful function that can be bound to this variable is + YASON:ENCODE-SYMBOL-AS-LOWERCASE. +

+
+
+
+
+ + +

+ In this mode, the JSON structure is generated in a stream. + The application makes explicit calls to the encoding library + in order to generate the JSON structure. It provides for more + control over the generated output, and can be used to generate + arbitary JSON without requiring that there exists a directly + matching Lisp data structure. The streaming API uses the + encode function, so it is possible to + intermix the two (see app-encoders for an + example). +

+ For example: +
CL-USER> (yason:with-output (*standard-output*)
+           (yason:with-array ()
+             (dotimes (i 3)
+               (yason:encode-array-element i))))
+[0,1,2]
+NIL
+CL-USER> (yason:with-output (*standard-output*)
+           (yason:with-object ()
+             (yason:encode-object-element "hello" "hu hu")
+             (yason:with-object-element ("harr")
+               (yason:with-array ()
+                 (dotimes (i 3)
+                   (yason:encode-array-element i))))))
+{"hello":"hu hu","harr":[0,1,2]}
+NIL
+ + + + (stream &key indent) &body body + result* + + Set up a JSON streaming encoder context on + stream, then evaluate + body. indent + can be set to T to enable indentation with a default + indentation width or to an integer specifying the desired + indentation width. By default, indentation is switched + off. + + + + + (&key indent stream-symbol) &body body + result* + + Set up a JSON streaming encoder context on + stream-symbol (by default + a gensym), then evaluate + body. Return a string with the + generated JSON output. See + WITH-OUTPUT for the description of + the indent keyword argument. + + + + + + This condition is signalled when one of the stream + encoding functions is used outside the dynamic context of + a WITH-OUTPUT or + WITH-OUTPUT-TO-STRING* body. + + + + + () &body body + result* + + Open a JSON array, then run body. + Inside the body, ENCODE-ARRAY-ELEMENT + must be called to encode elements to the opened array. + Must be called within an existing JSON encoder context + (see WITH-OUTPUT and + WITH-OUTPUT-TO-STRING*). + + + + + object + object + + Encode object as next array element to + the last JSON array opened + with WITH-ARRAY in the dynamic + context. object is encoded using the + ENCODE generic function, so it must be of + a type for which an ENCODE method is + defined. + + + + + &rest objects + result* + + Encode objects, a series of JSON + encodable objects, as the next array elements in a JSON + array opened with + WITH-ARRAY. ENCODE-ARRAY-ELEMENTS + uses ENCODE-ARRAY-ELEMENT, which must + be applicable to each object in the list + (i.e. ENCODE must be defined for each + object type). Additionally, this must be called within a + valid stream context. + + + + + () &body body + result* + + Open a JSON object, then run body. + Inside the body, + ENCODE-OBJECT-ELEMENT or + WITH-OBJECT-ELEMENT must be called to + encode elements to the object. Must be called within an + existing JSON encoder + WITH-OUTPUT and + WITH-OUTPUT-TO-STRING*. + + + + + (key) &body body + result* + + Open a new encoding context to encode a JSON object + element. key is the key of the + element. The value will be whatever + body serializes to the current JSON + output context using one of the stream encoding functions. + This can be used to stream out nested object structures. + + + + + key value + value + + Encode key and + value as object element to the last + JSON object opened with WITH-OBJECT + in the dynamic context. key and + value are encoded using the + ENCODE generic function, so they both + must be of a type for which an ENCODE + method is defined. + + + + + &rest elements + result* + + Encodes the parameters into JSON in the last object opened + with WITH-OBJECT using + ENCODE-OBJECT-ELEMENT. The parameters + should consist of alternating key/value pairs, and this + must be called within a valid stream context. + + + + + object slots + result* + + Encodes each slot in SLOTS for OBJECT in the last object + opened with WITH-OBJECT using + ENCODE-OBJECT-ELEMENT. The key is the + slot name, and the value is the slot value for the slot on + OBJECT. It is equivalent to +
(loop for slot in slots
+    do (encode-object-element (string slot)
+                              (slot-value object slot)))
+			
+
+
+ + + object + result* + + Generic function to encode object slots. There is no default + implementation. + It should be called in an object encoding context. It uses + PROGN combinatation with MOST-SPECIFIC-LAST order, so that + base class slots are encoded before derived class slots. + + + + + object + result* + + Generic function to encode an object. The default implementation + opens a new object encoding context and calls + ENCODE-SLOTS on the argument. + + + + + + Instances of this class are used to wrap an output stream + that is used as a serialization target in the stream + encoder and optionally in the DOM encoder if indentation + is desired. The class name is not exported, use + make-json-output-stream to create a + wrapper stream if required. + + +
+
+ + + + Suppose your application uses structs to represent its data and + you want to encode these structs using JSON in order to send + them to a client application. Suppose further that your structs + also include internal information that you do not want to send. + Here is some code that illustrates how one could implement a + serialization function: + +
CL-USER> (defstruct user name age password)
+USER
+CL-USER> (defmethod yason:encode ((user user) &optional (stream *standard-output*))
+           (yason:with-output (stream)
+             (yason:with-object ()
+               (yason:encode-object-element "name" (user-name user))
+               (yason:encode-object-element "age" (user-age user)))))
+#<STANDARD-METHOD YASON:ENCODE (USER) {5B40A591}>
+CL-USER> (yason:encode (list (make-user :name "horst" :age 27 :password "puppy")
+                            (make-user :name "uschi" :age 28 :password "kitten")))
+[{"name":"horst","age":27},{"name":"uschi","age":28}]
+(#S(USER :NAME "horst" :AGE 27 :PASSWORD "puppy")
+ #S(USER :NAME "uschi" :AGE 28 :PASSWORD "kitten"))
+ + As you can see, the streaming API and the DOM encoder can be + used together. ENCODE invokes itself + recursively, so any application defined method will be called + while encoding in-memory objects as appropriate. + +

For an example of the interplay between + ENCODE-OBJECT and + ENCODE-SLOTS, suppose you have the following + CLOS class heirarchy: + +

(defclass shape ()
+  ((color :reader color)))
+
+(defclass square (shape)
+  ((side-length :reader side-length)))
+
+(defclass circle (shape)
+  ((radius :reader radius)))
+ + In order to implement encoding of circles and squares without + duplicating code you can specialize + ENCODE-SLOTS for all three classes + +
(defmethod yason:encode-slots progn ((shape shape))
+  (yason:encode-object-element "color" (color shape)))
+
+(defmethod yason:encode-slots progn ((square square))
+  (yason:encode-object-element "side-length" (side-length square)))
+
+(defmethod yason:encode-slots progn ((circle circle))
+  (yason:encode-object-element "radius" (radius circle)))
+ + and then use ENCODE-OBJECT: + +
CL-USER> (yason:with-output-to-string* ()
+           (yason:encode-object (make-instance 'square :color "red" :side-length 3)))
+"{\"color\":\"red\",\"side-length\":3}"
+CL-USER> (yason:with-output-to-string* ()
+           (yason:encode-object (make-instance 'circle :color "blue" :side-length 5)))
+"{\"color\":\"blue\",\"radius\":5}"
+

+

Alternatively, you can use the shortcut ENCODE-OBJECT-SLOTS + if you want the keys to be the slot names. For example: +

(defclass person ()
+  ((name :reader name :initarg :name)
+   (address :reader address :initarg :address)
+   (phone-number :reader phone-number :initarg :phone)
+   (favorite-color :reader favorite-color :initarg :color)))
+
+(defmethod yason:encode-slots progn ((person person))
+  (yason:encode-object-slots person '(name address phone-number favorite-color)))
+ and then: + +
CL-USER> (yason:with-output-to-string* ()
+       (yason:encode-object (make-instance 'person :name "John Doe"
+                                                   :address "123 Main St."
+                                                   :phone "(123)-456-7890"
+                                                   :color "blue")))
+"{\"NAME\":\"John Doe\",\"ADDRESS\":\"123 Main St.\",\"PHONE-NUMBER\":\"(123)-456-7890\",
+\"FAVORITE-COLOR\":\"blue\"}"
+

+
+
+ + + + + + +
Copyright (c) 2008-2014 Hans Hübner and contributors
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+  - Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+  - Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+
+  - Neither the name BKNR nor the names of its contributors may be
+    used to endorse or promote products derived from this software
+    without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+ + + Thanks go to Edi Weitz for being a great inspiration. This + documentation as been generated with a hacked-up version of his DOCUMENTATION-TEMPLATE + software. Thanks to David Lichteblau for coining YASON's name. + + +
diff --git a/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/encode.lisp b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/encode.lisp new file mode 100644 index 0000000..6c7f902 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/encode.lisp @@ -0,0 +1,388 @@ +;; This file is part of yason, a Common Lisp JSON parser/encoder +;; +;; Copyright (c) 2008-2014 Hans Huebner and contributors +;; All rights reserved. +;; +;; Please see the file LICENSE in the distribution. + +(in-package :yason) + +(defvar *json-output*) + +(defparameter *default-indent* nil + "Set to T or an numeric indentation width in order to have YASON + indent its output by default.") + +(defparameter *default-indent-width* 2 + "Default indentation width for output if indentation is selected + with no indentation width specified.") + +(defparameter *list-encoder* 'encode-plain-list-to-array + "The actual function used to encode a LIST. + Can be changed to encode ALISTs or PLISTs as dictionaries by + setting it to ENCODE-ALIST or ENCODE-PLIST.") + +(defparameter *symbol-key-encoder* 'encode-symbol-key-error + "The actual function used to encode a SYMBOL when seen as a key. + You might want ENCODE-SYMBOL-AS-LOWERCASE here.") + + +(defgeneric encode (object &optional stream) + + (:documentation "Encode OBJECT to STREAM in JSON format. May be + specialized by applications to perform specific rendering. STREAM + defaults to *STANDARD-OUTPUT*.")) + +(defparameter *char-replacements* + (alexandria:plist-hash-table + '(#\\ "\\\\" + #\" "\\\"" + #\Backspace "\\b" + #\Page "\\f" + #\Newline "\\n" + #\Return "\\r" + #\Tab "\\t"))) + +(defun unicode-code (char) + (char-code char)) + +(defun unicode-char (code) + (code-char code)) + +(defun write-surrogate-pair-escape (code stream) + (let ((upper (+ (ldb (byte 10 10) (- code #x10000)) + #xD800)) + (lower (+ (ldb (byte 10 0) (- code #x10000)) + #xDC00))) + (format stream "\\u~4,'0X\\u~4,'0X" upper lower))) + +(defmethod encode ((string string) &optional (stream *standard-output*)) + (write-char #\" stream) + (dotimes (i (length string)) + (let* ((char (aref string i)) + (replacement (gethash char *char-replacements*))) + (cond + (replacement (write-string replacement stream)) + ;; Control characters (U+0000 - U+001F) must be escaped. + ((<= #x0000 (unicode-code char) #x001F) + (format stream "\\u~4,'0X" (unicode-code char))) + ;; Non-BMP characters must be escaped as a UTF-16 surrogate pair. + ((<= #x010000 (unicode-code char) #x10FFFF) + (write-surrogate-pair-escape (unicode-code char) stream)) + (t (write-char char stream))))) + (write-char #\" stream) + string) + +(defmethod encode ((object ratio) &optional (stream *standard-output*)) + (encode (coerce object 'double-float) stream) + object) + +(defmethod encode ((object float) &optional (stream *standard-output*)) + (let ((*read-default-float-format* 'double-float)) + (format stream "~F" (coerce object 'double-float))) + object) + +(defmethod encode ((object integer) &optional (stream *standard-output*)) + (princ object stream)) + +(defmacro with-aggregate/object ((stream opening-char closing-char) &body body) + "Set up serialization context for aggregate serialization with the + object encoder." + (alexandria:with-gensyms (printed) + `(progn + (write-delimiter ,opening-char ,stream) + (change-indentation ,stream #'+) + (prog1 + (let (,printed) + (macrolet ((with-element-output (() &body body) + `(progn + (cond + (,',printed + (write-delimiter #\, ,',stream)) + (t + (setf ,',printed t))) + (write-indentation ,',stream) + ,@body))) + ,@body)) + (change-indentation ,stream #'-) + (write-indentation ,stream) + (write-delimiter ,closing-char ,stream))))) + +(defun encode-key/value (key value stream) + (encode key stream) + (write-char #\: stream) + (encode value stream)) + +(defmethod encode ((object hash-table) &optional (stream *standard-output*)) + (with-aggregate/object (stream #\{ #\}) + (maphash (lambda (key value) + (with-element-output () + (encode-key/value key value stream))) + object) + object)) + +(defmethod encode ((object vector) &optional (stream *standard-output*)) + (with-aggregate/object (stream #\[ #\]) + (loop for value across object + do (with-element-output () + (encode value stream))) + object)) + +(defun encode-plain-list-to-array (object stream) + (with-aggregate/object (stream #\[ #\]) + (dolist (value object) + (with-element-output () + (encode value stream))) + object)) + +(defmethod encode ((object list) &optional (stream *standard-output*)) + (funcall *list-encoder* object stream)) + + +(defun encode-symbol-key-error (key) + (error "No policy for symbols as keys defined. ~ + Please check YASON:*SYMBOL-KEY-ENCODER*.")) + +(defun encode-symbol-as-lowercase (key) + "Encodes a symbol KEY as a lowercase string. + Ensure that there's no intentional lower-case character lost." + (let ((name (symbol-name key))) + (assert (notany #'lower-case-p name)) + (string-downcase name))) + +(defun encode-assoc-key/value (key value stream) + ;; Checking (EVERY #'UPPER-CASE-P name) breaks with non-alpha characters like #\- + (let ((string (if (symbolp key) + (funcall *symbol-key-encoder* key) + (string key)))) + (encode-key/value string value stream))) + +(defun encode-alist (object &optional (stream *standard-output*)) + ;; Failsafe in case this here is not an ALIST but a normal list + (if (consp (first object)) + (with-aggregate/object (stream #\{ #\}) + (loop for (key . value) in object + do (with-element-output () + (encode-assoc-key/value key value stream))) + object) + ;; We can't call *LIST-ENCODER* again, that would be an unlimited recursion + (encode-plain-list-to-array object stream))) + +(defun encode-plist (object &optional (stream *standard-output*)) + (with-aggregate/object (stream #\{ #\}) + (loop for (key value) on object by #'cddr + do (with-element-output () + (encode-assoc-key/value key value stream))) + object)) + +(defmethod encode ((object (eql 'true)) &optional (stream *standard-output*)) + (write-string "true" stream) + object) + +(defmethod encode ((object (eql 'false)) &optional (stream *standard-output*)) + (write-string "false" stream) + object) + +(defmethod encode ((object (eql :null)) &optional (stream *standard-output*)) + (write-string "null" stream) + object) + +(defmethod encode ((object (eql t)) &optional (stream *standard-output*)) + (write-string "true" stream) + object) + +(defmethod encode ((object (eql nil)) &optional (stream *standard-output*)) + (write-string "null" stream) + object) + +(defclass json-output-stream (trivial-gray-streams:fundamental-character-output-stream) + ((output-stream :reader output-stream + :initarg :output-stream) + (stack :accessor stack + :initform nil) + (indent :initarg :indent + :reader indent + :accessor indent%) + (indent-string :initform "" + :accessor indent-string)) + (:default-initargs :indent *default-indent*) + (:documentation "Objects of this class capture the state of a JSON stream encoder.")) + +(defmethod initialize-instance :after ((stream json-output-stream) &key indent) + (when (eq indent t) + (setf (indent% stream) *default-indent-width*))) + +(defgeneric make-json-output-stream (stream &key indent)) + +(defmethod make-json-output-stream (stream &key (indent t)) + "Create a JSON output stream with indentation enabled." + (if indent + (make-instance 'json-output-stream :output-stream stream :indent indent) + stream)) + +(defmethod trivial-gray-streams:stream-write-char ((stream json-output-stream) char) + (write-char char (output-stream stream))) + +(defgeneric write-indentation (stream) + (:method ((stream t)) + nil) + (:method ((stream json-output-stream)) + (when (indent stream) + (fresh-line (output-stream stream)) + (write-string (indent-string stream) (output-stream stream))))) + +(defgeneric write-delimiter (char stream) + (:method (char stream) + (write-char char stream)) + (:method (char (stream json-output-stream)) + (write-char char (output-stream stream)))) + +(defgeneric change-indentation (stream operator) + (:method ((stream t) (operator t)) + nil) + (:method ((stream json-output-stream) operator) + (when (indent stream) + (setf (indent-string stream) (make-string (funcall operator (length (indent-string stream)) + (indent stream)) + :initial-element #\Space))))) + +(defun next-aggregate-element () + (if (car (stack *json-output*)) + (write-char (car (stack *json-output*)) (output-stream *json-output*)) + (setf (car (stack *json-output*)) #\,))) + +(defmacro with-output ((stream &rest args &key indent) &body body) + (declare (ignore indent)) + "Set up a JSON streaming encoder context on STREAM, then evaluate BODY." + `(let ((*json-output* (make-instance 'json-output-stream :output-stream ,stream ,@args))) + ,@body)) + +(defmacro with-output-to-string* ((&rest args &key indent stream-symbol) &body body) + "Set up a JSON streaming encoder context, then evaluate BODY. + Return a string with the generated JSON output." + (declare (ignore indent)) + (let ((stream (or stream-symbol (gensym "STREAM")))) + (remf args :stream-symbol) + `(with-output-to-string (,stream) + (with-output (,stream ,@args) + ,@body)))) + +(define-condition no-json-output-context (error) + () + (:report "No JSON output context is active") + (:documentation "This condition is signalled when one of the stream + encoding function is used outside the dynamic context of a + WITH-OUTPUT or WITH-OUTPUT-TO-STRING* body.")) + +(defmacro with-aggregate/stream ((begin-char end-char) &body body) + "Set up context for aggregate serialization for the stream encoder." + `(progn + (unless (boundp '*json-output*) + (error 'no-json-output-context)) + (when (stack *json-output*) + (next-aggregate-element)) + (write-indentation *json-output*) + (write-delimiter ,begin-char *json-output*) + (change-indentation *json-output* #'+) + (push nil (stack *json-output*)) + (prog1 + (progn ,@body) + (pop (stack *json-output*)) + (change-indentation *json-output* #'-) + (write-indentation *json-output*) + (write-delimiter ,end-char *json-output*)))) + +(defmacro with-array (() &body body) + "Open a JSON array, then run BODY. Inside the body, +ENCODE-ARRAY-ELEMENT must be called to encode elements to the opened +array. Must be called within an existing JSON encoder context, see +WITH-OUTPUT and WITH-OUTPUT-TO-STRING*." + `(with-aggregate/stream (#\[ #\]) ,@body)) + +(defmacro with-object (() &body body) + "Open a JSON object, then run BODY. Inside the body, +ENCODE-OBJECT-ELEMENT or WITH-OBJECT-ELEMENT must be called to encode +elements to the object. Must be called within an existing JSON +encoder context, see WITH-OUTPUT and WITH-OUTPUT-TO-STRING*." + `(with-aggregate/stream (#\{ #\}) ,@body)) + +(defun encode-array-element (object) + "Encode OBJECT as next array element to the last JSON array opened +with WITH-ARRAY in the dynamic context. OBJECT is encoded using the +ENCODE generic function, so it must be of a type for which an ENCODE +method is defined." + (next-aggregate-element) + (write-indentation *json-output*) + (encode object (output-stream *json-output*))) + +(defun encode-array-elements (&rest objects) + "Encode OBJECTS, a list of JSON encodable objects, as array elements." + (dolist (object objects) + (encode-array-element object))) + +(defun encode-object-element (key value) + "Encode KEY and VALUE as object element to the last JSON object +opened with WITH-OBJECT in the dynamic context. KEY and VALUE are +encoded using the ENCODE generic function, so they both must be of a +type for which an ENCODE method is defined." + (next-aggregate-element) + (write-indentation *json-output*) + (encode-key/value key value (output-stream *json-output*)) + value) + +(defun encode-object-elements (&rest elements) + "Encode plist ELEMENTS as object elements." + (loop for (key value) on elements by #'cddr + do (encode-object-element key value))) + +(defun encode-object-slots (object slots) + "For each slot in SLOTS, encode that slot on OBJECT as an object element. +Equivalent to calling ENCODE-OBJECT-ELEMENT for each slot where the +key is the slot name, and the value is the (SLOT-VALUE OBJECT slot)" + (loop for slot in slots + do (encode-object-element (string slot) + (slot-value object slot)))) + +(define-compiler-macro encode-object-slots (&whole form &environment env object raw-slots) + "Compiler macro to allow open-coding with encode-object-slots when slots are literal list." + (let ((slots (macroexpand raw-slots env))) + (cond + ((null slots) nil) + ((eq (car slots) 'quote) + (setf slots (cadr slots)) ; Get the quoted list + `(with-slots ,slots ,object + ,@(loop for slot in slots + collect `(encode-object-element ,(string slot) ,slot)))) + (t form)))) + +(defmacro with-object-element ((key) &body body) + "Open a new encoding context to encode a JSON object element. KEY + is the key of the element. The value will be whatever BODY + serializes to the current JSON output context using one of the + stream encoding functions. This can be used to stream out nested + object structures." + `(progn + (next-aggregate-element) + (write-indentation *json-output*) + (encode ,key (output-stream *json-output*)) + (setf (car (stack *json-output*)) #\:) + (unwind-protect + (progn ,@body) + (setf (car (stack *json-output*)) #\,)))) + +(defgeneric encode-slots (object) + (:documentation + "Generic function to encode object slots. It should be called in an + object encoding context. It uses PROGN combinatation with + MOST-SPECIFIC-LAST order, so that base class slots are encoded + before derived class slots.") + (:method-combination progn :most-specific-last)) + +(defgeneric encode-object (object) + (:documentation + "Generic function to encode an object. The default implementation + opens a new object encoding context and calls ENCODE-SLOTS on + the argument.") + (:method (object) + (with-object () + (yason:encode-slots object)))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/index.html b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/index.html new file mode 100644 index 0000000..9f09709 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/index.html @@ -0,0 +1,764 @@ + +YASON - A JSON encoder/decoder for Common Lisp + +

YASON - A JSON encoder/decoder for Common Lisp

+ + + +

Abstract

+
+ YASON is a Common Lisp library for encoding and decoding data in + the JSON interchange format. JSON + is used as a lightweight alternative to XML. YASON has the sole + purpose of encoding and decoding data and does not impose any + object model on the Common Lisp application that uses it. +
+ +

Contents

+
    +
  1. Introduction
  2. +
  3. Download and Installation
  4. +
  5. Using JSON as package name
  6. +
  7. Mapping between JSON and CL datatypes
  8. +
  9. +Parsing JSON data
    1. Parser dictionary
    +
  10. +
  11. +Encoding JSON data
      +
    1. Encoding a JSON DOM
    2. +
    3. Encoding JSON in streaming mode
    4. +
    5. Application specific encoders
    6. +
    +
  12. +
  13. Symbol index
  14. +
  15. License
  16. +
  17. Acknowledgements
  18. +
+ +

Introduction

+

+ JSON is an established + alternative to XML as a data interchange format for web + applications. YASON implements reading and writing of JSON + formatted data in Common Lisp. It does not attempt to provide a + mapping between CLOS objects and YASON, but can be used to + implement such mappings. +

+

+ CL-JSON is + another Common Lisp package that can be used to work with JSON + encoded data. It takes a more integrated approach, providing + for library internal mappings between JSON objects and CLOS + objects. YASON was created as a lightweight, documented + alternative with a minimalistic approach and extensibilty. +

+ + +

Download and Installation

+

+ YASON has its permanent home at GitHub. + It can be obtained by downloading the release + tarball. The current release is 0.7.6. +

+

+ You may also check out the current development version from its + git + repository. If you have suggestions regarding YASON, please + email me at hans.huebner@gmail.com. +

+

+ YASON is written in ANSI Common Lisp. It depends on UNIT-TEST, + TRIVIAL-GRAY-STREAMS and ALEXANDRIA open source libraries. The + recommended way to install YASON and its dependencies is through + the excellent Quicklisp + library management system. +

+

+ YASON lives in the :yason package and creates a package + nickname :json. Applications will not normally + :use this package, but rather use qualified names to + access YASON's symbols. For that reason, YASON's symbols do not + contain the string "JSON" themselves. See below for usage + samples. +

+ + +

Using JSON as package name

+ Versions of YASON preceding the v0.6.0 release provided a package + nickname "JSON" for the "YASON" package. This made it impossible + to load both YASON and CL-JSON into the same image, because + CL-JSON uses the "JSON" package name as well. + +

+ As CL-JSON's use of "JSON" as package name has a much longer + history and loading of both CL-JSON and YASON into the same + image has become more common, the "JSON" nickname was removed + from the YASON package with the v0.6.0 release. Users will need + to change their applications so that the "JSON" nickname is no + longer used to refer to the "YASON" package. It is understood + that this is a disruptive change, but as there is no + all-encompassing workaround, this step was felt to be the right + one to make +

+ + +

Mapping between JSON and CL datatypes

+ By default, YASON performs the following mappings between JSON and + CL datatypes: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
JSON

datatype
CL

datatype
Notes
objecthash-table

:test #'equal
+ Keys are strings by default (see + *parse-object-key-fn*). Set + *parse-object-as* to :alist in + order to have YASON parse objects as alists or to + :plist to parse them as plists. When using plists, + you probably want to also set + *parse-object-key-fn* to a function + that interns the object's keys to symbols. +
arraylist + Can be changed to read to vectors (see + *parse-json-arrays-as-vectors*). +
stringstring + JSON escape characters are recognized upon reading. Upon + writing, known escape characters are used, but non-ASCII + Unicode characters are written as is. +
numbernumber + Parsed with READ, printed with PRINC. This is not a + faithful implementation of the specification. +
truet + Can be changed to read as TRUE (see + *parse-json-booleans-as-symbols*). +
falsenil + Can be changed to read as FALSE (see + *parse-json-booleans-as-symbols*). +
nullnil
+ + +

Parsing JSON data

+

+ JSON data is always completely parsed into an equivalent + in-memory representation. Upon reading, some translations are + performed by default to make it easier for the Common Lisp + program to work with the data; see mapping + for details. If desired, the parser can be configured to + preserve the full semantics of the JSON data read. +

+ + For example + +
CL-USER> (defvar *json-string* "[{\"foo\":1,\"bar\":[7,8,9]},2,3,4,[5,6,7],true,null]")
+*JSON-STRING*
+CL-USER> (let* ((result (yason:parse *json-string*)))
+           (print result)
+           (alexandria:hash-table-plist (first result)))
+
+(#<HASH-TABLE :TEST EQUAL :COUNT 2 {5A4420F1}> 2 3 4 (5 6 7) T NIL)
+("bar" (7 8 9) "foo" 1)
+CL-USER> (defun maybe-convert-to-keyword (js-name)
+           (or (find-symbol (string-upcase js-name) :keyword)
+               js-name))
+MAYBE-CONVERT-TO-KEYWORD
+CL-USER> :FOO ; intern the :FOO keyword
+:FOO
+CL-USER> (let* ((yason:*parse-json-arrays-as-vectors* t)
+                (yason:*parse-json-booleans-as-symbols* t)
+                (yason:*parse-object-key-fn* #'maybe-convert-to-keyword)
+                (result (yason:parse *json-string*)))
+           (print result)
+           (alexandria:hash-table-plist (aref result 0)))
+
+#(#<HASH-TABLE :TEST EQUAL :COUNT 2 {59B4EAD1}> 2 3 4 #(5 6 7) YASON:TRUE NIL)
+("bar" #(7 8 9) :FOO 1)
+ +

+ The second example modifies the parser's behaviour so that JSON + arrays are read as CL vectors, JSON booleans will be read as the + symbols TRUE and FALSE and JSON object keys will be looked up in + the :keyword package. Interning strings coming from an + external source is not recommended practice. +

+ +

Parser dictionary

+

[Function]
parse input &key (object-key-fn + *parse-object-as-key-fn*) (object-as *parse-object-as*) + (json-arrays-as-vectors *parse-json-arrays-as-vectors*) + (json-booleans-as-symbols *parse-json-booleans-as-symbols*) + (json-nulls-as-keyword *parse-json-null-as-keyword*) + => + object

+ Parse input, which must be a string or + a stream, as JSON. Returns the Lisp representation of the + JSON structure parsed. +

+ The keyword arguments object-key-fn, + object-as, + json-arrays-as-vectors, + json-booleans-as-symbols, and + json-null-as-keyword may be used + to specify different values for the parsing parameters + from the current bindings of the respective special + variables. +

+

+ +

+ [Special variable]
*parse-json-arrays-as-vectors*

+ If set to a true value, JSON arrays will be parsed as + vectors, not as lists. NIL is the default. +

+ +

+ [Special variable]
*parse-object-as*

+ Can be set to :hash-table to parse objects as hash + tables, :alist to parse them as alists or + :plist to parse them as plists. :hash-table + is the default. +

+ +

+ [Special variable]
*parse-json-booleans-as-symbols*

+ If set to a true value, JSON booleans will be read as the + symbols TRUE and FALSE instead of T and NIL, respectively. + NIL is the default. +

+ +

+ [Special variable]
*parse-json-null-as-keyword*

+ If set to a true value, JSON null will be read as the + keyword :NULL, instead of NIL. + NIL is the default. +

+ +

+ [Special variable]
*parse-object-key-fn*

+ Function to call to convert a key string in a JSON object to + a key in the CL hash produced. IDENTITY is the default. +

+ + + + +

Encoding JSON data

+ YASON provides two distinct modes to encode JSON data: + applications can either create an in-memory representation of the + data to be serialized, then have YASON convert it to JSON in one + go, or they can use a set of macros to serialze the JSON data + element-by-element, allowing fine-grained control over the layout + of the generated data. + +

+ Optionally, the JSON that is produced can be indented. + Indentation requires the use of a + JSON-OUTPUT-STREAM as serialization target. + With the stream serializer, such a stream is automatically used. + If indentation is desired with the DOM serializer, such a stream + can be obtained by calling the + MAKE-JSON-OUTPUT-STREAM function with the + target output string as argument. Please be aware that indented + output not requires more space, but is also slower and should + not be enabled in performance critical applications. +

+ +

Encoding a JSON DOM

+

+ In this mode, an in-memory structure is encoded in JSON + format. The structure must consist of objects that are + serializable using the ENCODE function. + YASON defines a number of encoders for standard data types + (see MAPPING), but the application can + define additional methods (e.g. for encoding CLOS objects). +

+ For example: +
CL-USER> (yason:encode
+          (list (alexandria:plist-hash-table
+                 '("foo" 1 "bar" (7 8 9))
+                 :test #'equal)
+                2 3 4
+                '(5 6 7)
+                t nil)
+          *standard-output*)
+[{"foo":1,"bar":[7,8,9]},2,3,4,[5,6,7],true,null]
+(#<HASH-TABLE :TEST EQUAL :COUNT 2 {59942D21}> 2 3 4 (5 6 7) T NIL)
+ +

DOM encoder dictionary

+

[Generic function]
encode object &optional + stream + => + object

+ Encode object in JSON format and + write to stream. May be specialized + by applications to perform specific rendering. Stream + defaults to *STANDARD-OUTPUT*. +

+ +

[Function]
encode-alist object &optional (stream + *standard-output*) + => + object

+ Encodes object, an alist, in JSON + format and write to stream. +

+ +

[Function]
encode-plist object &optional (stream + *standard-output*) + => + object

+ Encodes object, a plist, in JSON + format and write to stream. +

+ +

[Function]
make-json-output-stream stream &key (indent t) + => + stream

+ Creates a json-output-stream instance + that wraps the supplied stream and + optionally performs indentation of the generated JSON + data. The indent argument is + described in WITH-OUTPUT. Note that + if the indent argument is NIL, the + original stream is returned in order to avoid the + performance penalty of the indentation algorithm. +

+ +

+ [Special variable]
*list-encoder*

+ Function to call to translate a CL list into JSON data. + 'YASON:ENCODE-PLAIN-LIST-TO-ARRAY is the default; + 'YASON:ENCODE-PLIST and + 'YASON:ENCODE-ALIST are available to produce + JSON objects. +

+ This is useful to translate a deeply recursive structure in a single + YASON:ENCODE call. +

+

+ + +

+ [Special variable]
*symbol-key-encoder*

+ Defines the policy to encode symbols as keys (eg. in hash tables). + The default is to error out, to provide backwards-compatible behaviour. +

+ A useful function that can be bound to this variable is + YASON:ENCODE-SYMBOL-AS-LOWERCASE. +

+

+ + + +

Encoding JSON in streaming mode

+

+ In this mode, the JSON structure is generated in a stream. + The application makes explicit calls to the encoding library + in order to generate the JSON structure. It provides for more + control over the generated output, and can be used to generate + arbitary JSON without requiring that there exists a directly + matching Lisp data structure. The streaming API uses the + encode function, so it is possible to + intermix the two (see app-encoders for an + example). +

+ For example: +
CL-USER> (yason:with-output (*standard-output*)
+           (yason:with-array ()
+             (dotimes (i 3)
+               (yason:encode-array-element i))))
+[0,1,2]
+NIL
+CL-USER> (yason:with-output (*standard-output*)
+           (yason:with-object ()
+             (yason:encode-object-element "hello" "hu hu")
+             (yason:with-object-element ("harr")
+               (yason:with-array ()
+                 (dotimes (i 3)
+                   (yason:encode-array-element i))))))
+{"hello":"hu hu","harr":[0,1,2]}
+NIL
+ +

Streaming encoder dictionary

+

[Macro]
with-output (stream &key indent) &body body + => + result*

+ Set up a JSON streaming encoder context on + stream, then evaluate + body. indent + can be set to T to enable indentation with a default + indentation width or to an integer specifying the desired + indentation width. By default, indentation is switched + off. +

+ +

[Macro]
with-output-to-string* (&key indent stream-symbol) &body body + => + result*

+ Set up a JSON streaming encoder context on + stream-symbol (by default + a gensym), then evaluate + body. Return a string with the + generated JSON output. See + WITH-OUTPUT for the description of + the indent keyword argument. +

+ +

+ [Condition type]
no-json-output-context

+ This condition is signalled when one of the stream + encoding functions is used outside the dynamic context of + a WITH-OUTPUT or + WITH-OUTPUT-TO-STRING* body. +

+ +

[Macro]
with-array () &body body + => + result*

+ Open a JSON array, then run body. + Inside the body, ENCODE-ARRAY-ELEMENT + must be called to encode elements to the opened array. + Must be called within an existing JSON encoder context + (see WITH-OUTPUT and + WITH-OUTPUT-TO-STRING*). +

+ +

[Function]
encode-array-element object + => + object

+ Encode object as next array element to + the last JSON array opened + with WITH-ARRAY in the dynamic + context. object is encoded using the + ENCODE generic function, so it must be of + a type for which an ENCODE method is + defined. +

+ +

[Function]
encode-array-elements &rest objects + => + result*

+ Encode objects, a series of JSON + encodable objects, as the next array elements in a JSON + array opened with + WITH-ARRAY. ENCODE-ARRAY-ELEMENTS + uses ENCODE-ARRAY-ELEMENT, which must + be applicable to each object in the list + (i.e. ENCODE must be defined for each + object type). Additionally, this must be called within a + valid stream context. +

+ +

[Macro]
with-object () &body body + => + result*

+ Open a JSON object, then run body. + Inside the body, + ENCODE-OBJECT-ELEMENT or + WITH-OBJECT-ELEMENT must be called to + encode elements to the object. Must be called within an + existing JSON encoder + WITH-OUTPUT and + WITH-OUTPUT-TO-STRING*. +

+ +

[Macro]
with-object-element (key) &body body + => + result*

+ Open a new encoding context to encode a JSON object + element. key is the key of the + element. The value will be whatever + body serializes to the current JSON + output context using one of the stream encoding functions. + This can be used to stream out nested object structures. +

+ +

[Function]
encode-object-element key value + => + value

+ Encode key and + value as object element to the last + JSON object opened with WITH-OBJECT + in the dynamic context. key and + value are encoded using the + ENCODE generic function, so they both + must be of a type for which an ENCODE + method is defined. +

+ +

[Function]
encode-object-elements &rest elements + => + result*

+ Encodes the parameters into JSON in the last object opened + with WITH-OBJECT using + ENCODE-OBJECT-ELEMENT. The parameters + should consist of alternating key/value pairs, and this + must be called within a valid stream context. +

+ +

[Function]
encode-object-slots object slots + => + result*

+ Encodes each slot in SLOTS for OBJECT in the last object + opened with WITH-OBJECT using + ENCODE-OBJECT-ELEMENT. The key is the + slot name, and the value is the slot value for the slot on + OBJECT. It is equivalent to +
(loop for slot in slots
+    do (encode-object-element (string slot)
+                              (slot-value object slot)))
+			
+

+ +

[Function]
encode-slots object + => + result*

+ Generic function to encode object slots. There is no default + implementation. + It should be called in an object encoding context. It uses + PROGN combinatation with MOST-SPECIFIC-LAST order, so that + base class slots are encoded before derived class slots. +

+ +

[Function]
encode-object object + => + result*

+ Generic function to encode an object. The default implementation + opens a new object encoding context and calls + ENCODE-SLOTS on the argument. +

+ +

+ [Standard class]
json-output-stream

+ Instances of this class are used to wrap an output stream + that is used as a serialization target in the stream + encoder and optionally in the DOM encoder if indentation + is desired. The class name is not exported, use + make-json-output-stream to create a + wrapper stream if required. +

+ + + +

Application specific encoders

+ + Suppose your application uses structs to represent its data and + you want to encode these structs using JSON in order to send + them to a client application. Suppose further that your structs + also include internal information that you do not want to send. + Here is some code that illustrates how one could implement a + serialization function: + +
CL-USER> (defstruct user name age password)
+USER
+CL-USER> (defmethod yason:encode ((user user) &optional (stream *standard-output*))
+           (yason:with-output (stream)
+             (yason:with-object ()
+               (yason:encode-object-element "name" (user-name user))
+               (yason:encode-object-element "age" (user-age user)))))
+#<STANDARD-METHOD YASON:ENCODE (USER) {5B40A591}>
+CL-USER> (yason:encode (list (make-user :name "horst" :age 27 :password "puppy")
+                            (make-user :name "uschi" :age 28 :password "kitten")))
+[{"name":"horst","age":27},{"name":"uschi","age":28}]
+(#S(USER :NAME "horst" :AGE 27 :PASSWORD "puppy")
+ #S(USER :NAME "uschi" :AGE 28 :PASSWORD "kitten"))
+ + As you can see, the streaming API and the DOM encoder can be + used together. ENCODE invokes itself + recursively, so any application defined method will be called + while encoding in-memory objects as appropriate. + +

For an example of the interplay between + ENCODE-OBJECT and + ENCODE-SLOTS, suppose you have the following + CLOS class heirarchy: + +

(defclass shape ()
+  ((color :reader color)))
+
+(defclass square (shape)
+  ((side-length :reader side-length)))
+
+(defclass circle (shape)
+  ((radius :reader radius)))
+ + In order to implement encoding of circles and squares without + duplicating code you can specialize + ENCODE-SLOTS for all three classes + +
(defmethod yason:encode-slots progn ((shape shape))
+  (yason:encode-object-element "color" (color shape)))
+
+(defmethod yason:encode-slots progn ((square square))
+  (yason:encode-object-element "side-length" (side-length square)))
+
+(defmethod yason:encode-slots progn ((circle circle))
+  (yason:encode-object-element "radius" (radius circle)))
+ + and then use ENCODE-OBJECT: + +
CL-USER> (yason:with-output-to-string* ()
+           (yason:encode-object (make-instance 'square :color "red" :side-length 3)))
+"{\"color\":\"red\",\"side-length\":3}"
+CL-USER> (yason:with-output-to-string* ()
+           (yason:encode-object (make-instance 'circle :color "blue" :side-length 5)))
+"{\"color\":\"blue\",\"radius\":5}"
+

+

Alternatively, you can use the shortcut ENCODE-OBJECT-SLOTS + if you want the keys to be the slot names. For example: +

(defclass person ()
+  ((name :reader name :initarg :name)
+   (address :reader address :initarg :address)
+   (phone-number :reader phone-number :initarg :phone)
+   (favorite-color :reader favorite-color :initarg :color)))
+
+(defmethod yason:encode-slots progn ((person person))
+  (yason:encode-object-slots person '(name address phone-number favorite-color)))
+ and then: + +
CL-USER> (yason:with-output-to-string* ()
+       (yason:encode-object (make-instance 'person :name "John Doe"
+                                                   :address "123 Main St."
+                                                   :phone "(123)-456-7890"
+                                                   :color "blue")))
+"{\"NAME\":\"John Doe\",\"ADDRESS\":\"123 Main St.\",\"PHONE-NUMBER\":\"(123)-456-7890\",
+\"FAVORITE-COLOR\":\"blue\"}"
+

+ + + +

Symbol index

+ + + +

License

+
Copyright (c) 2008-2014 Hans Hübner and contributors
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+  - Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+  - Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+
+  - Neither the name BKNR nor the names of its contributors may be
+    used to endorse or promote products derived from this software
+    without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ + +

Acknowledgements

+ Thanks go to Edi Weitz for being a great inspiration. This + documentation as been generated with a hacked-up version of his DOCUMENTATION-TEMPLATE + software. Thanks to David Lichteblau for coining YASON's name. + + + diff --git a/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/package.lisp b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/package.lisp new file mode 100644 index 0000000..0140304 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/package.lisp @@ -0,0 +1,50 @@ +;; This file is part of yason, a Common Lisp JSON parser/encoder +;; +;; Copyright (c) 2008-2019 Hans Huebner and contributors +;; All rights reserved. +;; +;; Please see the file LICENSE in the distribution. + +(defpackage :yason + + (:use :cl) + + (:export + ;; Parser + #:parse + #:*parse-object-key-fn* + #:*parse-object-as* + #:*parse-object-as-alist* ; deprecated + #:*parse-json-arrays-as-vectors* + #:*parse-json-booleans-as-symbols* + #:*parse-json-null-as-keyword* + + #:true + #:false + #:null + + ;; Basic encoder interface + #:encode + #:encode-slots + #:encode-object + #:encode-plist + #:encode-alist + #:encode-plain-list-to-array + #:*list-encoder* + #:*symbol-key-encoder* + #:encode-symbol-as-lowercase + + #:make-json-output-stream + + ;; Streaming encoder interface + #:with-output + #:with-output-to-string* + #:no-json-output-context + #:with-array + #:encode-array-element + #:encode-array-elements + #:with-object + #:encode-object-element + #:encode-object-elements + #:encode-object-slots + #:with-object-element)) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/parse.lisp b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/parse.lisp new file mode 100644 index 0000000..b7542bc --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/parse.lisp @@ -0,0 +1,258 @@ +;; This file is part of yason, a Common Lisp JSON parser/encoder +;; +;; Copyright (c) 2008-2014 Hans Huebner and contributors +;; All rights reserved. +;; +;; Please see the file LICENSE in the distribution. + +(in-package :yason) + +(defconstant +default-string-length+ 20 + "Default length of strings that are created while reading json input.") + +(defvar *parse-object-key-fn* #'identity + "Function to call to convert a key string in a JSON array to a key + in the CL hash produced.") + +(defvar *parse-json-arrays-as-vectors* nil + "If set to a true value, JSON arrays will be parsed as vectors, not + as lists.") + +(defvar *parse-json-booleans-as-symbols* nil + "If set to a true value, JSON booleans will be read as the symbols + TRUE and FALSE, not as T and NIL, respectively.") + +(defvar *parse-json-null-as-keyword* nil + "If set to a true value, JSON nulls will be read as the keyword :NULL, not as NIL.") + +(defvar *parse-object-as* :hash-table + "Set to either :hash-table, :plist or :alist to determine the data + structure that objects are parsed to.") + +(defvar *parse-object-as-alist* nil + "DEPRECATED, provided for backward compatibility") + +(defun make-adjustable-string () + "Return an adjustable empty string, usable as a buffer for parsing strings and numbers." + (make-array +default-string-length+ + :adjustable t :fill-pointer 0 :element-type 'character)) + +(defun parse-number (input) + ;; would be + ;; (cl-ppcre:scan-to-strings "^-?(?:0|[1-9][0-9]*)(?:\\.[0-9]+|)(?:[eE][-+]?[0-9]+|)" buffer) + ;; but we want to operate on streams + (let ((buffer (make-adjustable-string))) + (loop while (position (peek-char nil input nil) ".0123456789+-Ee") + do (vector-push-extend (read-char input) buffer)) + (values (read-from-string buffer)))) + +(defun parse-unicode-escape (input) + (let ((char-code (let ((buffer (make-string 4))) + (read-sequence buffer input) + (parse-integer buffer :radix 16)))) + (if (and (>= char-code #xd800) + (<= char-code #xdbff)) + (let ((buffer (make-string 6))) + (read-sequence buffer input) + (when (not (string= buffer "\\u" :end1 2)) + (error "Lead Surrogate without Tail Surrogate")) + (let ((tail-code (parse-integer buffer :radix 16 :start 2))) + (when (not (and (>= tail-code #xdc00) + (<= tail-code #xdfff))) + (error "Lead Surrogate without Tail Surrogate")) + (code-char (+ #x010000 + (ash (- char-code #xd800) 10) + (- tail-code #xdc00))))) + (code-char char-code)))) + +(defun parse-string (input) + (let ((output (make-adjustable-string))) + (labels ((outc (c) + (vector-push-extend c output)) + (next () + (read-char input)) + (peek () + (peek-char nil input))) + (let* ((starting-symbol (next)) + (string-quoted (equal starting-symbol #\"))) + (unless string-quoted + (outc starting-symbol)) + (loop + (cond + ((eql (peek) #\") + (next) + (return-from parse-string output)) + ((eql (peek) #\\) + (next) + (ecase (next) + (#\" (outc #\")) + (#\\ (outc #\\)) + (#\/ (outc #\/)) + (#\b (outc #\Backspace)) + (#\f (outc #\Page)) + (#\n (outc #\Newline)) + (#\r (outc #\Return)) + (#\t (outc #\Tab)) + (#\u (outc (parse-unicode-escape input))))) + ((and (or (whitespace-p (peek)) + (eql (peek) #\:)) + (not string-quoted)) + (return-from parse-string output)) + (t + (outc (next))))))))) + +(defun whitespace-p (char) + (member char '(#\Space #\Newline #\Tab #\Linefeed #\Return))) + +(defun skip-whitespace (input) + (loop for c = (peek-char nil input nil nil) + while (and c (whitespace-p c)) + do (read-char input))) + +(defun peek-char-skipping-whitespace (input &optional (eof-error-p t)) + (skip-whitespace input) + (peek-char nil input eof-error-p)) + +(defun parse-constant (input) + (destructuring-bind (expected-string return-value) + (find (peek-char nil input nil) + `(("true" ,(if *parse-json-booleans-as-symbols* 'true t)) + ("false" ,(if *parse-json-booleans-as-symbols* 'false nil)) + ("null" ,(if *parse-json-null-as-keyword* :null nil))) + :key (lambda (entry) (aref (car entry) 0)) + :test #'eql) + (loop for char across expected-string + unless (eql (read-char input nil) char) + do (error "invalid constant")) + return-value)) + +(define-condition cannot-convert-key (error) + ((key-string :initarg :key-string + :reader key-string)) + (:report (lambda (c stream) + (format stream "cannot convert key ~S used in JSON object to hash table key" + (key-string c))))) + +(defun create-container () + (ecase *parse-object-as* + ((:plist :alist) + nil) + (:hash-table + (make-hash-table :test #'equal)))) + +(defun add-attribute (to key value) + (ecase *parse-object-as* + (:plist + (append to (list key value))) + (:alist + (acons key value to)) + (:hash-table + (setf (gethash key to) value) + to))) + +(define-condition expected-colon (error) + ((key-string :initarg :key-string + :reader key-string)) + (:report (lambda (c stream) + (format stream "expected colon to follow key ~S used in JSON object" + (key-string c))))) + +(defun parse-object (input) + (let ((return-value (create-container))) + (read-char input) + (loop + (when (eql (peek-char-skipping-whitespace input) + #\}) + (return)) + (skip-whitespace input) + (setf return-value + (add-attribute return-value + (let ((key-string (parse-string input))) + (prog1 + (or (funcall *parse-object-key-fn* key-string) + (error 'cannot-convert-key :key-string key-string)) + (skip-whitespace input) + (unless (eql #\: (read-char input)) + (error 'expected-colon :key-string key-string)) + (skip-whitespace input))) + (parse input))) + (ecase (peek-char-skipping-whitespace input) + (#\, (read-char input)) + (#\} nil))) + (read-char input) + return-value)) + +(defconstant +initial-array-size+ 20 + "Initial size of JSON arrays read, they will grow as needed.") + +(defun %parse-array (input add-element-function) + "Parse JSON array from input, calling ADD-ELEMENT-FUNCTION for each array element parsed." + (read-char input) + (loop + (when (eql (peek-char-skipping-whitespace input) + #\]) + (return)) + (funcall add-element-function (parse input)) + (ecase (peek-char-skipping-whitespace input) + (#\, (read-char input)) + (#\] nil))) + (read-char input)) + +(defun parse-array (input) + (if *parse-json-arrays-as-vectors* + (let ((return-value (make-array +initial-array-size+ :adjustable t :fill-pointer 0))) + (%parse-array input + (lambda (element) + (vector-push-extend element return-value))) + return-value) + (let (return-value) + (%parse-array input + (lambda (element) + (push element return-value))) + (nreverse return-value)))) + +(defgeneric parse% (input) + (:method ((input stream)) + ;; backward compatibility code + (assert (or (not *parse-object-as-alist*) + (eq *parse-object-as* :hash-table)) + () "unexpected combination of *parse-object-as* and *parse-object-as-alist*, please use *parse-object-as* exclusively") + (let ((*parse-object-as* (if *parse-object-as-alist* + :alist + *parse-object-as*))) + ;; end of backward compatibility code + (check-type *parse-object-as* (member :hash-table :alist :plist)) + (ecase (peek-char-skipping-whitespace input) + (#\" + (parse-string input)) + ((#\- #\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9) + (parse-number input)) + (#\{ + (parse-object input)) + (#\[ + (parse-array input)) + ((#\t #\f #\n) + (parse-constant input))))) + (:method ((input pathname)) + (with-open-file (stream input) + (parse stream))) + (:method ((input string)) + (parse (make-string-input-stream input)))) + +(defun parse (input + &key + (object-key-fn *parse-object-key-fn*) + (object-as *parse-object-as*) + (json-arrays-as-vectors *parse-json-arrays-as-vectors*) + (json-booleans-as-symbols *parse-json-booleans-as-symbols*) + (json-nulls-as-keyword *parse-json-null-as-keyword*)) + "Parse INPUT, which needs to be a string or a stream, as JSON. + Returns the lisp representation of the JSON structure parsed. The + keyword arguments can be used to override the parser settings as + defined by the respective special variables." + (let ((*parse-object-key-fn* object-key-fn) + (*parse-object-as* object-as) + (*parse-json-arrays-as-vectors* json-arrays-as-vectors) + (*parse-json-booleans-as-symbols* json-booleans-as-symbols) + (*parse-json-null-as-keyword* json-nulls-as-keyword)) + (parse% input))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/render-doc.sh b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/render-doc.sh new file mode 100644 index 0000000..07fb104 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/render-doc.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +xmllint --noout doc.xml +[ -f clixdoc.xsl ] || wget -q https://raw.github.com/hanshuebner/clixdoc/master/clixdoc.xsl +xsltproc --stringparam current-release `perl -ne 'if (/^ *:version +"(.*)"/) { print "$1\n" }' yason.asd` -o index.html clixdoc.xsl doc.xml diff --git a/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/test.lisp b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/test.lisp new file mode 100644 index 0000000..7001609 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/test.lisp @@ -0,0 +1,116 @@ +(defpackage :yason-test + (:use :cl :unit-test)) + +(in-package :yason-test) + +(defparameter *basic-test-json-string* "[{\"foo\":1,\"bar\":[7,8,9]},2,3,4,[5,6,7],true,null]") +(defparameter *basic-test-json-string-indented* " +[ + {\"foo\":1, + \"bar\":[7,8,9] + }, + 2, 3, 4, [5, 6, 7], true, null +]") +(defparameter *basic-test-json-dom* (list (alexandria:plist-hash-table + '("foo" 1 "bar" (7 8 9)) + :test #'equal) + 2 3 4 + '(5 6 7) + t nil)) + + +(deftest :yason "parser.basic" + (let ((result (yason:parse *basic-test-json-string*))) + (test-equal (first *basic-test-json-dom*) (first result) :test #'equalp) + (test-equal (rest *basic-test-json-dom*) (rest result)))) + +(deftest :yason "parser.basic-with-whitespace" + (let ((result (yason:parse *basic-test-json-string-indented*))) + (test-equal (first *basic-test-json-dom*) (first result) :test #'equalp) + (test-equal (rest *basic-test-json-dom*) (rest result)))) + +(deftest :yason "dom-encoder.basic" + (let ((result (yason:parse + (with-output-to-string (s) + (yason:encode *basic-test-json-dom* s))))) + (test-equal (first *basic-test-json-dom*) (first result) :test #'equalp) + (test-equal (rest *basic-test-json-dom*) (rest result)))) + +(defun whitespace-char-p (char) + (member char '(#\space #\tab #\return #\newline #\linefeed))) + +(deftest :yason "dom-encoder.indentation" + (test-equal "[ + 1, + 2, + 3 +]" + (with-output-to-string (s) + (yason:encode '(1 2 3) (yason:make-json-output-stream s :indent 10)))) + (dolist (indentation-arg '(nil t 2 20)) + (test-equal "[1,2,3]" (remove-if #'whitespace-char-p + (with-output-to-string (s) + (yason:encode '(1 2 3) + (yason:make-json-output-stream s :indent indentation-arg))))))) + +(deftest :yason "stream-encoder.basic-array" + (test-equal "[0,1,2]" + (with-output-to-string (s) + (yason:with-output (s) + (yason:with-array () + (dotimes (i 3) + (yason:encode-array-element i))))))) + +(deftest :yason "stream-encoder.basic-object" + (test-equal "{\"hello\":\"hu hu\",\"harr\":[0,1,2]}" + (with-output-to-string (s) + (yason:with-output (s) + (yason:with-object () + (yason:encode-object-element "hello" "hu hu") + (yason:with-object-element ("harr") + (yason:with-array () + (dotimes (i 3) + (yason:encode-array-element i))))))))) + +(deftest :yason "stream-encode.unicode-string" + (test-equal "\"ab\\u0002 cde \\uD834\\uDD1E\"" + (with-output-to-string (s) + (yason:encode (format nil "ab~C cde ~C" (code-char #x02) (code-char #x1d11e)) s)))) + +(defstruct user name age password) + +(defmethod yason:encode ((user user) &optional (stream *standard-output*)) + (yason:with-output (stream) + (yason:with-object () + (yason:encode-object-element "name" (user-name user)) + (yason:encode-object-element "age" (user-age user))))) + +(deftest :yason "stream-encoder.application-struct" + (test-equal "[{\"name\":\"horst\",\"age\":27},{\"name\":\"uschi\",\"age\":28}]" + (with-output-to-string (s) + (yason:encode (list (make-user :name "horst" :age 27 :password "puppy") + (make-user :name "uschi" :age 28 :password "kitten")) + s)))) + +(deftest :yason "recursive-alist-encode" + (test-equal "{\"a\":3,\"b\":[1,2,{\"c\":4,\"d\":[6]}]}" + (yason:with-output-to-string* (:stream-symbol s) + (let ((yason:*list-encoder* #'yason:encode-alist)) + (yason:encode + `(("a" . 3) ("b" . #(1 2 (("c" . 4) ("d" . #(6)))))) + s))))) + +(deftest :yason "symbols-as-keys" + (test-condition + (yason:with-output-to-string* (:stream-symbol s) + (let ((yason:*symbol-key-encoder* #'yason:encode-symbol-as-lowercase)) + (yason:encode-alist + `((:|abC| . 3)) + s))) + 'error) + (test-equal "{\"a\":3}" + (yason:with-output-to-string* (:stream-symbol s) + (let ((yason:*symbol-key-encoder* #'yason:encode-symbol-as-lowercase)) + (yason:encode-alist + `((:a . 3)) + s))))) diff --git a/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/yason.asd b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/yason.asd new file mode 100644 index 0000000..5609413 --- /dev/null +++ b/sbcl/.quicklisp/dists/quicklisp/software/yason-v0.7.8/yason.asd @@ -0,0 +1,33 @@ +;;;; -*- Mode: Lisp -*- + +;; This file is part of yason, a Common Lisp JSON parser/encoder +;; +;; Copyright (c) 2008-2014 Hans Huebner and contributors +;; All rights reserved. +;; +;; Please see the file LICENSE in the distribution. + +(in-package :cl-user) + +(defpackage :yason.system + (:use :cl :asdf)) + +(in-package :yason.system) + +(defsystem :yason + :name "YASON" + :author "Hans Huebner " + :version "0.7.6" + :maintainer "Hans Huebner " + :licence "BSD" + :description "JSON parser/encoder" + :long-description "YASON is a Common Lisp library for encoding and + decoding data in the JSON interchange format. JSON is used as a + lightweight alternative to XML. YASON has the sole purpose of + encoding and decoding data and does not impose any object model on + the Common Lisp application that uses it." + + :depends-on (:alexandria :trivial-gray-streams) + :components ((:file "package") + (:file "encode" :depends-on ("package")) + (:file "parse" :depends-on ("package")))) diff --git a/sbcl/.quicklisp/dists/quicklisp/systems.cdb b/sbcl/.quicklisp/dists/quicklisp/systems.cdb new file mode 100644 index 0000000000000000000000000000000000000000..49191e12004f50188ace9eb9f87e9706b38fba3b GIT binary patch literal 497817 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%0D=K7 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%0DLzR+ZlLGijjdibn(hSn!4-X2{ALU?4PO88N|%M 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 + :key #'preference)) + ;; FIXME: find-asdf-system-file does another find-system + ;; behind the scenes. Bogus. Should be a better way to go + ;; from system object to system file. + (let* ((system-file (find-asdf-system-file (name system))) + (enough (and system-file (enough-namestring system-file + output-file))) + (native (and enough (native-namestring enough)))) + (when (and native (not (gethash native already-seen))) + (setf (gethash native already-seen) native) + (format stream "~A~%" native))))))) + (probe-file output-file)) + +(defun where-is-system (name) + "Return the pathname to the source directory of ASDF system with the +given NAME, or NIL if no system by that name can be found known." + (let ((system (asdf:find-system name nil))) + (when system + (asdf:system-source-directory system)))) diff --git a/sbcl/.quicklisp/quicklisp/config.lisp b/sbcl/.quicklisp/quicklisp/config.lisp new file mode 100644 index 0000000..fd94790 --- /dev/null +++ b/sbcl/.quicklisp/quicklisp/config.lisp @@ -0,0 +1,40 @@ +;;;; config.lisp + +(in-package #:ql-config) + +(defun config-value-file-pathname (path) + (let ((bad-position (position #\Space path))) + (when bad-position + (error "Space not allowed at position ~D in ~S" + bad-position + path))) + (let* ((space-path (substitute #\Space #\/ path)) + (split (split-spaces space-path)) + (directory-parts (butlast split)) + (name (first (last split))) + (base (qmerge "config/"))) + (merge-pathnames + (make-pathname :name name + :type "txt" + :directory (list* :relative directory-parts)) + base))) + +(defun config-value (path) + (let ((file (config-value-file-pathname path))) + (with-open-file (stream file :if-does-not-exist nil) + (when stream + (values (read-line stream nil)))))) + +(defun (setf config-value) (new-value path) + (let ((file (config-value-file-pathname path))) + (typecase new-value + (null + (delete-file-if-exists file)) + (string + (ensure-directories-exist file) + (with-open-file (stream file :direction :output + :if-does-not-exist :create + :if-exists :rename-and-delete) + (write-line new-value stream))) + (t + (error "Bad config value ~S; must be a string or NIL" new-value))))) diff --git a/sbcl/.quicklisp/quicklisp/deflate.lisp b/sbcl/.quicklisp/quicklisp/deflate.lisp new file mode 100644 index 0000000..39129cf --- /dev/null +++ b/sbcl/.quicklisp/quicklisp/deflate.lisp @@ -0,0 +1,785 @@ +;;;; Deflate --- RFC 1951 Deflate Decompression +;;;; +;;;; Copyright (C) 2000-2009 PMSF IT Consulting Pierre R. Mai. +;;;; +;;;; Permission is hereby granted, free of charge, to any person obtaining +;;;; a copy of this software and associated documentation files (the +;;;; "Software"), to deal in the Software without restriction, including +;;;; without limitation the rights to use, copy, modify, merge, publish, +;;;; distribute, sublicense, and/or sell copies of the Software, and to +;;;; permit persons to whom the Software is furnished to do so, subject to +;;;; the following conditions: +;;;; +;;;; The above copyright notice and this permission notice shall be +;;;; included in all copies or substantial portions of the Software. +;;;; +;;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +;;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +;;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +;;;; IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR +;;;; OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +;;;; ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +;;;; OTHER DEALINGS IN THE SOFTWARE. +;;;; +;;;; Except as contained in this notice, the name of the author shall +;;;; not be used in advertising or otherwise to promote the sale, use or +;;;; other dealings in this Software without prior written authorization +;;;; from the author. +;;;; +;;;; $Id: 377d3a33e9db5a3b54c850619183ee555a41b894 $ + +(cl:in-package #:ql-gunzipper) + +;;;; %File Description: +;;;; +;;;; This file contains routines implementing the RFC 1951 Deflate +;;;; Compression and/or Decompression method, as used by e.g. gzip and +;;;; other compression and archiving tools and protocols. It also +;;;; implements handling routines for zlib-style (RFC 1950) and +;;;; gzip-style (RFC 1952) wrappers around raw Deflate streams. +;;;; +;;;; The main entry points are the functions inflate-stream, and its +;;;; cousins inflate-zlib-stream and inflate-gzip-stream, which take +;;;; an input-stream and an output-stream as their arguments, and +;;;; inflate the RFC 1951, RFC 1950 or RFC 1952-style deflate formats +;;;; from the input-stream to the output-stream. +;;;; + +;;; +;;; Conditions +;;; + +(define-condition decompression-error (simple-error) + ()) + +(define-condition deflate-decompression-error (decompression-error) + () + (:report + (lambda (c s) + (with-standard-io-syntax + (let ((*print-readably* nil)) + (format s + "Error detected during deflate decompression: ~?" + (simple-condition-format-control c) + (simple-condition-format-arguments c))))))) + +(define-condition zlib-decompression-error (decompression-error) + () + (:report + (lambda (c s) + (with-standard-io-syntax + (let ((*print-readably* nil)) + (format s + "Error detected during zlib decompression: ~?" + (simple-condition-format-control c) + (simple-condition-format-arguments c))))))) + +(define-condition gzip-decompression-error (decompression-error) + () + (:report + (lambda (c s) + (with-standard-io-syntax + (let ((*print-readably* nil)) + (format s + "Error detected during zlib decompression: ~?" + (simple-condition-format-control c) + (simple-condition-format-arguments c))))))) + +;;; +;;; Adler-32 Checksums +;;; + +(defconstant +adler-32-start-value+ 1 + "Start value for Adler-32 checksums as per RFC 1950.") + +(defconstant +adler-32-base+ 65521 + "Base value for Adler-32 checksums as per RFC 1950.") + +(declaim (ftype + (function ((unsigned-byte 32) (simple-array (unsigned-byte 8) (*)) fixnum) + (unsigned-byte 32)) + update-adler32-checksum)) +(defun update-adler32-checksum (crc buffer end) + (declare (type (unsigned-byte 32) crc) + (type (simple-array (unsigned-byte 8) (*)) buffer) + (type fixnum end) + (optimize (speed 3) (debug 0) (space 0) (safety 0)) + #+sbcl (sb-ext:muffle-conditions sb-ext:compiler-note)) + (let ((s1 (ldb (byte 16 0) crc)) + (s2 (ldb (byte 16 16) crc))) + (declare (type (unsigned-byte 32) s1 s2)) + (dotimes (i end) + (declare (type fixnum i)) + (setq s1 (mod (+ s1 (aref buffer i)) +adler-32-base+) + s2 (mod (+ s2 s1) +adler-32-base+))) + (dpb s2 (byte 16 16) s1))) + +;;; +;;; CRC-32 Checksums +;;; + +(defconstant +crc-32-start-value+ 0 + "Start value for CRC-32 checksums as per RFC 1952.") + +(defconstant +crc-32-polynomial+ #xedb88320 + "CRC-32 Polynomial as per RFC 1952.") + +(declaim (ftype #-lispworks (function () (simple-array (unsigned-byte 32) (256))) + #+lispworks (function () (sys:simple-int32-vector 256)) + generate-crc32-table)) +(defun generate-crc32-table () + (let ((result #-lispworks (make-array 256 :element-type '(unsigned-byte 32)) + #+lispworks (sys:make-simple-int32-vector 256))) + (dotimes (i #-lispworks (length result) #+lispworks 256 result) + (let ((cur i)) + (dotimes (k 8) + (setq cur (if (= 1 (logand cur 1)) + (logxor (ash cur -1) +crc-32-polynomial+) + (ash cur -1)))) + #-lispworks (setf (aref result i) cur) + #+lispworks (setf (sys:int32-aref result i) + (sys:integer-to-int32 + (dpb (ldb (byte 32 0) cur) (byte 32 0) + (if (logbitp 31 cur) -1 0)))))))) + +(declaim (ftype + (function ((unsigned-byte 32) (simple-array (unsigned-byte 8) (*)) fixnum) + (unsigned-byte 32)) + update-crc32-checksum)) +#-lispworks +(defun update-crc32-checksum (crc buffer end) + (declare (type (unsigned-byte 32) crc) + (type (simple-array (unsigned-byte 8) (*)) buffer) + (type fixnum end) + (optimize (speed 3) (debug 0) (space 0) (safety 0)) + #+sbcl (sb-ext:muffle-conditions sb-ext:compiler-note)) + (let ((table (load-time-value (generate-crc32-table))) + (cur (logxor crc #xffffffff))) + (declare (type (simple-array (unsigned-byte 32) (256)) table) + (type (unsigned-byte 32) cur)) + (dotimes (i end) + (declare (type fixnum i)) + (let ((index (logand #xff (logxor cur (aref buffer i))))) + (declare (type (unsigned-byte 8) index)) + (setq cur (logxor (aref table index) (ash cur -8))))) + (logxor cur #xffffffff))) + +#+lispworks +(defun update-crc32-checksum (crc buffer end) + (declare (type (unsigned-byte 32) crc) + (type (simple-array (unsigned-byte 8) (*)) buffer) + (type fixnum end) + (optimize (speed 3) (debug 0) (space 0) (safety 0) (float 0))) + (let ((table (load-time-value (generate-crc32-table))) + (cur (sys:int32-lognot (sys:integer-to-int32 + (dpb (ldb (byte 32 0) crc) (byte 32 0) + (if (logbitp 31 crc) -1 0)))))) + (declare (type (sys:simple-int32-vector 256) table) + (type sys:int32 cur)) + (dotimes (i end) + (declare (type fixnum i)) + (let ((index (sys:int32-to-integer + (sys:int32-logand #xff (sys:int32-logxor cur (aref buffer i)))))) + (declare (type fixnum index)) + (setq cur (sys:int32-logxor (sys:int32-aref table index) + (sys:int32-logand #x00ffffff + (sys:int32>> cur 8)))))) + (ldb (byte 32 0) (sys:int32-to-integer (sys:int32-lognot cur))))) + +;;; +;;; Helper Data Structures: Sliding Window Stream +;;; + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defconstant +sliding-window-size+ 32768 + "Size of sliding window for RFC 1951 Deflate compression scheme.")) + +(defstruct sliding-window-stream + (stream nil :type stream :read-only t) + (buffer (make-array +sliding-window-size+ :element-type '(unsigned-byte 8)) + :type (simple-array (unsigned-byte 8) (#.+sliding-window-size+)) :read-only t) + (buffer-end 0 :type fixnum) + (checksum nil :type symbol :read-only t) + (checksum-value 0 :type (unsigned-byte 32))) + +(declaim (inline sliding-window-stream-write-byte)) +(defun sliding-window-stream-write-byte (stream byte) + (declare (type sliding-window-stream stream) (type (unsigned-byte 8) byte) + #+sbcl (sb-ext:muffle-conditions sb-ext:compiler-note)) + "Write a single byte to the sliding-window-stream." + (let ((end (sliding-window-stream-buffer-end stream))) + (declare (type fixnum end)) + (unless (< end +sliding-window-size+) + (write-sequence (sliding-window-stream-buffer stream) + (sliding-window-stream-stream stream)) + (case (sliding-window-stream-checksum stream) + (:adler-32 (setf (sliding-window-stream-checksum-value stream) + (update-adler32-checksum + (sliding-window-stream-checksum-value stream) + (sliding-window-stream-buffer stream) + +sliding-window-size+))) + (:crc-32 (setf (sliding-window-stream-checksum-value stream) + (update-crc32-checksum + (sliding-window-stream-checksum-value stream) + (sliding-window-stream-buffer stream) + +sliding-window-size+)))) + (setq end 0)) + (setf (aref (sliding-window-stream-buffer stream) end) byte + (sliding-window-stream-buffer-end stream) (1+ end)))) + +(defun sliding-window-stream-flush (stream) + (declare (type sliding-window-stream stream)) + "Flush any remaining buffered bytes from the stream." + (let ((end (sliding-window-stream-buffer-end stream))) + (declare (type fixnum end)) + (unless (zerop end) + (case (sliding-window-stream-checksum stream) + (:adler-32 (setf (sliding-window-stream-checksum-value stream) + (update-adler32-checksum + (sliding-window-stream-checksum-value stream) + (sliding-window-stream-buffer stream) + end))) + (:crc-32 (setf (sliding-window-stream-checksum-value stream) + (update-crc32-checksum + (sliding-window-stream-checksum-value stream) + (sliding-window-stream-buffer stream) + end)))) + (write-sequence (sliding-window-stream-buffer stream) + (sliding-window-stream-stream stream) + :end end)))) + +(defun sliding-window-stream-copy-bytes (stream distance length) + (declare (type sliding-window-stream stream) (type fixnum distance length)) + "Copy a number of bytes from the current sliding window." + (let* ((end (sliding-window-stream-buffer-end stream)) + (start (mod (- end distance) +sliding-window-size+)) + (buffer (sliding-window-stream-buffer stream))) + (declare (type fixnum end start) + (type (simple-array (unsigned-byte 8) (#.+sliding-window-size+)) buffer)) + (dotimes (i length) + (sliding-window-stream-write-byte + stream + (aref buffer (mod (+ start i) +sliding-window-size+)))))) + +;;; +;;; Helper Data Structures: Bit-wise Input Stream +;;; + +(defstruct bit-stream + (stream nil :type stream :read-only t) + (next-byte 0 :type fixnum) + (bits 0 :type (unsigned-byte 29)) + (bit-count 0 :type (unsigned-byte 8))) + +(declaim (inline bit-stream-get-byte)) +(defun bit-stream-get-byte (stream) + (declare (type bit-stream stream)) + "Read another byte from the underlying stream." + (the (unsigned-byte 8) (read-byte (bit-stream-stream stream)))) + +(declaim (inline bit-stream-read-bits)) +(defun bit-stream-read-bits (stream bits) + (declare (type bit-stream stream) + ;; [quicklisp-added] + ;; FIXME: This might be fixed soon in ECL. + ;; http://article.gmane.org/gmane.lisp.ecl.general/7659 + #-ecl + (type (unsigned-byte 8) bits)) + "Read single or multiple bits from the given bit-stream." + (loop while (< (bit-stream-bit-count stream) bits) + do + ;; Fill bits + (setf (bit-stream-bits stream) + (logior (bit-stream-bits stream) + (the (unsigned-byte 29) + (ash (bit-stream-get-byte stream) + (bit-stream-bit-count stream)))) + (bit-stream-bit-count stream) (+ (bit-stream-bit-count stream) 8))) + ;; Return properly masked bits + (if (= (bit-stream-bit-count stream) bits) + (prog1 (bit-stream-bits stream) + (setf (bit-stream-bits stream) 0 + (bit-stream-bit-count stream) 0)) + (prog1 (ldb (byte bits 0) (bit-stream-bits stream)) + (setf (bit-stream-bits stream) (ash (bit-stream-bits stream) (- bits)) + (bit-stream-bit-count stream) (- (bit-stream-bit-count stream) bits))))) + +(declaim (inline bit-stream-copy-block)) +(defun bit-stream-copy-block (stream out-stream) + (declare (type bit-stream stream) (type sliding-window-stream out-stream) + (optimize (speed 3) (safety 0) (space 0) (debug 0))) + "Copy a given block of bytes directly from the underlying stream." + ;; Skip any remaining unprocessed bits + (setf (bit-stream-bits stream) 0 + (bit-stream-bit-count stream) 0) + ;; Get LEN/NLEN and copy bytes + (let* ((len (logior (bit-stream-get-byte stream) + (ash (bit-stream-get-byte stream) 8))) + (nlen (ldb (byte 16 0) + (lognot (logior (bit-stream-get-byte stream) + (ash (bit-stream-get-byte stream) 8)))))) + (unless (= len nlen) + (error 'deflate-decompression-error + :format-control + "Block length mismatch for stored block: LEN(~D) vs. NLEN(~D)!" + :format-arguments (list len nlen))) + (dotimes (i len) + (sliding-window-stream-write-byte out-stream (bit-stream-get-byte stream))))) + +;;; +;;; Huffman Coding +;;; + +;;; A decode-tree struct contains all information necessary to decode +;;; the given canonical huffman code. Note that length-count contains +;;; the number of codes with a given length for each length, whereas +;;; the code-symbols array contains the symbols corresponding to the +;;; codes in canoical order of the codes. +;;; +;;; Decoding then uses this information and the principles underlying +;;; canonical huffman codes to determine whether the currently +;;; collected word falls between the first code and the last code for +;;; the current length, and if so, uses the offset to determine the +;;; code's symbol. Otherwise more bits are needed. + +(defstruct decode-tree + (length-count (make-array 16 :element-type 'fixnum :initial-element 0) + :type (simple-array fixnum (*)) :read-only t) + (code-symbols (make-array 16 :element-type 'fixnum :initial-element 0) + :type (simple-array fixnum (*)))) + +(defun make-huffman-decode-tree (code-lengths) + "Construct a huffman decode-tree for the canonical huffman code with +the code lengths of each symbol given in the input array." + (let* ((max-length (reduce #'max code-lengths :initial-value 0)) + (next-code (make-array (1+ max-length) :element-type 'fixnum + :initial-element 0)) + (code-symbols (make-array (length code-lengths) :element-type 'fixnum + :initial-element 0)) + (length-count (make-array (1+ max-length) :element-type 'fixnum + :initial-element 0))) + ;; Count length occurences and calculate offsets of smallest codes + (loop for index from 1 to max-length + for code = 0 then (+ code (aref length-count (1- index))) + do + (setf (aref next-code index) code) + initially + ;; Count length occurences + (loop for length across code-lengths + do + (incf (aref length-count length)) + finally + (setf (aref length-count 0) 0))) + ;; Construct code symbols mapping + (loop for length across code-lengths + for index upfrom 0 + unless (zerop length) + do + (setf (aref code-symbols (aref next-code length)) index) + (incf (aref next-code length))) + ;; Return result + (make-decode-tree :length-count length-count :code-symbols code-symbols))) + +(declaim (inline read-huffman-code)) +(defun read-huffman-code (bit-stream decode-tree) + (declare (type bit-stream bit-stream) (type decode-tree decode-tree) + (optimize (speed 3) (safety 0) (space 0) (debug 0))) + "Read the next huffman code word from the given bit-stream and +return its decoded symbol, for the huffman code given by decode-tree." + (loop with length-count of-type (simple-array fixnum (*)) + = (decode-tree-length-count decode-tree) + with code-symbols of-type (simple-array fixnum (*)) + = (decode-tree-code-symbols decode-tree) + for code of-type fixnum = (bit-stream-read-bits bit-stream 1) + then (+ (* code 2) (bit-stream-read-bits bit-stream 1)) + for index of-type fixnum = 0 then (+ index count) + for first of-type fixnum = 0 then (* (+ first count) 2) + for length of-type fixnum upfrom 1 below (length length-count) + for count = (aref length-count length) + thereis (when (< code (the fixnum (+ first count))) + (aref code-symbols (+ index (- code first)))) + finally + (error 'deflate-decompression-error + :format-control + "Corrupted Data detected during decompression: ~ + Incorrect huffman code (~X) in huffman decode!" + :format-arguments (list code)))) + +;;; +;;; Standard Huffman Tables +;;; + +(defparameter *std-lit-decode-tree* + (make-huffman-decode-tree + (concatenate 'vector + (make-sequence 'vector 144 :initial-element 8) + (make-sequence 'vector 112 :initial-element 9) + (make-sequence 'vector 24 :initial-element 7) + (make-sequence 'vector 8 :initial-element 8)))) + +(defparameter *std-dist-decode-tree* + (make-huffman-decode-tree + (make-sequence 'vector 32 :initial-element 5))) + +;;; +;;; Dynamic Huffman Table Handling +;;; + +(defparameter *code-length-entry-order* + #(16 17 18 0 8 7 9 6 10 5 11 4 12 3 13 2 14 1 15) + "Order of Code Length Tree Code Lengths.") + +(defun decode-code-length-entries (bit-stream count decode-tree) + "Decode the given number of code length entries from the bit-stream +using the given decode-tree, and return a corresponding array of code +lengths for further processing." + (do ((result (make-array count :element-type 'fixnum :initial-element 0)) + (index 0)) + ((>= index count) result) + (let ((code (read-huffman-code bit-stream decode-tree))) + (ecase code + ((0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) + (setf (aref result index) code) + (incf index)) + (16 + (let ((length (+ 3 (bit-stream-read-bits bit-stream 2)))) + (dotimes (i length) + (setf (aref result (+ index i)) (aref result (1- index)))) + (incf index length))) + (17 + (let ((length (+ 3 (bit-stream-read-bits bit-stream 3)))) + (dotimes (i length) + (setf (aref result (+ index i)) 0)) + (incf index length))) + (18 + (let ((length (+ 11 (bit-stream-read-bits bit-stream 7)))) + (dotimes (i length) + (setf (aref result (+ index i)) 0)) + (incf index length))))))) + +(defun decode-huffman-tables (bit-stream) + "Decode the stored huffman tables from the given bit-stream, returning +the corresponding decode-trees for literals/length and distance codes." + (let* ((hlit (bit-stream-read-bits bit-stream 5)) + (hdist (bit-stream-read-bits bit-stream 5)) + (hclen (bit-stream-read-bits bit-stream 4))) + ;; Construct Code Length Decode Tree + (let ((cl-decode-tree + (loop with code-lengths = (make-array 19 :element-type '(unsigned-byte 8) + :initial-element 0) + for index from 0 below (+ hclen 4) + for code-length = (bit-stream-read-bits bit-stream 3) + for code-index = (aref *code-length-entry-order* index) + do + (setf (aref code-lengths code-index) code-length) + finally + (return (make-huffman-decode-tree code-lengths))))) + ;; Decode Code Length Table and generate separate huffman trees + (let ((entries (decode-code-length-entries bit-stream + (+ hlit 257 hdist 1) + cl-decode-tree))) + (values + (make-huffman-decode-tree (subseq entries 0 (+ hlit 257))) + (make-huffman-decode-tree (subseq entries (+ hlit 257)))))))) + +;;; +;;; Compressed Block Handling +;;; + +(declaim (inline decode-length-entry)) +(defun decode-length-entry (symbol bit-stream) + "Decode the given length symbol into a proper length specification." + (cond + ((<= symbol 264) (- symbol 254)) + ((<= symbol 268) (+ 11 (* (- symbol 265) 2) (bit-stream-read-bits bit-stream 1))) + ((<= symbol 272) (+ 19 (* (- symbol 269) 4) (bit-stream-read-bits bit-stream 2))) + ((<= symbol 276) (+ 35 (* (- symbol 273) 8) (bit-stream-read-bits bit-stream 3))) + ((<= symbol 280) (+ 67 (* (- symbol 277) 16) (bit-stream-read-bits bit-stream 4))) + ((<= symbol 284) + (+ 131 (* (- symbol 281) 32) (bit-stream-read-bits bit-stream 5))) + ((= symbol 285) 258) + (t + (error 'deflate-decompression-error + :format-control "Strange Length Code in bitstream: ~D" + :format-arguments (list symbol))))) + +(declaim (inline decode-distance-entry)) +(defun decode-distance-entry (symbol bit-stream) + "Decode the given distance symbol into a proper distance specification." + (cond + ((<= symbol 3) (1+ symbol)) + (t + (multiple-value-bind (order offset) (truncate symbol 2) + (let* ((extra-bits (1- order)) + (factor (ash 1 extra-bits))) + (+ (1+ (ash 1 order)) + (* offset factor) + (bit-stream-read-bits bit-stream extra-bits))))))) + +(defun decode-huffman-block (bit-stream window-stream + lit-decode-tree dist-decode-tree) + "Decode the huffman code block using the huffman codes given by +lit-decode-tree and dist-decode-tree." + (do ((symbol (read-huffman-code bit-stream lit-decode-tree) + (read-huffman-code bit-stream lit-decode-tree))) + ((= symbol 256)) + (cond + ((<= symbol 255) + (sliding-window-stream-write-byte window-stream symbol)) + (t + (let ((length (decode-length-entry symbol bit-stream)) + (distance (decode-distance-entry + (read-huffman-code bit-stream dist-decode-tree) bit-stream))) + (sliding-window-stream-copy-bytes window-stream distance length)))))) + +;;; +;;; Block Handling Code +;;; + +(defun decode-block (bit-stream window-stream) + "Decompress a block read from bit-stream into window-stream." + (let* ((finalp (not (zerop (bit-stream-read-bits bit-stream 1)))) + (type (bit-stream-read-bits bit-stream 2))) + (ecase type + (#b00 (bit-stream-copy-block bit-stream window-stream)) + (#b01 + (decode-huffman-block bit-stream window-stream + *std-lit-decode-tree* + *std-dist-decode-tree*)) + (#b10 + (multiple-value-bind (lit-decode-tree dist-decode-tree) + (decode-huffman-tables bit-stream) + (decode-huffman-block bit-stream window-stream + lit-decode-tree dist-decode-tree))) + (#b11 + (error 'deflate-decompression-error + :format-control "Encountered Reserved Block Type ~D!" + :format-arguments (list type)))) + (not finalp))) + +;;; +;;; ZLIB - RFC 1950 handling +;;; + +(defun parse-zlib-header (input-stream) + "Parse a ZLIB-style header as per RFC 1950 from the input-stream and +return the compression-method, compression-level dictionary-id and flags +fields of the header as return values. Checks the header for corruption +and signals a zlib-decompression-error in case of corruption." + (let ((compression-method (read-byte input-stream)) + (flags (read-byte input-stream))) + (unless (zerop (mod (+ (* compression-method 256) flags) 31)) + (error 'zlib-decompression-error + :format-control "Corrupted Header ~2,'0X,~2,'0X!" + :format-arguments (list compression-method flags))) + (let ((dict (unless (zerop (ldb (byte 1 5) flags)) + (parse-zlib-checksum input-stream)))) + (values (ldb (byte 4 0) compression-method) + (ldb (byte 4 4) compression-method) + dict + (ldb (byte 2 6) flags))))) + +(defun parse-zlib-checksum (input-stream) + (+ (* (read-byte input-stream) 256 256 256) + (* (read-byte input-stream) 256 256) + (* (read-byte input-stream) 256) + (read-byte input-stream))) + +(defun parse-zlib-footer (input-stream) + "Parse the ZLIB-style footer as per RFC 1950 from the input-stream and +return the Adler-32 checksum contained in the footer as its return value." + (parse-zlib-checksum input-stream)) + +;;; +;;; GZIP - RFC 1952 handling +;;; + +(defconstant +gzip-header-id1+ 31 + "GZIP Header Magic Value ID1 as per RFC 1952.") + +(defconstant +gzip-header-id2+ 139 + "GZIP Header Magic Value ID2 as per RFC 1952.") + +(defun parse-gzip-header (input-stream) + "Parse a GZIP-style header as per RFC 1952 from the input-stream and +return the compression-method, text-flag, modification time, XFLAGS, +OS, FEXTRA flags, filename, comment and CRC16 fields of the header as +return values (or nil if any given field is not present). Checks the +header for magic values and correct flags settings and signals a +gzip-decompression-error in case of incorrect or unsupported magic +values or flags." + (let ((id1 (read-byte input-stream)) + (id2 (read-byte input-stream)) + (compression-method (read-byte input-stream)) + (flags (read-byte input-stream))) + (unless (and (= id1 +gzip-header-id1+) (= id2 +gzip-header-id2+)) + (error 'gzip-decompression-error + :format-control + "Header missing magic values ~2,'0X,~2,'0X (got ~2,'0X,~2,'0X instead)!" + :format-arguments (list +gzip-header-id1+ +gzip-header-id2+ id1 id2))) + (unless (= compression-method 8) + (error 'gzip-decompression-error + :format-control "Unknown compression-method in Header ~2,'0X!" + :format-arguments (list compression-method))) + (unless (zerop (ldb (byte 3 5) flags)) + (error 'gzip-decompression-error + :format-control "Unknown flags in Header ~2,'0X!" + :format-arguments (list flags))) + (values compression-method + ;; FTEXT + (= 1 (ldb (byte 1 0) flags)) + ;; MTIME + (parse-gzip-mtime input-stream) + ;; XFLAGS + (read-byte input-stream) + ;; OS + (read-byte input-stream) + ;; FEXTRA + (unless (zerop (ldb (byte 1 2) flags)) + (parse-gzip-extra input-stream)) + ;; FNAME + (unless (zerop (ldb (byte 1 3) flags)) + (parse-gzip-string input-stream)) + ;; FCOMMENT + (unless (zerop (ldb (byte 1 4) flags)) + (parse-gzip-string input-stream)) + ;; CRC16 + (unless (zerop (ldb (byte 1 1) flags)) + (+ (read-byte input-stream) + (* (read-byte input-stream 256))))))) + +(defun parse-gzip-mtime (input-stream) + (let ((time (+ (read-byte input-stream) + (* (read-byte input-stream) 256) + (* (read-byte input-stream) 256 256) + (* (read-byte input-stream) 256 256 256)))) + (if (zerop time) + nil + (+ time 2208988800)))) + +(defun parse-gzip-extra (input-stream) + (let* ((length (+ (read-byte input-stream) (* (read-byte input-stream) 256))) + (result (make-array length :element-type '(unsigned-byte 8)))) + (read-sequence result input-stream) + result)) + +(defun parse-gzip-string (input-stream) + (with-output-to-string (string) + (loop for value = (read-byte input-stream) + until (zerop value) + do (write-char (code-char value) string)))) + +(defun parse-gzip-checksum (input-stream) + (+ (read-byte input-stream) + (* (read-byte input-stream) 256) + (* (read-byte input-stream) 256 256) + (* (read-byte input-stream) 256 256 256))) + +(defun parse-gzip-footer (input-stream) + "Parse the GZIP-style footer as per RFC 1952 from the input-stream and +return the CRC-32 checksum and ISIZE fields contained in the footer as +its return values." + (values (parse-gzip-checksum input-stream) + ;; ISIZE + (+ (read-byte input-stream) + (* (read-byte input-stream) 256) + (* (read-byte input-stream) 256 256) + (* (read-byte input-stream) 256 256 256)))) + +;;; +;;; Main Entry Points +;;; + +(defun inflate-stream (input-stream output-stream &key checksum) + "Inflate the RFC 1951 data from the given input stream into the +given output stream, which are required to have an element-type +of (unsigned-byte 8). If checksum is given, it indicates the +checksumming algorithm to employ in calculating a checksum of +the expanded content, which is then returned from this function. +Valid values are :adler-32 for Adler-32 checksum (see RFC 1950), +or :crc-32 for CRC-32 as per ISO 3309 (see RFC 1952, ZIP)." + (loop with window-stream = (make-sliding-window-stream :stream output-stream + :checksum checksum + :checksum-value + (ecase checksum + ((nil) 0) + (:crc-32 +crc-32-start-value+) + (:adler-32 +adler-32-start-value+))) + with bit-stream = (make-bit-stream :stream input-stream) + while (decode-block bit-stream window-stream) + finally (sliding-window-stream-flush window-stream) + (when checksum + (return (sliding-window-stream-checksum-value window-stream))))) + +(defun inflate-zlib-stream (input-stream output-stream &key check-checksum) + "Inflate the RFC 1950 zlib data from the given input stream into +the given output stream, which are required to have an element-type +of (unsigned-byte 8). This returns the Adler-32 checksum of the +file as its first return value, with the compression level as its +second return value. Note that it is the responsibility of the +caller to check whether the expanded data matches the Adler-32 +checksum, unless the check-checksum keyword argument is set to +true, in which case the checksum is checked internally and a +zlib-decompression-error is signalled if they don't match." + (multiple-value-bind (cm cinfo dictid flevel) (parse-zlib-header input-stream) + (unless (= cm 8) + (error 'zlib-decompression-error + :format-control "Unknown compression method ~D!" + :format-arguments (list cm))) + (unless (<= cinfo 7) + (error 'zlib-decompression-error + :format-control "Unsupported sliding window size 2^~D = ~D!" + :format-arguments (list (+ 8 cinfo) (expt 2 (+ 8 cinfo))))) + (unless (null dictid) + (error 'zlib-decompression-error + :format-control "Unknown preset dictionary id ~8,'0X!" + :format-arguments (list dictid))) + (let ((checksum-new (inflate-stream input-stream output-stream + :checksum (when check-checksum :adler-32))) + (checksum-old (parse-zlib-footer input-stream))) + (when (and check-checksum (not (= checksum-old checksum-new))) + (error 'zlib-decompression-error + :format-control + "Checksum mismatch for decompressed stream: ~8,'0X != ~8,'0X!" + :format-arguments (list checksum-old checksum-new))) + (values checksum-old flevel)))) + +(defun inflate-gzip-stream (input-stream output-stream &key check-checksum) + "Inflate the RFC 1952 gzip data from the given input stream into +the given output stream, which are required to have an element-type +of (unsigned-byte 8). This returns the CRC-32 checksum of the +file as its first return value, with any filename, modification time, +and comment fields as further return values or nil if not present. +Note that it is the responsibility of the caller to check whether the +expanded data matches the CRC-32 checksum, unless the check-checksum +keyword argument is set to true, in which case the checksum is checked +internally and a gzip-decompression-error is signalled if they don't +match." + (multiple-value-bind (cm ftext mtime xfl os fextra fname fcomment) + (parse-gzip-header input-stream) + (declare (ignore ftext xfl os fextra)) + (unless (= cm 8) + (error 'gzip-decompression-error + :format-control "Unknown compression method ~D!" + :format-arguments (list cm))) + (let ((checksum-new (inflate-stream input-stream output-stream + :checksum (when check-checksum :crc-32))) + (checksum-old (parse-gzip-footer input-stream))) + ;; Handle Checksums + (when (and check-checksum (not (= checksum-old checksum-new))) + (error 'gzip-decompression-error + :format-control + "Checksum mismatch for decompressed stream: ~8,'0X != ~8,'0X!" + :format-arguments (list checksum-old checksum-new))) + (values checksum-old fname mtime fcomment)))) + + +(defun gunzip (input-file output-file) + (with-open-file (input input-file + :element-type '(unsigned-byte 8)) + (with-open-file (output output-file + :direction :output + :if-exists :supersede + :element-type '(unsigned-byte 8)) + (inflate-gzip-stream input output))) + (probe-file output-file)) diff --git a/sbcl/.quicklisp/quicklisp/dist-update.lisp b/sbcl/.quicklisp/quicklisp/dist-update.lisp new file mode 100644 index 0000000..0974eb4 --- /dev/null +++ b/sbcl/.quicklisp/quicklisp/dist-update.lisp @@ -0,0 +1,164 @@ +;;;; dist-update.lisp + +(in-package #:ql-dist) + +(defgeneric available-update (dist) + (:documentation "If an update is available for DIST, return the + update as an uninstalled dist object. Otherwise, return NIL.")) + +(defgeneric update-release-differences (old-dist new-dist) + (:documentation "Compare OLD-DIST to NEW-DIST and return three lists + as multiple values: new releases \(present in NEW-DIST but not + OLD-DIST), changed releases \(present in both dists but different in + some way), and removed releases \(present in OLD-DIST but not + NEW-DIST). The list of changed releases is a list of two-element + lists, with each two-element list having first the old release + object and then the new release object.")) + +(defgeneric show-update-report (old-dist new-dist) + (:documentation "Display a description of the update from OLD-DIST + to NEW-DIST.")) + +(defgeneric update-in-place (old-dist new-dist) + (:documentation "Update OLD-DIST to NEW-DIST in place.")) + +(defmethod available-update ((dist dist)) + (let ((url (distinfo-subscription-url dist)) + (target (qmerge "tmp/distinfo-update/distinfo.txt")) + (update-directory (qmerge "tmp/distinfo-update/"))) + (when (probe-directory update-directory) + (delete-directory-tree (qmerge "tmp/distinfo-update/"))) + (when url + (ensure-directories-exist target) + (fetch url target :quietly t) + (let ((new (make-dist-from-file target))) + (setf (base-directory new) + (make-pathname :name nil + :type nil + :version nil + :defaults target)) + (when (and (string= (name dist) (name new)) + (string/= (version dist) (version new))) + new))))) + +(defmethod update-release-differences ((old-dist dist) + (new-dist dist)) + (let ((old-releases (provided-releases old-dist)) + (new-releases (provided-releases new-dist)) + (new '()) + (updated '()) + (removed '()) + (old-by-name (make-hash-table :test 'equalp))) + (dolist (release old-releases) + (setf (gethash (name release) old-by-name) + release)) + (dolist (new-release new-releases) + (let* ((name (name new-release)) + (old-release (gethash name old-by-name))) + (remhash name old-by-name) + (cond ((not old-release) + (push new-release new)) + ((not (equal (archive-content-sha1 new-release) + (archive-content-sha1 old-release))) + (push (list old-release new-release) updated))))) + (maphash (lambda (name old-release) + (declare (ignore name)) + (push old-release removed)) + old-by-name) + (values (nreverse new) + (nreverse updated) + (sort removed #'string< :key #'prefix)))) + +(defmethod show-update-report ((old-dist dist) (new-dist dist)) + (multiple-value-bind (new updated removed) + (update-release-differences old-dist new-dist) + (format t "Changes from ~A ~A to ~A ~A:~%" + (name old-dist) + (version old-dist) + (name new-dist) + (version new-dist)) + (when new + (format t "~& New projects:~%") + (format t "~{ ~A~%~}" (mapcar #'prefix new))) + (when updated + (format t "~% Updated projects:~%") + (loop for (old-release new-release) in updated + do (format t " ~A -> ~A~%" + (prefix old-release) + (prefix new-release)))) + (when removed + (format t "~% Removed projects:~%") + (format t "~{ ~A~%~}" (mapcar #'prefix removed))))) + +(defun clear-dist-systems (dist) + (dolist (system (provided-systems dist)) + (asdf:clear-system (name system)))) + +(defmethod update-in-place :before ((old-dist dist) (new-dist dist)) + ;; Make sure ASDF will reload any systems at their new locations + (clear-dist-systems old-dist)) + +(defmethod update-in-place :after ((old-dist dist) (new-dist dist)) + (clean new-dist)) + +(defmethod update-in-place ((old-dist dist) (new-dist dist)) + (flet ((remove-installed (type) + (let ((wild (merge-pathnames (make-pathname :directory + (list :relative + "installed" + type) + :name :wild + :type "txt") + (base-directory old-dist)))) + (dolist (file (directory wild)) + (delete-file file))))) + (let ((reinstall-releases (installed-releases old-dist))) + (remove-installed "systems") + (remove-installed "releases") + (delete-file-if-exists (relative-to old-dist "releases.txt")) + (delete-file-if-exists (relative-to old-dist "systems.txt")) + (delete-file-if-exists (relative-to old-dist "releases.cdb")) + (delete-file-if-exists (relative-to old-dist "systems.cdb")) + (replace-file (local-distinfo-file new-dist) + (local-distinfo-file old-dist)) + (setf new-dist (find-dist (name new-dist))) + (dolist (old-release reinstall-releases) + (let* ((name (name old-release)) + (new-release (find-release-in-dist name new-dist))) + (if new-release + (ensure-installed new-release) + (warn "~S is not available in ~A" name new-dist))))))) + +(defun install-dist (url &key (prompt t) replace) + (block nil + (setf url (url url)) + (let ((temp-file (qmerge "tmp/install-dist-distinfo.txt"))) + (ensure-directories-exist temp-file) + (delete-file-if-exists temp-file) + (fetch url temp-file) + (let* ((new-dist (make-dist-from-file temp-file)) + (old-dist (find-dist (name new-dist)))) + (when old-dist + (if replace + (uninstall old-dist) + (restart-case + (error "A dist named ~S is already installed." + (name new-dist)) + (replace () + :report "Replace installed dist with new dist" + (uninstall old-dist))))) + (format t "Installing dist ~S version ~S.~%" + (name new-dist) + (version new-dist)) + (when (or (not prompt) + (press-enter-to-continue)) + (ensure-directories-exist (base-directory new-dist)) + (copy-file temp-file (relative-to new-dist "distinfo.txt")) + (ensure-release-index-file new-dist) + (ensure-system-index-file new-dist) + (enable new-dist) + (setf (preference new-dist) (get-universal-time)) + (when old-dist + (clear-dist-systems old-dist)) + (clear-dist-systems new-dist) + new-dist))))) diff --git a/sbcl/.quicklisp/quicklisp/dist.lisp b/sbcl/.quicklisp/quicklisp/dist.lisp new file mode 100644 index 0000000..960e2c9 --- /dev/null +++ b/sbcl/.quicklisp/quicklisp/dist.lisp @@ -0,0 +1,1168 @@ +;;;; dist.lisp + +(in-package #:ql-dist) + + +;;; Generic functions + +(defgeneric dist (object) + (:documentation + "Return the dist of OBJECT.")) + +(defgeneric available-versions (object) + (:documentation + "Return a list of version information for OBJECT.")) + +(defgeneric system-index-url (object) + (:documentation + "Return the URL for the system index of OBJECT.")) + +(defgeneric release-index-url (object) + (:documentation + "Return the URL for the release index of OBJECT.")) + +(defgeneric available-versions-url (object) + (:documentation + "Return the URL for the available versions data file of OBJECT.")) + +(defgeneric release (object) + (:documentation + "Return the release of OBJECT.")) + +(defgeneric system (object) + (:documentation + "Return the system of OBJECT.")) + +(defgeneric name (object) + (:documentation + "Return the name of OBJECT.")) + +(defgeneric find-system (name) + (:documentation + "Return a system with the given NAME, or NIL if no system is + found. If multiple systems have the same name, the one with the + highest preference is returned.")) + +(defgeneric find-release (name) + (:documentation + "Return a release with the given NAME, or NIL if no system is + found. If multiple releases have the same name, the one with the + highest preference is returned.")) + +(defgeneric find-systems-named (name) + (:documentation + "Return a list of all systems in all enabled dists with the given + NAME, sorted by preference.")) + +(defgeneric find-releases-named (name) + (:documentation + "Return a list of all releases in all enabled dists with the given + NAME, sorted by preference.")) + + +(defgeneric base-directory (object) + (:documentation + "Return the base directory pathname of OBJECT.") + (:method ((object pathname)) + (merge-pathnames object))) + +(defgeneric relative-to (object pathname) + (:documentation + "Merge PATHNAME with the base-directory of OBJECT.") + (:method (object pathname) + (merge-pathnames pathname (base-directory object)))) + + +(defgeneric enabledp (object) + (:documentation + "Return true if OBJECT is enabled.")) + +(defgeneric enable (object) + (:documentation + "Enable OBJECT.")) + +(defgeneric disable (object) + (:documentation + "Disable OBJECT.")) + +(defgeneric installedp (object) + (:documentation + "Return true if OBJECT is installed.")) + +(defgeneric install (object) + (:documentation + "Install OBJECT.")) + +(defgeneric ensure-installed (object) + (:documentation + "Ensure that OBJECT is installed.") + (:method (object) + (unless (installedp object) + (install object)) + object)) + +(defgeneric uninstall (object) + (:documentation + "Uninstall OBJECT.")) + +(defgeneric metadata-name (object) + (:documentation + "The metadata-name of an object is used to form the pathname for a + few different object metadata files.")) + +(defgeneric install-metadata-file (object) + (:documentation + "The pathname to a file describing the installation status of + OBJECT.")) + +(defgeneric subscription-inhibition-file (object) + (:documentation "The file whose presence indicates the inhibited + subscription status of OBJECT.") + (:method (object) + (relative-to object "subscription-inhibited.txt"))) + +(defgeneric inhibit-subscription (object) + (:documentation "Inhibit subscription for OBJECT.") + (:method (object) + (ensure-file-exists (subscription-inhibition-file object)))) + +(defgeneric uninhibit-subscription (object) + (:documentation "Remove inhibition of subscription for OBJECT.") + (:method (object) + (delete-file-if-exists (subscription-inhibition-file object)))) + +(defgeneric subscription-inhibited-p (object) + (:documentation "Return T if subscription to OBJECT is inhibited.") + (:method (object) + (not (not (probe-file (subscription-inhibition-file object)))))) + +(define-condition subscription-unavailable (error) + ((object + :initarg :object + :reader subscription-unavailable-object))) + +(defgeneric subscribedp (object) + (:documentation "Return true if OBJECT is subscribed to updates.")) + +(defgeneric subscribe (object) + (:documentation "Subscribe to updates of OBJECT, if possible. If no + updates are available, a condition of type SUBSCRIPTION-UNAVAILABLE + is raised.") + (:method (object) + (uninhibit-subscription object) + (unless (subscribedp object) + (error 'subscription-unavailable + :object object)) + t)) + +(defgeneric unsubscribe (object) + (:documentation "Unsubscribe from updates to OBJECT.") + (:method (object) + (inhibit-subscription object))) + + +(defgeneric preference-parent (object) + (:documentation + "Return a value suitable for checking if OBJECT has no specific + preference set.") + (:method (object) + (declare (ignore object)) + nil)) + +(defgeneric preference-file (object) + (:documentation + "Return the file from which preference information is loaded for + OBJECT.") + (:method (object) + (relative-to object "preference.txt"))) + +(defgeneric preference (object) + (:documentation + "Returns a value used when comparing multiple systems or releases + with the same name. Objects with higher preference are returned by + FIND-SYSTEM and FIND-RELEASE.") + (:method ((object null)) + 0) + (:method (object) + (with-open-file (stream (preference-file object) + :if-does-not-exist nil) + (if stream + (values (parse-integer (read-line stream))) + (preference (preference-parent object)))))) + +(defgeneric (setf preference) (preference object) + (:documentation + "Set the preference for OBJECT. Objects with higher preference are + returned by FIND-SYSTEM and FIND-RELEASE.") + (:method (preference object) + (check-type preference integer) + (let ((preference-file (preference-file object))) + (ensure-directories-exist preference-file) + (with-open-file (stream (preference-file object) + :direction :output + :if-exists :supersede) + (format stream "~D" preference))) + preference)) + +(defgeneric forget-preference (object) + (:documentation + "Remove specific preference information for OBJECT.") + (:method (object) + (delete-file-if-exists (preference-file object)))) + +(defgeneric short-description (object) + (:documentation "Return a short string describing OBJECT.")) + + +(defgeneric provided-releases (object) + (:documentation "Return a list of releases provided by OBJECT.")) + +(defgeneric provided-systems (object) + (:documentation "Return a list of systems provided by OBJECT.")) + +(defgeneric installed-releases (dist) + (:documentation + "Return a list of all releases installed for DIST.") + (:method (dist) + (remove-if-not #'installedp (provided-releases dist)))) + +(defgeneric installed-systems (dist) + (:documentation + "Return a list of all systems installed for DIST.") + (:method (dist) + (remove-if-not #'installedp (provided-systems dist)))) + +(defgeneric new-version-available-p (dist) + (:documentation + "Return true if a new version of DIST is available.")) + +(defgeneric find-system-in-dist (system-name dist) + (:documentation + "Return a system with the given NAME in DIST, or NIL if no system + is found.")) + +(defgeneric find-release-in-dist (release-name dist) + (:documentation + "Return a release with the given NAME in DIST, or NIL if no release + is found.")) + + +(defgeneric ensure-system-index-file (dist) + (:documentation + "Return the pathname for the system index file of DIST, fetching it + from a remote source first if necessary.")) + +(defgeneric ensure-system-cdb-file (dist) + (:documentation + "Return the pathname for the system cdb file of DIST, creating it + if necessary.")) + +(defgeneric ensure-release-index-file (dist) + (:documentation + "Return the pathname for the release index file of DIST, fetching + it from a remote source first if necessary.")) + +(defgeneric ensure-release-cdb-file (dist) + (:documentation + "Return the pathname for the release cdb file of DIST, creating it + if necessary.")) + + +(defgeneric initialize-release-index (dist) + (:documentation + "Initialize the release index of DIST.")) + +(defgeneric initialize-system-index (dist) + (:documentation + "Initialize the system index of DIST.")) + + +(defgeneric local-archive-file (release) + (:documentation + "Return the pathname to where the archive file of RELEASE should be + stored.")) + +(defgeneric ensure-local-archive-file (release) + (:documentation + "If the archive file for RELEASE is not available locally, fetch it + and return the pathname to it.")) + +(defgeneric check-local-archive-file (release) + (:documentation + "Check the local archive file of RELEASE for validity, including + size and signature checks. Signals errors in the case of invalid files.")) + + +(defgeneric archive-url (release) + (:documentation + "Return the full URL for fetching the archive file of RELEASE.")) + +(defgeneric installed-asdf-system-file (object) + (:documentation + "Return the path to the installed ASDF system file for OBJECT, or + NIL if there is no installed system file.")) + + + + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defmacro destructure-line (lambda-list line &body body) + `(destructuring-bind ,lambda-list + (split-spaces ,line) + ,@body)) + + (defun call-for-each-line (fun file) + (with-open-file (stream file) + (loop for line = (read-line stream nil) + while line do (funcall fun line)))) + + (defmacro for-each-line ((line file) &body body) + `(call-for-each-line (lambda (,line) ,@body) ,file))) + +(defun make-line-instance (line class &rest initargs) + "Create an instance from words in an index file line. The last initarg collects all the trailing arguments, if any." + (let* ((words (split-spaces line)) + (args (mapcan #'list + (butlast initargs) + words)) + (trailing (subseq words (1- (length initargs))))) + (apply #'make-instance class (first (last initargs)) trailing args))) + +(defun ignorable-line (line) + (labels ((blank-char-p (char) + (member char '(#\Space #\Tab))) + (blankp (line) + (every #'blank-char-p line)) + (ignorable (line) + (or (zerop (length line)) + (blankp line) + (eql (char line 0) #\#)))) + (ignorable line))) + +(defvar *initarg-case-converter* + (cond ((string= :string "string") + #'string-downcase) + ((string= :string "STRING") + #'string-upcase))) + +(defun config-file-initargs (file) + (flet ((initarg-keyword (string) + ;; A concession to mlisp + (intern (funcall *initarg-case-converter* string) + 'keyword))) + (let ((initargs '())) + (for-each-line (line file) + (unless (ignorable-line line) + (destructure-line (initarg value) + line + (let ((keyword (initarg-keyword (string-right-trim ":" initarg)))) + (push value initargs) + (push keyword initargs))))) + initargs))) + +;;; +;;; A few generic things +;;; + +(defmethod dist ((name symbol)) + (dist (string name))) + +(defmethod dist ((name string)) + (find-dist (string-downcase name))) + +(defmethod release ((name symbol)) + (release (string name))) + +(defmethod release ((name string)) + (find-release (string-downcase name))) + +(defmethod system ((name symbol)) + (system (string name))) + +(defmethod system ((name string)) + (find-system (string-downcase name))) + +;;; +;;; Dists +;;; +;;; A dist is a set of releases. +;;; + +(defclass dist () + ((base-directory + :initarg :base-directory + :accessor base-directory) + (name + :initarg :name + :accessor name) + (version + :initarg :version + :accessor version) + (system-index-url + :initarg :system-index-url + :accessor system-index-url) + (release-index-url + :initarg :release-index-url + :accessor release-index-url) + (available-versions-url + :initarg :available-versions-url + :accessor available-versions-url) + (archive-base-url + :initarg :archive-base-url + :accessor archive-base-url) + (canonical-distinfo-url + :initarg :canonical-distinfo-url + :accessor canonical-distinfo-url) + (distinfo-subscription-url + :initarg :distinfo-subscription-url + :accessor distinfo-subscription-url) + (system-index + :initarg :system-index + :accessor system-index) + (release-index + :initarg :release-index + :accessor release-index) + (provided-systems + :initarg :provided-systems + :accessor provided-systems) + (provided-releases + :initarg :provided-releases + :accessor provided-releases) + (local-distinfo-file + :initarg :local-distinfo-file + :accessor local-distinfo-file)) + (:default-initargs + :name "unnamed" + :version "unknown" + :distinfo-subscription-url nil)) + +(defmethod short-description ((dist dist)) + (format nil "~A ~A" (name dist) (version dist))) + +(defmethod print-object ((dist dist) stream) + (print-unreadable-object (dist stream :type t) + (write-string (short-description dist) stream))) + +(defun cdb-lookup (dist key cdb) + (ql-cdb:lookup key + (relative-to dist cdb))) + +(defmethod slot-unbound (class (dist dist) (slot (eql 'available-versions-url))) + (declare (ignore class)) + (setf (available-versions-url dist) + (make-versions-url (distinfo-subscription-url dist)))) + + +(defmethod ensure-system-index-file ((dist dist)) + (let ((pathname (relative-to dist "systems.txt"))) + (or (probe-file pathname) + (nth-value 1 (fetch (system-index-url dist) pathname))))) + +(defmethod ensure-system-cdb-file ((dist dist)) + (let* ((system-file (ensure-system-index-file dist)) + (cdb-file (make-pathname :type "cdb" :defaults system-file))) + (or (probe-file cdb-file) + (ql-cdb:convert-index-file system-file + :cdb-file cdb-file + :index 2)))) + +(defmethod ensure-release-index-file ((dist dist)) + (let ((pathname (relative-to dist "releases.txt"))) + (or (probe-file pathname) + (nth-value 1 (fetch (release-index-url dist) pathname))))) + +(defmethod ensure-release-cdb-file ((dist dist)) + (let* ((release-file (ensure-release-index-file dist)) + (cdb-file (make-pathname :type "cdb" :defaults release-file))) + (or (probe-file cdb-file) + (ql-cdb:convert-index-file release-file + :cdb-file cdb-file + :index 0)))) + +(defmethod slot-unbound (class (dist dist) (slot (eql 'provided-systems))) + (declare (ignore class)) + (initialize-system-index dist) + (setf (slot-value dist 'provided-systems) + (loop for system being each hash-value of (system-index dist) + collect system))) + +(defmethod slot-unbound (class (dist dist) (slot (eql 'provided-releases))) + (declare (ignore class)) + (initialize-release-index dist) + (setf (slot-value dist 'provided-releases) + (loop for system being each hash-value of (release-index dist) + collect system))) + + +(defun dist-name-pathname (name) + "Return the pathname that would be used for an installed dist with +the given NAME." + (qmerge (make-pathname :directory (list :relative "dists" name)))) + +(defmethod slot-unbound (class (dist dist) (slot (eql 'base-directory))) + (declare (ignore class)) + (setf (base-directory dist) (dist-name-pathname (name dist)))) + +(defun make-dist-from-file (file &key (class 'dist)) + "Load dist info from FILE and use it to create a dist instance." + (let ((initargs (config-file-initargs file))) + (apply #'make-instance class + :local-distinfo-file file + :allow-other-keys t + initargs))) + +(defmethod install-metadata-file ((dist dist)) + (relative-to dist "distinfo.txt")) + +(defun find-dist (name) + (find name (all-dists) + :key #'name + :test #'string=)) + +(defmethod enabledp ((dist dist)) + (not (not (probe-file (relative-to dist "enabled.txt"))))) + +(defmethod enable ((dist dist)) + (ensure-file-exists (relative-to dist "enabled.txt")) + t) + +(defmethod disable ((dist dist)) + (delete-file-if-exists (relative-to dist "enabled.txt")) + t) + +(defmethod installedp ((dist dist)) + (let ((installed (find-dist (name dist)))) + (equalp (version installed) (version dist)))) + +(defmethod uninstall ((dist dist)) + (when (installedp dist) + (dolist (system (provided-systems dist)) + (asdf:clear-system (name system))) + (ql-impl-util:delete-directory-tree (base-directory dist)) + t)) + + +(defun make-release-from-line (line dist) + (let ((release + (make-line-instance line 'release + :project-name + :archive-url + :archive-size + :archive-md5 + :archive-content-sha1 + :prefix + :system-files))) + (setf (dist release) dist) + (setf (archive-size release) + (parse-integer (archive-size release))) + release)) + +(defmethod find-release-in-dist (release-name (dist dist)) + (let* ((index (release-index dist)) + (release (gethash release-name index))) + (or release + (let ((line (cdb-lookup dist release-name + (ensure-release-cdb-file dist)))) + (when line + (setf (gethash release-name index) + (make-release-from-line line dist))))))) + + +(defparameter *dist-enumeration-functions* + '(standard-dist-enumeration-function) + "ALL-DISTS calls each function in this list with no arguments, and + appends the results into a list of dist objects, removing + duplicates. Functions might be called just once for a batch of + related operations; see WITH-CONSISTENT-DISTS.") + +(defun standard-dist-enumeration-function () + "The default function used for producing a list of dist objects." + (loop for file in (directory (qmerge "dists/*/distinfo.txt")) + collect (make-dist-from-file file))) + +(defun all-dists () + "Return a list of all known dists." + (remove-duplicates + (apply 'append (mapcar 'funcall *dist-enumeration-functions*)))) + +(defun enabled-dists () + "Return a list of all known dists for which ENABLEDP returns true." + (remove-if-not #'enabledp (all-dists))) + + +(defmethod install-metadata-file (object) + (relative-to (dist object) + (make-pathname :directory + (list :relative "installed" + (metadata-name object)) + :name (name object) + :type "txt"))) + + +(defclass preference-mixin () () + (:documentation + "Instances of this class have a special location for their + preference files.")) + +(defgeneric filesystem-name (object) + (:method (object) + ;; This is to work around system names like "foo/bar". + (let* ((name (name object)) + (slash (position #\/ name))) + (if slash + (subseq name 0 slash) + name)))) + +(defmethod preference-file ((object preference-mixin)) + (relative-to + (dist object) + (make-pathname :directory (list :relative + "preferences" + (metadata-name object)) + :name (filesystem-name object) + :type "txt"))) + +(defmethod distinfo-subscription-url :around ((dist dist)) + (unless (subscription-inhibited-p dist) + (call-next-method))) + +(defmethod subscribedp ((dist dist)) + (distinfo-subscription-url dist)) + +;;; +;;; Releases +;;; + +(defclass release (preference-mixin) + ((project-name + :initarg :project-name + :accessor name + :accessor project-name) + (dist + :initarg :dist + :accessor dist + :reader preference-parent) + (provided-systems + :initarg :provided-systems + :accessor provided-systems) + (archive-url + :initarg :archive-url + :accessor archive-url) + (archive-size + :initarg :archive-size + :accessor archive-size) + (archive-md5 + :initarg :archive-md5 + :accessor archive-md5) + (archive-content-sha1 + :initarg :archive-content-sha1 + :accessor archive-content-sha1) + (prefix + :initarg :prefix + :accessor prefix + :reader short-description) + (system-files + :initarg :system-files + :accessor system-files) + (metadata-name + :initarg :metadata-name + :accessor metadata-name)) + (:default-initargs + :metadata-name "releases") + (:documentation + "Instances of this class represent a snapshot of a project at some + point in time, which might be from version control, or from an + official release, or from some other source.")) + +(defmethod print-object ((release release) stream) + (print-unreadable-object (release stream :type t) + (format stream "~A / ~A" + (short-description release) + (short-description (dist release))))) + +(define-condition invalid-local-archive (error) + ((release + :initarg :release + :reader invalid-local-archive-release) + (file + :initarg :file + :reader invalid-local-archive-file)) + (:report + (lambda (condition stream) + (format stream "The archive file ~S for release ~S is invalid" + (file-namestring (invalid-local-archive-file condition)) + (name (invalid-local-archive-release condition)))))) + +(define-condition missing-local-archive (invalid-local-archive) + () + (:report + (lambda (condition stream) + (format stream "The archive file ~S for release ~S is missing" + (file-namestring (invalid-local-archive-file condition)) + (name (invalid-local-archive-release condition)))))) + +(define-condition badly-sized-local-archive (invalid-local-archive) + ((expected-size + :initarg :expected-size + :reader badly-sized-local-archive-expected-size) + (actual-size + :initarg :actual-size + :reader badly-sized-local-archive-actual-size)) + (:report + (lambda (condition stream) + (format stream "The archive file ~S for ~S is the wrong size: ~ + expected ~:D, got ~:D" + (file-namestring (invalid-local-archive-file condition)) + (name (invalid-local-archive-release condition)) + (badly-sized-local-archive-expected-size condition) + (badly-sized-local-archive-actual-size condition))))) + +(defmethod check-local-archive-file ((release release)) + (let ((file (local-archive-file release))) + (unless (probe-file file) + (error 'missing-local-archive + :file file + :release release)) + (let ((actual-size (file-size file)) + (expected-size (archive-size release))) + (unless (= actual-size expected-size) + (error 'badly-sized-local-archive + :file file + :release release + :actual-size actual-size + :expected-size expected-size))))) + +(defmethod local-archive-file ((release release)) + (relative-to (dist release) + (make-pathname :directory '(:relative "archives") + :defaults (file-namestring + (path (url (archive-url release))))))) + +(defmethod ensure-local-archive-file ((release release)) + (let ((pathname (local-archive-file release))) + (tagbody + :retry + (or (probe-file pathname) + (progn + (ensure-directories-exist pathname) + (fetch (archive-url release) pathname))) + (restart-case + (check-local-archive-file release) + (delete-and-retry (&optional v) + :report "Delete the archive file and fetch it again" + (declare (ignore v)) + (delete-file pathname) + (go :retry)))) + pathname)) + + +(defmethod base-directory ((release release)) + (relative-to + (dist release) + (make-pathname :directory (list :relative "software" (prefix release))))) + +(defmethod installedp ((release release)) + (and (probe-file (install-metadata-file release)) + (every #'installedp (provided-systems release)))) + +(defmethod install ((release release)) + (let ((archive (ensure-local-archive-file release)) + (tar (qmerge "tmp/release-install.tar")) + (output (relative-to (dist release) + (make-pathname :directory + (list :relative "software")))) + (tracking (install-metadata-file release))) + (ensure-directories-exist tar) + (ensure-directories-exist output) + (ensure-directories-exist tracking) + (gunzip archive tar) + (unpack-tarball tar :directory output) + (ensure-directories-exist tracking) + (with-open-file (stream tracking + :direction :output + :if-exists :supersede) + (write-line (qenough (base-directory release)) stream)) + (let ((provided (provided-systems release)) + (dist (dist release))) + (dolist (file (system-files release)) + (let ((system (find-system-in-dist (pathname-name file) dist))) + (unless (member system provided) + (error "FIND-SYSTEM-IN-DIST returned ~A but I expected one of ~A" + system provided)) + (let ((system-tracking (install-metadata-file system)) + (system-file (merge-pathnames file + (base-directory release)))) + (ensure-directories-exist system-tracking) + (unless (probe-file system-file) + (error "Release claims to have ~A, but I can't find it" + system-file)) + (with-open-file (stream system-tracking + :direction :output + :if-exists :supersede) + (write-line (qenough system-file) + stream)))))) + release)) + +(defmethod uninstall ((release release)) + (when (installedp release) + (dolist (system (installed-systems release)) + (asdf:clear-system (name system)) + (delete-file (install-metadata-file system))) + (delete-file (install-metadata-file release)) + (delete-file (local-archive-file release)) + (ql-impl-util:delete-directory-tree (base-directory release)) + t)) + + +(defun call-for-each-index-entry (file fun) + (labels ((blank-char-p (char) + (member char '(#\Space #\Tab))) + (blankp (line) + (every #'blank-char-p line)) + (ignorable (line) + (or (zerop (length line)) + (blankp line) + (eql (char line 0) #\#)))) + (with-open-file (stream file) + (loop for line = (read-line stream nil) + while line do + (unless (ignorable line) + (funcall fun line)))))) + +(defmethod slot-unbound (class (dist dist) (slot (eql 'release-index))) + (declare (ignore class)) + (setf (slot-value dist 'release-index) + (make-hash-table :test 'equal))) + + +;;; +;;; Systems +;;; +;;; A "system" in the defsystem sense. +;;; + +(defclass system (preference-mixin) + ((name + :initarg :name + :accessor name + :reader short-description) + (system-file-name + :initarg :system-file-name + :accessor system-file-name) + (release + :initarg :release + :accessor release + :reader preference-parent) + (dist + :initarg :dist + :accessor dist) + (required-systems + :initarg :required-systems + :accessor required-systems) + (metadata-name + :initarg :metadata-name + :accessor metadata-name)) + (:default-initargs + :metadata-name "systems")) + +(defmethod print-object ((system system) stream) + (print-unreadable-object (system stream :type t) + (format stream "~A / ~A / ~A" + (short-description system) + (short-description (release system)) + (short-description (dist system))))) + +(defmethod provided-systems ((system system)) + (list system)) + +(defmethod initialize-release-index ((dist dist)) + (let ((releases (ensure-release-index-file dist)) + (index (release-index dist))) + (call-for-each-index-entry + releases + (lambda (line) + (let ((instance (make-line-instance line 'release + :project-name + :archive-url + :archive-size + :archive-md5 + :archive-content-sha1 + :prefix + :system-files))) + ;; Don't clobber anything previously loaded via CDB + (unless (gethash (project-name instance) index) + (setf (dist instance) dist) + (setf (archive-size instance) + (parse-integer (archive-size instance))) + (setf (gethash (project-name instance) index) instance))))) + (setf (release-index dist) index))) + +(defmethod initialize-system-index ((dist dist)) + (initialize-release-index dist) + (let ((systems (ensure-system-index-file dist)) + (index (system-index dist))) + (call-for-each-index-entry + systems + (lambda (line) + (let ((instance (make-line-instance line 'system + :release + :system-file-name + :name + :required-systems))) + ;; Don't clobber anything previously loaded via CDB + (unless (gethash (name instance) index) + (let ((release (find-release-in-dist (release instance) dist))) + (setf (release instance) release) + (if (slot-boundp release 'provided-systems) + (pushnew instance (provided-systems release)) + (setf (provided-systems release) (list instance)))) + (setf (dist instance) dist) + (setf (gethash (name instance) index) instance))))) + (setf (system-index dist) index))) + +(defmethod slot-unbound (class (release release) (slot (eql 'provided-systems))) + (declare (ignore class)) + ;; FIXME: This isn't right, since the system index has systems that + ;; don't match the defining system file name. + (setf (slot-value release 'provided-systems) + (mapcar (lambda (system-file) + (find-system-in-dist (pathname-name system-file) + (dist release))) + (system-files release)))) + +(defmethod slot-unbound (class (dist dist) (slot (eql 'system-index))) + (declare (ignore class)) + (setf (slot-value dist 'system-index) + (make-hash-table :test 'equal))) + +(defun make-system-from-line (line dist) + (let ((system (make-line-instance line 'system + :release + :system-file-name + :name + :required-systems))) + (setf (dist system) dist) + (setf (release system) + (find-release-in-dist (release system) dist)) + system)) + +(defmethod find-system-in-dist (system-name (dist dist)) + (let* ((index (system-index dist)) + (system (gethash system-name index))) + (or system + (let ((line (cdb-lookup dist system-name + (ensure-system-cdb-file dist)))) + (when line + (setf (gethash system-name index) + (make-system-from-line line dist))))))) + +(defmethod preference ((system system)) + (if (probe-file (preference-file system)) + (call-next-method) + (preference (release system)))) + +(defun thing-name-designator (designator) + "Convert DESIGNATOR to a string naming a thing. Strings are used + as-is, symbols are converted to their downcased symbol-name." + (typecase designator + (string designator) + (symbol (string-downcase designator)) + (t + (error "~S is not a valid designator for a system or release" + designator)))) + +(defun find-thing-named (find-fun name) + (setf name (thing-name-designator name)) + (let ((result '())) + (dolist (dist (enabled-dists) (sort result #'> :key #'preference)) + (let ((thing (funcall find-fun name dist))) + (when thing + (push thing result)))))) + +(defmethod find-systems-named (name) + (find-thing-named #'find-system-in-dist name)) + +(defmethod find-releases-named (name) + (find-thing-named #'find-release-in-dist name)) + +(defmethod find-system (name) + (first (find-systems-named name))) + +(defmethod find-release (name) + (first (find-releases-named name))) + +(defmethod install ((system system)) + (ensure-installed (release system))) + + +(defmethod install-metadata-file ((system system)) + (relative-to (dist system) + (make-pathname :name (system-file-name system) + :type "txt" + :directory '(:relative "installed" "systems")))) + +(defmethod installed-asdf-system-file ((system system)) + (let ((metadata-file (install-metadata-file system))) + (when (probe-file metadata-file) + (with-open-file (stream metadata-file) + (let* ((relative (read-line stream)) + (full (qmerge relative))) + (when (probe-file full) + full)))))) + +(defmethod installedp ((system system)) + (installed-asdf-system-file system)) + +(defmethod uninstall ((system system)) + (uninstall (release system))) + +(defun find-asdf-system-file (name) + "Return the ASDF system file in which the system named NAME is defined." + (let ((system (find-system name))) + (when system + (installed-asdf-system-file system)))) + +(defun system-definition-searcher (name) + "Like FIND-ASDF-SYSTEM-FILE, but this function can be used in +ASDF:*SYSTEM-DEFINITION-SEARCH-FUNCTIONS*; it will only return system +file names if they match NAME." + (let ((system-file (find-asdf-system-file name))) + (when (and system-file + (string= (pathname-name system-file) name)) + system-file))) + +(defun call-with-consistent-dists (fun) + "Take a snapshot of the available dists and return the same list +consistently each time ALL-DISTS is called in the dynamic scope of +FUN." + (let* ((all-dists (all-dists)) + (*dist-enumeration-functions* (list (constantly all-dists)))) + (funcall fun))) + +(defmacro with-consistent-dists (&body body) + "See CALL-WITH-CONSISTENT-DISTS." + `(call-with-consistent-dists (lambda () ,@body))) + + +(defgeneric dependency-tree (system) + (:method ((symbol symbol)) + (dependency-tree (string-downcase symbol))) + (:method ((string string)) + (let ((system (find-system string))) + (when system + (dependency-tree system)))) + (:method ((system system)) + (with-consistent-dists + (list* system + (remove nil + (mapcar 'dependency-tree (required-systems system))))))) + +(defmethod provided-systems ((object (eql t))) + (let ((systems (loop for dist in (enabled-dists) + appending (provided-systems dist)))) + (sort systems #'string< :key #'name))) + +(defmethod provided-releases ((object (eql t))) + (let ((releases (loop for dist in (enabled-dists) + appending (provided-releases dist)))) + (sort releases #'string< :key #'name))) + + +(defgeneric system-apropos-list (term) + (:method ((term symbol)) + (system-apropos-list (symbol-name term))) + (:method ((term string)) + (setf term (string-downcase term)) + (let ((result '())) + (dolist (system (provided-systems t) (nreverse result)) + (when (or (search term (name system)) + (search term (name (release system)))) + (push system result)))))) + +(defgeneric system-apropos (term) + (:method (term) + (map nil (lambda (system) + (format t "~A~%" system)) + (system-apropos-list term)) + (values))) + + +;;; +;;; Clean up things +;;; + +(defgeneric clean (object) + (:documentation "Remove any unneeded files or directories related to + OBJECT.")) + +(defmethod clean ((dist dist)) + (let* ((releases (provided-releases dist)) + (known-archives (mapcar 'local-archive-file releases)) + (known-directories (mapcar 'base-directory releases)) + (present-archives (mapcar 'truename + (directory-entries + (relative-to dist "archives/")))) + (present-directories (mapcar 'truename + (directory-entries + (relative-to dist "software/")))) + (garbage-archives + (set-difference present-archives known-archives + :test 'equalp)) + (garbage-directories + ;; Use the namestring here on the theory that pathnames with + ;; equalp namestrings are sufficiently the same. On + ;; LispWorks, for example, identical namestrings can still + ;; differ in :name, :type, and more. + (set-difference present-directories known-directories + :test 'equalp + :key 'namestring))) + (map nil 'delete-file garbage-archives) + (map nil 'delete-directory-tree garbage-directories))) + + +;;; +;;; Available versions +;;; + +(defmethod available-versions ((dist dist)) + (let ((temp (qmerge "tmp/dist-versions.txt")) + (versions '()) + (url (available-versions-url dist))) + (when url + (ensure-directories-exist temp) + (delete-file-if-exists temp) + (handler-case + (fetch url temp) + (unexpected-http-status () + (return-from available-versions nil))) + (with-open-file (stream temp) + (loop for line = (read-line stream nil) + while line do + (destructuring-bind (version url) + (split-spaces line) + (setf versions (acons version url versions))))) + versions))) + + +;;; +;;; User interface bits to re-export from QL +;;; + +(define-condition unknown-dist (error) + ((name + :initarg :name + :reader unknown-dist-name)) + (:report (lambda (condition stream) + (format stream "No dist known by that name -- ~S" + (unknown-dist-name condition))))) + +(defun find-dist-or-lose (name) + (let ((dist (find-dist name))) + (or dist + (error 'unknown-dist :name name)))) + +(defun dist-url (name) + (canonical-distinfo-url (find-dist-or-lose name))) + +(defun dist-version (name) + (version (find-dist-or-lose name))) diff --git a/sbcl/.quicklisp/quicklisp/fetch-gzipped.lisp b/sbcl/.quicklisp/quicklisp/fetch-gzipped.lisp new file mode 100644 index 0000000..b453803 --- /dev/null +++ b/sbcl/.quicklisp/quicklisp/fetch-gzipped.lisp @@ -0,0 +1,29 @@ +;;;; fetch-gzipped.lisp + +(in-package #:quicklisp-client) + +(defun gzipped-url (url) + (check-type url string) + (concatenate 'string url ".gz")) + +(defun fetch-gzipped-version (url file &key quietly) + (let ((gzipped (gzipped-url url)) + (gzipped-temp (merge-pathnames "gzipped.tmp" file))) + (fetch gzipped gzipped-temp :quietly quietly) + (gunzip gzipped-temp file) + (delete-file-if-exists gzipped-temp) + (probe-file file))) + +(defun url-not-suitable-error-p (condition) + (<= 400 (unexpected-http-status-code condition) 499)) + +(defun maybe-fetch-gzipped (url file &key quietly) + (handler-case + (fetch-gzipped-version url file :quietly quietly) + (unexpected-http-status (condition) + (cond ((url-not-suitable-error-p condition) + (fetch url file :quietly quietly) + (probe-file file)) + (t + (error condition)))))) + diff --git a/sbcl/.quicklisp/quicklisp/http.lisp b/sbcl/.quicklisp/quicklisp/http.lisp new file mode 100644 index 0000000..d942fb8 --- /dev/null +++ b/sbcl/.quicklisp/quicklisp/http.lisp @@ -0,0 +1,859 @@ +;;; +;;; A simple HTTP client +;;; + +(in-package #:ql-http) + +;;; Octet data + +(deftype octet () + '(unsigned-byte 8)) + +(defun make-octet-vector (size) + (make-array size :element-type 'octet + :initial-element 0)) + +(defun octet-vector (&rest octets) + (make-array (length octets) :element-type 'octet + :initial-contents octets)) + +;;; ASCII characters as integers + +(defun acode (char) + (cond ((eql char :cr) + 13) + ((eql char :lf) + 10) + (t + (let ((code (char-code char))) + (if (<= 0 code 127) + code + (error "Character ~S is not in the ASCII character set" + char)))))) + +(defvar *whitespace* + (list (acode #\Space) (acode #\Tab) (acode :cr) (acode :lf))) + +(defun whitep (code) + (member code *whitespace*)) + +(defun ascii-vector (string) + (let ((vector (make-octet-vector (length string)))) + (loop for char across string + for code = (char-code char) + for i from 0 + if (< 127 code) do + (error "Invalid character for ASCII -- ~A" char) + else + do (setf (aref vector i) code)) + vector)) + +(defun ascii-subseq (vector start end) + "Return a subseq of octet-specialized VECTOR as a string." + (let ((string (make-string (- end start)))) + (loop for i from 0 + for j from start below end + do (setf (char string i) (code-char (aref vector j)))) + string)) + +(defun ascii-downcase (code) + (if (<= 65 code 90) + (+ code 32) + code)) + +(defun ascii-equal (a b) + (eql (ascii-downcase a) (ascii-downcase b))) + +(defmacro acase (value &body cases) + (flet ((convert-case-keys (keys) + (mapcar (lambda (key) + (etypecase key + (integer key) + (character (char-code key)) + (symbol + (ecase key + (:cr 13) + (:lf 10) + ((t) t))))) + (if (consp keys) keys (list keys))))) + `(case ,value + ,@(mapcar (lambda (case) + (destructuring-bind (keys &rest body) + case + `(,(if (eql keys t) + t + (convert-case-keys keys)) + ,@body))) + cases)))) + +;;; Pattern matching (for finding headers) + +(defclass matcher () + ((pattern + :initarg :pattern + :reader pattern) + (pos + :initform 0 + :accessor match-pos) + (matchedp + :initform nil + :accessor matchedp))) + +(defun reset-match (matcher) + (setf (match-pos matcher) 0 + (matchedp matcher) nil)) + +(define-condition match-failure (error) ()) + +(defun match (matcher input &key (start 0) end error) + (let ((i start) + (end (or end (length input))) + (match-end (length (pattern matcher)))) + (with-slots (pattern pos) + matcher + (loop + (cond ((= pos match-end) + (let ((match-start (- i pos))) + (setf pos 0) + (setf (matchedp matcher) t) + (return (values match-start (+ match-start match-end))))) + ((= i end) + (return nil)) + ((= (aref pattern pos) + (aref input i)) + (incf i) + (incf pos)) + (t + (if error + (error 'match-failure) + (if (zerop pos) + (incf i) + (setf pos 0))))))))) + +(defun ascii-matcher (string) + (make-instance 'matcher + :pattern (ascii-vector string))) + +(defun octet-matcher (&rest octets) + (make-instance 'matcher + :pattern (apply 'octet-vector octets))) + +(defun acode-matcher (&rest codes) + (make-instance 'matcher + :pattern (make-array (length codes) + :element-type 'octet + :initial-contents + (mapcar 'acode codes)))) + + +;;; "Connection Buffers" are a kind of callback-driven, +;;; pattern-matching chunky stream. Callbacks can be called for a +;;; certain number of octets or until one or more patterns are seen in +;;; the input. cbufs automatically refill themselves from a +;;; connection as needed. + +(defvar *cbuf-buffer-size* 8192) + +(define-condition end-of-data (error) ()) + +(defclass cbuf () + ((data + :initarg :data + :accessor data) + (connection + :initarg :connection + :accessor connection) + (start + :initarg :start + :accessor start) + (end + :initarg :end + :accessor end) + (eofp + :initarg :eofp + :accessor eofp)) + (:default-initargs + :data (make-octet-vector *cbuf-buffer-size*) + :connection nil + :start 0 + :end 0 + :eofp nil) + (:documentation "A CBUF is a connection buffer that keeps track of + incoming data from a connection. Several functions make it easy to + treat a CBUF as a kind of chunky, callback-driven stream.")) + +(define-condition cbuf-progress () + ((size + :initarg :size + :accessor cbuf-progress-size + :initform 0))) + +(defun call-processor (fun cbuf start end) + (signal 'cbuf-progress :size (- end start)) + (funcall fun (data cbuf) start end)) + +(defun make-cbuf (connection) + (make-instance 'cbuf :connection connection)) + +(defun make-stream-writer (stream) + "Create a callback for writing data to STREAM." + (lambda (data start end) + (write-sequence data stream :start start :end end))) + +(defgeneric size (cbuf) + (:method ((cbuf cbuf)) + (- (end cbuf) (start cbuf)))) + +(defgeneric emptyp (cbuf) + (:method ((cbuf cbuf)) + (zerop (size cbuf)))) + +(defgeneric refill (cbuf) + (:method ((cbuf cbuf)) + (when (eofp cbuf) + (error 'end-of-data)) + (setf (start cbuf) 0) + (setf (end cbuf) + (read-octets (data cbuf) + (connection cbuf))) + (cond ((emptyp cbuf) + (setf (eofp cbuf) t) + (error 'end-of-data)) + (t (size cbuf))))) + +(defun process-all (fun cbuf) + (unless (emptyp cbuf) + (call-processor fun cbuf (start cbuf) (end cbuf)))) + +(defun multi-cmatch (matchers cbuf) + (let (start end) + (dolist (matcher matchers (values start end)) + (multiple-value-bind (s e) + (match matcher (data cbuf) + :start (start cbuf) + :end (end cbuf)) + (when (and s (or (null start) (< s start))) + (setf start s + end e)))))) + +(defun cmatch (matcher cbuf) + (if (consp matcher) + (multi-cmatch matcher cbuf) + (match matcher (data cbuf) :start (start cbuf) :end (end cbuf)))) + +(defun call-until-end (fun cbuf) + (handler-case + (loop + (process-all fun cbuf) + (refill cbuf)) + (end-of-data () + (return-from call-until-end)))) + +(defun show-cbuf (context cbuf) + (format t "cbuf: ~A ~D - ~D~%" context (start cbuf) (end cbuf))) + +(defun call-for-n-octets (n fun cbuf) + (let ((remaining n)) + (loop + (when (<= remaining (size cbuf)) + (let ((end (+ (start cbuf) remaining))) + (call-processor fun cbuf (start cbuf) end) + (setf (start cbuf) end) + (return))) + (process-all fun cbuf) + (decf remaining (size cbuf)) + (refill cbuf)))) + +(defun call-until-matching (matcher fun cbuf) + (loop + (multiple-value-bind (start end) + (cmatch matcher cbuf) + (when start + (call-processor fun cbuf (start cbuf) end) + (setf (start cbuf) end) + (return))) + (process-all fun cbuf) + (refill cbuf))) + +(defun ignore-data (data start end) + (declare (ignore data start end))) + +(defun skip-until-matching (matcher cbuf) + (call-until-matching matcher 'ignore-data cbuf)) + + +;;; Creating HTTP requests as octet buffers + +(defclass octet-sink () + ((storage + :initarg :storage + :accessor storage)) + (:default-initargs + :storage (make-array 1024 :element-type 'octet + :fill-pointer 0 + :adjustable t)) + (:documentation "A simple stream-like target for collecting + octets.")) + +(defun add-octet (octet sink) + (vector-push-extend octet (storage sink))) + +(defun add-octets (octets sink &key (start 0) end) + (setf end (or end (length octets))) + (loop for i from start below end + do (add-octet (aref octets i) sink))) + +(defun add-string (string sink) + (loop for char across string + for code = (char-code char) + do (add-octet code sink))) + +(defun add-strings (sink &rest strings) + (mapc (lambda (string) (add-string string sink)) strings)) + +(defun add-newline (sink) + (add-octet 13 sink) + (add-octet 10 sink)) + +(defun sink-buffer (sink) + (subseq (storage sink) 0)) + +(defvar *proxy-url* (config-value "proxy-url")) + +(defun full-proxy-path (host port path) + (format nil "~:[http~;https~]://~A~:[:~D~;~*~]~A" + (eql port 443) + host + (or (null port) + (eql port 80) + (eql port 443)) + port + path)) + +(defun user-agent-string () + "Return a string suitable for using as the User-Agent value in HTTP +requests. Includes Quicklisp version and CL implementation and version +information." + (labels ((requires-encoding (char) + (not (or (alphanumericp char) + (member char '(#\. #\- #\_))))) + (encode (string) + (substitute-if #\_ #'requires-encoding string)) + (version-string (string) + (if (string-equal string nil) + "unknown" + (let* ((length (length string)) + (start (or (position-if #'digit-char-p string) + 0)) + (space (or (position #\Space string :start start) + length)) + (limit (min space length (+ start 24)))) + (encode (subseq string start limit)))))) + ;; FIXME: Be more configurable, and take/set the version from + ;; somewhere else. + (format nil "quicklisp-client/~A ~A/~A" + ql-info:*version* + (encode (lisp-implementation-type)) + (version-string (lisp-implementation-version))))) + +(defun make-request-buffer (host port path &key (method "GET")) + "Return an octet vector suitable for sending as an HTTP 1.1 request." + (setf method (string method)) + (when *proxy-url* + (setf path (full-proxy-path host port path))) + (let ((sink (make-instance 'octet-sink))) + (flet ((add-line (&rest strings) + (apply #'add-strings sink strings) + (add-newline sink))) + (add-line method " " path " HTTP/1.1") + (add-line "Host: " host (if (integerp port) + (format nil ":~D" port) + "")) + (add-line "Connection: close") + (add-line "User-Agent: " (user-agent-string)) + (add-newline sink) + (sink-buffer sink)))) + +(defun sink-until-matching (matcher cbuf) + (let ((sink (make-instance 'octet-sink))) + (call-until-matching + matcher + (lambda (buffer start end) + (add-octets buffer sink :start start :end end)) + cbuf) + (sink-buffer sink))) + + +;;; HTTP headers + +(defclass header () + ((data + :initarg :data + :accessor data) + (status + :initarg :status + :accessor status) + (name-starts + :initarg :name-starts + :accessor name-starts) + (name-ends + :initarg :name-ends + :accessor name-ends) + (value-starts + :initarg :value-starts + :accessor value-starts) + (value-ends + :initarg :value-ends + :accessor value-ends))) + +(defmethod print-object ((header header) stream) + (print-unreadable-object (header stream :type t) + (prin1 (status header) stream))) + +(defun matches-at (pattern target pos) + (= (mismatch pattern target :start2 pos) (length pattern))) + +(defun header-value-indexes (field-name header) + (loop with data = (data header) + with pattern = (ascii-vector (string-downcase field-name)) + for start across (name-starts header) + for i from 0 + when (matches-at pattern data start) + return (values (aref (value-starts header) i) + (aref (value-ends header) i)))) + +(defun ascii-header-value (field-name header) + (multiple-value-bind (start end) + (header-value-indexes field-name header) + (when start + (ascii-subseq (data header) start end)))) + +(defun all-field-names (header) + (map 'list + (lambda (start end) + (ascii-subseq (data header) start end)) + (name-starts header) + (name-ends header))) + +(defun headers-alist (header) + (mapcar (lambda (name) + (cons name (ascii-header-value name header))) + (all-field-names header))) + +(defmethod describe-object :after ((header header) stream) + (format stream "~&Decoded headers:~% ~S~%" (headers-alist header))) + +(defun content-length (header) + (let ((field-value (ascii-header-value "content-length" header))) + (when field-value + (let ((value (ignore-errors (parse-integer field-value)))) + (or value + (error "Content-Length header field value is not a number -- ~A" + field-value)))))) + +(defun chunkedp (header) + (string= (ascii-header-value "transfer-encoding" header) "chunked")) + +(defun location (header) + (ascii-header-value "location" header)) + +(defun status-code (vector) + (let* ((space (position (acode #\Space) vector)) + (c1 (- (aref vector (incf space)) 48)) + (c2 (- (aref vector (incf space)) 48)) + (c3 (- (aref vector (incf space)) 48))) + (+ (* c1 100) + (* c2 10) + (* c3 1)))) + +(defun force-downcase-field-names (header) + (loop with data = (data header) + for start across (name-starts header) + for end across (name-ends header) + do (loop for i from start below end + for code = (aref data i) + do (setf (aref data i) (ascii-downcase code))))) + +(defun skip-white-forward (pos vector) + (position-if-not 'whitep vector :start pos)) + +(defun skip-white-backward (pos vector) + (let ((nonwhite (position-if-not 'whitep vector :end pos :from-end t))) + (if nonwhite + (1+ nonwhite) + pos))) + +(defun contract-field-value-indexes (header) + "Header field values exclude leading and trailing whitespace; adjust +the indexes in the header accordingly." + (loop with starts = (value-starts header) + with ends = (value-ends header) + with data = (data header) + for i from 0 + for start across starts + for end across ends + do + (setf (aref starts i) (skip-white-forward start data)) + (setf (aref ends i) (skip-white-backward end data)))) + +(defun next-line-pos (vector) + (let ((pos 0)) + (labels ((finish (&optional (i pos)) + (return-from next-line-pos i)) + (after-cr (code) + (acase code + (:lf (finish pos)) + (t (finish (1- pos))))) + (pending (code) + (acase code + (:cr #'after-cr) + (:lf (finish pos)) + (t #'pending)))) + (let ((state #'pending)) + (loop + (setf state (funcall state (aref vector pos))) + (incf pos)))))) + +(defun make-hvector () + (make-array 16 :fill-pointer 0 :adjustable t)) + +(defun process-header (vector) + "Create a HEADER instance from the octet data in VECTOR." + (let* ((name-starts (make-hvector)) + (name-ends (make-hvector)) + (value-starts (make-hvector)) + (value-ends (make-hvector)) + (header (make-instance 'header + :data vector + :status 999 + :name-starts name-starts + :name-ends name-ends + :value-starts value-starts + :value-ends value-ends)) + (mark nil) + (pos (next-line-pos vector))) + (unless pos + (error "Unable to process HTTP header")) + (setf (status header) (status-code vector)) + (labels ((save (value vector) + (vector-push-extend value vector)) + (mark () + (setf mark pos)) + (clear-mark () + (setf mark nil)) + (finish () + (if mark + (save mark value-ends) + (save pos value-ends)) + (force-downcase-field-names header) + (contract-field-value-indexes header) + (return-from process-header header)) + (in-new-line (code) + (acase code + ((#\Tab #\Space) (setf mark nil) #'in-value) + (t + (when mark + (save mark value-ends)) + (clear-mark) + (save pos name-starts) + (in-name code)))) + (after-cr (code) + (acase code + (:lf #'in-new-line) + (t (in-new-line code)))) + (in-name (code) + (acase code + (#\: + (save pos name-ends) + (save (1+ pos) value-starts) + #'in-value) + ((:cr :lf) + (finish)) + ((#\Tab #\Space) + (error "Unexpected whitespace in header field name")) + (t + (unless (<= 0 code 127) + (error "Unexpected non-ASCII header field name")) + #'in-name))) + (in-value (code) + (acase code + (:lf (mark) #'in-new-line) + (:cr (mark) #'after-cr) + (t #'in-value)))) + (let ((state #'in-new-line)) + (loop + (incf pos) + (when (<= (length vector) pos) + (error "No header found in response")) + (setf state (funcall state (aref vector pos)))))))) + + +;;; HTTP URL parsing + +(defclass url () + ((scheme + :initarg :scheme + :accessor scheme + :initform nil) + (hostname + :initarg :hostname + :accessor hostname + :initform nil) + (port + :initarg :port + :accessor port + :initform nil) + (path + :initarg :path + :accessor path + :initform "/"))) + +(defun parse-urlstring (urlstring) + (setf urlstring (string-trim " " urlstring)) + (let* ((pos (position #\: urlstring)) + (scheme (or (and pos (subseq urlstring 0 pos)) "http")) + (pos (mismatch urlstring "://" :test 'char-equal :start1 pos)) + (mark pos) + (url (make-instance 'url))) + (setf (scheme url) scheme) + (labels ((save () + (subseq urlstring mark pos)) + (mark () + (setf mark pos)) + (finish () + (return-from parse-urlstring url)) + (hostname-char-p (char) + (position char "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_." + :test 'char-equal)) + (at-start (char) + (case char + (#\/ + (setf (port url) nil) + (mark) + #'in-path) + (t + #'in-host))) + (in-host (char) + (case char + ((#\/ :end) + (setf (hostname url) (save)) + (mark) + #'in-path) + (#\: + (setf (hostname url) (save)) + (mark) + #'in-port) + (t + (unless (hostname-char-p char) + (error "~S is not a valid URL" urlstring)) + #'in-host))) + (in-port (char) + (case char + ((#\/ :end) + (setf (port url) + (parse-integer urlstring + :start (1+ mark) + :end pos)) + (mark) + #'in-path) + (t + (unless (digit-char-p char) + (error "Bad port in URL ~S" urlstring)) + #'in-port))) + (in-path (char) + (case char + ((#\# :end) + (setf (path url) (save)) + (finish))) + #'in-path)) + (let ((state #'at-start)) + (loop + (when (<= (length urlstring) pos) + (funcall state :end) + (finish)) + (setf state (funcall state (aref urlstring pos))) + (incf pos)))))) + +(defun url (thing) + (if (stringp thing) + (parse-urlstring thing) + thing)) + +(defgeneric request-buffer (method url) + (:method (method url) + (setf url (url url)) + (make-request-buffer (hostname url) (or (port url) 80) (path url) + :method method))) + +(defun urlstring (url) + (format nil "~@[~A://~]~@[~A~]~@[:~D~]~A" + (and (hostname url) (scheme url)) + (hostname url) + (port url) + (path url))) + +(defmethod print-object ((url url) stream) + (print-unreadable-object (url stream :type t) + (prin1 (urlstring url) stream))) + +(defun merge-urls (url1 url2) + (setf url1 (url url1)) + (setf url2 (url url2)) + (make-instance 'url + :scheme (or (scheme url1) + (scheme url2)) + :hostname (or (hostname url1) + (hostname url2)) + :port (or (port url1) + (port url2)) + :path (or (path url1) + (path url2)))) + + +;;; Requesting an URL and saving it to a file + +(defparameter *maximum-redirects* 10) +(defvar *default-url-defaults* (url "http://src.quicklisp.org/")) + +(defun read-http-header (cbuf) + (let ((header-data (sink-until-matching (list (acode-matcher :lf :lf) + (acode-matcher :cr :cr) + (acode-matcher :cr :lf :cr :lf)) + cbuf))) + (process-header header-data))) + +(defun read-chunk-header (cbuf) + (let* ((header-data (sink-until-matching (acode-matcher :cr :lf) cbuf)) + (end (or (position (acode :cr) header-data) + (position (acode #\;) header-data)))) + (values (parse-integer (ascii-subseq header-data 0 end) :radix 16)))) + +(defun save-chunk-response (stream cbuf) + "For a chunked response, read all chunks and write them to STREAM." + (let ((fun (make-stream-writer stream)) + (matcher (acode-matcher :cr :lf))) + (loop + (let ((chunk-size (read-chunk-header cbuf))) + (when (zerop chunk-size) + (return)) + (call-for-n-octets chunk-size fun cbuf) + (skip-until-matching matcher cbuf))))) + +(defun save-response (file header cbuf &key (if-exists :rename-and-delete)) + (with-open-file (stream file + :direction :output + :if-exists if-exists + :element-type 'octet) + (let ((content-length (content-length header))) + (cond ((chunkedp header) + (save-chunk-response stream cbuf)) + (content-length + (call-for-n-octets content-length + (make-stream-writer stream) + cbuf)) + (t + (call-until-end (make-stream-writer stream) cbuf)))))) + +(defun call-with-progress-bar (size fun) + (let ((progress-bar (make-progress-bar size))) + (start-display progress-bar) + (flet ((update (condition) + (update-progress progress-bar + (cbuf-progress-size condition)))) + (handler-bind ((cbuf-progress #'update)) + (funcall fun))) + (finish-display progress-bar))) + +(define-condition fetch-error (error) ()) + +(define-condition unexpected-http-status (fetch-error) + ((status-code + :initarg :status-code + :reader unexpected-http-status-code) + (url + :initarg :url + :reader unexpected-http-status-url)) + (:report + (lambda (condition stream) + (format stream "Unexpected HTTP status for ~A: ~A" + (unexpected-http-status-url condition) + (unexpected-http-status-code condition))))) + +(define-condition too-many-redirects (fetch-error) + ((url + :initarg :url + :reader too-many-redirects-url) + (redirect-count + :initarg :redirect-count + :reader too-many-redirects-count)) + (:report + (lambda (condition stream) + (format stream "Too many redirects (~:D) for ~A" + (too-many-redirects-count condition) + (too-many-redirects-url condition))))) + +(defvar *fetch-scheme-functions* + '(("http" . http-fetch)) + "assoc list to decide which scheme-function are called by FETCH function.") + +(defun fetch (url file &rest rest) + "Request URL and write the body of the response to FILE." + (let* ((url (merge-urls url *default-url-defaults*)) + (call (cdr (assoc (scheme url) *fetch-scheme-functions* :test 'equal)))) + (if call + (apply call (urlstring url) file rest) + (error "Unknown scheme ~S" url)))) + +(defun http-fetch (url file &key (follow-redirects t) quietly + (if-exists :rename-and-delete) + (maximum-redirects *maximum-redirects*)) + "default scheme-function for http protocol." + (setf url (merge-urls url *default-url-defaults*)) + (setf file (merge-pathnames file)) + (let ((redirect-count 0) + (original-url url) + (connect-url (or (url *proxy-url*) url)) + (stream (if quietly + (make-broadcast-stream) + *trace-output*))) + (loop + (when (<= maximum-redirects redirect-count) + (error 'too-many-redirects + :url original-url + :redirect-count redirect-count)) + (with-connection (connection (hostname connect-url) (or (port connect-url) 80)) + (let ((cbuf (make-instance 'cbuf :connection connection)) + (request (request-buffer "GET" url))) + (write-octets request connection) + (let ((header (read-http-header cbuf))) + (loop while (= (status header) 100) + do (setf header (read-http-header cbuf))) + (cond ((= (status header) 200) + (let ((size (content-length header))) + (format stream "~&; Fetching ~A~%" url) + (if (and (numberp size) + (plusp size)) + (format stream "; ~$KB~%" (/ size 1024)) + (format stream "; Unknown size~%")) + (if quietly + (save-response file header cbuf + :if-exists if-exists) + (call-with-progress-bar + (content-length header) + (lambda () + (save-response file header cbuf + :if-exists if-exists)))))) + ((not (<= 300 (status header) 399)) + (error 'unexpected-http-status + :url url + :status-code (status header)))) + (if (and follow-redirects (<= 300 (status header) 399)) + (let ((new-urlstring (ascii-header-value "location" header))) + (when (not new-urlstring) + (error "Redirect code ~D received, but no Location: header" + (status header))) + (incf redirect-count) + (setf url (merge-urls new-urlstring + url)) + (format stream "~&; Redirecting to ~A~%" url)) + (return (values header (and file (probe-file file))))))))))) diff --git a/sbcl/.quicklisp/quicklisp/impl-util.lisp b/sbcl/.quicklisp/quicklisp/impl-util.lisp new file mode 100644 index 0000000..654c217 --- /dev/null +++ b/sbcl/.quicklisp/quicklisp/impl-util.lisp @@ -0,0 +1,340 @@ +;;;; impl-util.lisp + +(in-package #:ql-impl-util) + +(definterface call-with-quiet-compilation (fun) + (:documentation + "Call FUN with warnings, style-warnings, and other verbose messages + suppressed.") + (:implementation t + (let ((*load-verbose* nil) + (*compile-verbose* nil) + (*load-print* nil) + (*compile-print* nil)) + (handler-bind ((warning #'muffle-warning)) + (funcall fun))))) + +(defimplementation (call-with-quiet-compilation :for sbcl :qualifier :around) + (fun) + (declare (ignore fun)) + (handler-bind ((ql-sbcl:compiler-note #'muffle-warning)) + (call-next-method))) + +(defimplementation (call-with-quiet-compilation :for cmucl :qualifier :around) + (fun) + (declare (ignore fun)) + (let ((ql-cmucl:*gc-verbose* nil)) + (call-next-method))) + +(definterface rename-directory (from to) + (:implementation t + (rename-file from to) + (truename to)) + (:implementation cmucl + (rename-file from (string-right-trim "/" (namestring to))) + (truename to)) + (:implementation clisp + (ql-clisp:rename-directory from to) + (truename to))) + +(definterface probe-directory (pathname) + (:documentation "Return the truename of PATHNAME, if it exists and + is a directory, or NIL otherwise.") + (:implementation t + (let ((directory (probe-file pathname))) + (when directory + ;; probe-file is specified to return the truename of the path, + ;; but Allegro does not return the truename; truenamize it. + (truename directory)))) + (:implementation clisp + (let ((directory (ql-clisp:probe-pathname pathname))) + (when (and directory (ql-clisp:probe-directory directory)) + directory)))) + +(definterface init-file-name () + (:documentation "Return the init file name for the current implementation.") + (:implementation allegro + ".clinit.cl") + (:implementation abcl + ".abclrc") + (:implementation ccl + #+windows + "ccl-init.lisp" + #-windows + ".ccl-init.lisp") + (:implementation clasp + ".clasprc") + (:implementation clisp + ".clisprc.lisp") + (:implementation ecl + ".eclrc") + (:implementation mkcl + ".mkclrc") + (:implementation lispworks + ".lispworks") + (:implementation sbcl + ".sbclrc") + (:implementation cmucl + ".cmucl-init.lisp") + (:implementation scl + ".scl-init.lisp") + ) + +(defun init-file-name-for (&optional implementation-designator) + (let* ((class-name (find-symbol (string-upcase implementation-designator) + 'ql-impl)) + (class (find-class class-name nil))) + (when class + (let ((*implementation* (make-instance class))) + (init-file-name))))) + +(defun quicklisp-init-file-form () + "Return a form suitable for describing the location of the quicklisp + init file. If the file is available relative to the home directory, + returns a form that merges with the home directory instead of + specifying an absolute file." + (let* ((init-file (ql-setup:qmerge "setup.lisp")) + (enough (enough-namestring init-file (user-homedir-pathname)))) + (cond ((equal (pathname enough) (pathname init-file)) + ;; The init-file is somewhere outside of the home directory + (pathname enough)) + (t + `(merge-pathnames ,enough (user-homedir-pathname)))))) + +(defun write-init-forms (stream &key (indentation 0)) + (format stream "~%~v@T;;; The following lines added by ql:add-to-init-file:~%" + indentation) + (format stream "~v@T#-quicklisp~%" indentation) + (let ((*print-case* :downcase)) + (format stream "~v@T(let ((quicklisp-init ~S))~%" + indentation + (quicklisp-init-file-form))) + (format stream "~v@T (when (probe-file quicklisp-init)~%" indentation) + (format stream "~v@T (load quicklisp-init)))~%~%" indentation)) + +(defun suitable-lisp-init-file (implementation) + "Return the name of IMPLEMENTATION's init file. If IMPLEMENTAION is +a string or pathname, return its merged pathname instead." + (typecase implementation + ((or string pathname) + (merge-pathnames implementation)) + ((or null (eql t)) + (init-file-name)) + (t + (init-file-name-for implementation)))) + +(defun add-to-init-file (&optional implementation-or-file) + "Add forms to the Lisp implementation's init file that will load +quicklisp at CL startup." + (let ((init-file (suitable-lisp-init-file implementation-or-file))) + (unless init-file + (error "Don't know how to add to init file for your implementation.")) + (setf init-file (merge-pathnames init-file (user-homedir-pathname))) + (format *query-io* "~&I will append the following lines to ~S:~%" + init-file) + (write-init-forms *query-io* :indentation 2) + (when (ql-util:press-enter-to-continue) + (with-open-file (stream init-file + :direction :output + :if-does-not-exist :create + :if-exists :append) + (write-init-forms stream))) + init-file)) + + + +;;; +;;; Native namestrings. +;;; + +(definterface native-namestring (pathname) + (:documentation "In Clozure CL, #\\.s in pathname-names are escaped + in namestrings with #\\> on Windows and #\\\\ elsewhere. This can + cause a problem when using CL:NAMESTRING to store pathname data that + might be used by other implementations. NATIVE-NAMESTRING is + intended to provide a namestring that can be parsed as a same-enough + object on multiple implementations.") + (:implementation t + (namestring pathname)) + (:implementation ccl + (ql-ccl:native-translated-namestring pathname)) + (:implementation sbcl + (ql-sbcl:native-namestring pathname))) + + +;;; +;;; Directory write date +;;; + +(definterface directory-write-date (pathname) + (:documentation "Return the write-date of the directory designated + by PATHNAME as a universal time, like file-write-date.") + (:implementation t + (file-write-date pathname)) + (:implementation clisp + (nth-value 2 (ql-clisp:probe-pathname pathname)))) + + +;;; +;;; Deleting a directory tree +;;; + +(defvar *wild-entry* + (make-pathname :name :wild :type :wild :version :wild)) + +(defvar *wild-relative* + (make-pathname :directory '(:relative :wild))) + +(definterface directoryp (entry) + (:documentation "Return true if ENTRY refers to a directory.") + (:implementation t + (not (or (pathname-name entry) + (pathname-type entry)))) + (:implementation allegro + (ql-allegro:file-directory-p entry)) + (:implementation lispworks + (ql-lispworks:file-directory-p entry))) + +(definterface directory-entries (directory) + (:documentation "Return all directory entries of DIRECTORY as a + list, or NIL if there are no directory entries. Excludes the \".\" + and \"..\" entries.") + (:implementation allegro + (directory directory + #+allegro :directories-are-files + #+allegro nil + #+allegro :follow-symbolic-links + #+allegro nil)) + (:implementation abcl + (directory (merge-pathnames *wild-entry* directory) + #+abcl :resolve-symlinks #+abcl nil)) + (:implementation ccl + (directory (merge-pathnames *wild-entry* directory) + #+ccl :directories #+ccl t + #+ccl :follow-links #+ccl nil)) + (:implementation clasp + (nconc + (directory (merge-pathnames *wild-entry* directory) + #+clasp :resolve-symlinks #+clasp nil) + (directory (merge-pathnames *wild-relative* directory) + #+clasp :resolve-symlinks #+clasp nil))) + (:implementation clisp + ;; :full gives pathnames as well as truenames, BUT: it returns a + ;; singleton pathname, not a list, on dead symlinks. + (remove nil + (mapcar (lambda (entry) (and (listp entry) (first entry))) + (nconc (directory (merge-pathnames *wild-entry* directory) + #+clisp :full #+clisp t + #+clisp :if-does-not-exist #+clisp :keep) + (directory (merge-pathnames *wild-relative* directory) + #+clisp :full #+clisp t + #+clisp :if-does-not-exist #+clisp :keep))))) + (:implementation cmucl + (directory (merge-pathnames *wild-entry* directory) + #+cmucl :truenamep #+cmucl nil)) + (:implementation scl + (directory (merge-pathnames *wild-entry* directory) + #+scl :truenamep #+scl nil)) + (:implementation lispworks + (directory (merge-pathnames *wild-entry* directory) + #+lispworks :directories #+lispworks t + #+lispworks :link-transparency #+lispworks nil)) + (:implementation ecl + (nconc + (directory (merge-pathnames *wild-entry* directory) + #+ecl :resolve-symlinks #+ecl nil) + (directory (merge-pathnames *wild-relative* directory) + #+ecl :resolve-symlinks #+ecl nil))) + (:implementation mkcl + (setf directory (truename directory)) + (nconc + (directory (merge-pathnames *wild-entry* directory)) + (directory (merge-pathnames *wild-relative* directory)))) + (:implementation sbcl + (directory (merge-pathnames *wild-entry* directory) + #+sbcl :resolve-symlinks #+sbcl nil))) + +(defimplementation (directory-entries :qualifier :around) (directory) + ;; Don't return any entries when called with a non-directory + ;; argument + (if (directoryp directory) + (call-next-method) + (warn "directory-entries - not a directory -- ~S" directory))) + +(definterface delete-directory (entry) + (:documentation "Delete the directory ENTRY. Might signal an error + if it is not an empty directory.") + (:implementation t + (delete-file entry)) + (:implementation allegro + (ql-allegro:delete-directory entry)) + (:implementation ccl + (ql-ccl:delete-directory entry)) + (:implementation clasp + (ql-clasp:rmdir entry)) + (:implementation clisp + (ql-clisp:delete-directory entry)) + (:implementation cmucl + (ql-cmucl:unix-rmdir (namestring entry))) + (:implementation scl + (ql-scl:unix-rmdir (ql-scl:unix-namestring entry))) + (:implementation ecl + (ql-ecl:rmdir entry)) + (:implementation mkcl + (ql-mkcl:rmdir entry)) + (:implementation lispworks + (ql-lispworks:delete-directory entry)) + (:implementation sbcl + (ql-sbcl:rmdir entry))) + +(defimplementation (delete-directory :qualifier :around) (directory) + ;; Don't delete non-directories with delete-directory + (if (directoryp directory) + (call-next-method) + (error "delete-directory - not a directory -- ~A" directory))) + +(definterface delete-directory-tree (pathname) + (:documentation "Delete the directory tree rooted at PATHNAME.") + (:implementation t + (let ((directories-to-process (list (truename pathname))) + (directories-to-delete '())) + (loop + (unless directories-to-process + (return)) + (let* ((current (pop directories-to-process)) + (entries (directory-entries current))) + (push current directories-to-delete) + (dolist (entry entries) + (if (directoryp entry) + (push entry directories-to-process) + (delete-file entry))))) + (map nil 'delete-directory directories-to-delete))) + (:implementation allegro + (ql-allegro:delete-directory-and-files pathname)) + (:implementation ccl + (ql-ccl:delete-directory pathname))) + +(defimplementation (delete-directory-tree :qualifier :around) (pathname) + (if (directoryp pathname) + (call-next-method) + (progn + (warn "delete-directory-tree - not a directory, ~ + deleting anyway -- ~s" pathname) + (delete-file pathname)))) + +(defun map-directory-tree (directory fun) + "Call FUN for every file in directory and all its subdirectories, +recursively. Uses the truename of directory as a starting point. Does +not follow symlinks, but, on some implementations, DOES include +potentially dead symlinks." + (let ((directories-to-process (list (truename directory)))) + (loop + (unless directories-to-process + (return)) + (let* ((current (pop directories-to-process)) + (entries (directory-entries current))) + (dolist (entry entries) + (if (directoryp entry) + (push entry directories-to-process) + (funcall fun entry))))))) + diff --git a/sbcl/.quicklisp/quicklisp/impl.lisp b/sbcl/.quicklisp/quicklisp/impl.lisp new file mode 100644 index 0000000..8411375 --- /dev/null +++ b/sbcl/.quicklisp/quicklisp/impl.lisp @@ -0,0 +1,301 @@ +(in-package #:ql-impl) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defun error-unimplemented (&rest args) + (declare (ignore args)) + (error "Not implemented"))) + +(defvar *interfaces* (make-hash-table) + "A table of defined interfaces and their documentation.") + +(defun show-interfaces () + "Display information about what interfaces are defined." + (maphash (lambda (interface info) + (destructuring-bind (arguments docstring) + info + (let ((*package* (find-package :keyword))) + (format t "(~S ~:[()~;~:*~A~]~@[~% ~S~])~%" + interface arguments docstring)))) + *interfaces*)) + +(defmacro neuter-package (name) + `(eval-when (:compile-toplevel :load-toplevel :execute) + (let ((definition (fdefinition 'error-unimplemented))) + (do-external-symbols (symbol ,(string name)) + (unless (fboundp symbol) + (setf (fdefinition symbol) definition)))))) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defun feature-expression-passes-p (expression) + (cond ((keywordp expression) + (member expression *features*)) + ((consp expression) + (case (first expression) + (or + (some 'feature-expression-passes-p (rest expression))) + (and + (every 'feature-expression-passes-p (rest expression))))) + (t (error "Unrecognized feature expression -- ~S" expression))))) + + +(defmacro define-implementation-package (feature package-name &rest options) + (let* ((output-options '((:use) + (:export #:lisp))) + (prep (cdr (assoc :prep options))) + (class-option (cdr (assoc :class options))) + (class (first class-option)) + (superclasses (rest class-option)) + (import-options '()) + (effectivep (feature-expression-passes-p feature))) + (dolist (option options) + (ecase (first option) + ((:prep :class)) + ((:import-from + :import) + (push option import-options)) + ((:export + :shadow + :intern + :documentation) + (push option output-options)) + ((:reexport-from) + (push (cons :export (cddr option)) output-options) + (push (cons :import-from (cdr option)) import-options)))) + `(progn + ,@(when effectivep + `((eval-when (:compile-toplevel :load-toplevel :execute) + ,@prep))) + (defclass ,class ,superclasses ()) + (defpackage ,package-name ,@output-options + ,@(when effectivep + import-options)) + ,@(when effectivep + `((setf *implementation* (make-instance ',class)))) + ,@(unless effectivep + `((neuter-package ,package-name)))))) + +(defmacro definterface (name lambda-list &body options) + (let* ((doc-option (find :documentation options :key #'first)) + (doc (second doc-option))) + (setf (gethash name *interfaces*) (list lambda-list doc))) + (let* ((forbidden (intersection lambda-list lambda-list-keywords)) + (gf-options (remove :implementation options :key #'first)) + (implementations (set-difference options gf-options)) + (implementation-arg (copy-symbol '%implementation))) + (when forbidden + (error "~S not allowed in definterface lambda list" forbidden)) + (flet ((method-option (class body) + `(:method ((,implementation-arg ,class) ,@lambda-list) + ,@body))) + (let ((generic-name (intern (format nil "%~A" name)))) + `(progn + (defgeneric ,generic-name (lisp ,@lambda-list) + ,@gf-options + ,@(mapcan (lambda (implementation) + (destructuring-bind (class &rest body) + (rest implementation) + (mapcar (lambda (class) + (method-option class body)) + (if (consp class) + class + (list class))))) + implementations)) + (defun ,name ,lambda-list + (,generic-name *implementation* ,@lambda-list))))))) + +(defmacro defimplementation (name-and-options + lambda-list &body body) + (destructuring-bind (name &key (for t) qualifier) + (if (consp name-and-options) + name-and-options + (list name-and-options)) + (unless for + (error "You must specify an implementation name.")) + (let ((generic-name (find-symbol (format nil "%~A" name))) + (implementation-arg (copy-symbol '%implementation))) + (unless generic-name + (error "~S does not name an implementation function" name)) + `(defmethod ,generic-name + ,@(when qualifier (list qualifier)) + ,(list* `(,implementation-arg ,for) lambda-list) ,@body)))) + + +;;; Bootstrap implementations + +(defvar *implementation* nil) +(defclass lisp () ()) + + +;;; Allegro Common Lisp + +(define-implementation-package :allegro #:ql-allegro + (:documentation + "Allegro Common Lisp - http://www.franz.com/products/allegrocl/") + (:class allegro) + (:reexport-from #:socket + #:make-socket) + (:reexport-from #:excl + #:file-directory-p + #:delete-directory + #:delete-directory-and-files + #:read-vector)) + + +;;; Armed Bear Common Lisp + +(define-implementation-package :abcl #:ql-abcl + (:documentation + "Armed Bear Common Lisp - http://common-lisp.net/project/armedbear/") + (:class abcl) + (:reexport-from #:ext + #:make-socket + #:get-socket-stream)) + +;;; Clozure CL + +(define-implementation-package :ccl #:ql-ccl + (:documentation + "Clozure Common Lisp - http://www.clozure.com/clozurecl.html") + (:class ccl) + (:reexport-from #:ccl + #:delete-directory + #:make-socket + #:native-translated-namestring)) + +;;; CLASP + +(define-implementation-package :clasp #:ql-clasp + (:documentation "CLASP - http://github.com/drmeister/clasp") + (:class clasp) + (:prep + (require 'sockets)) + (:intern #:host-network-address) + (:reexport-from #:si + #:rmdir + #:file-kind) + (:reexport-from #:sb-bsd-sockets + #:get-host-by-name + #:host-ent-address + #:inet-socket + #:socket-connect + #:socket-make-stream)) + + +;;; GNU CLISP + +(define-implementation-package :clisp #:ql-clisp + (:documentation "GNU CLISP - http://clisp.cons.org/") + (:class clisp) + (:reexport-from #:socket + #:socket-connect) + (:reexport-from #:ext + #:delete-directory + #:rename-directory + #:probe-directory + #:probe-pathname + #:read-byte-sequence)) + + +;;; CMUCL + +(define-implementation-package :cmu #:ql-cmucl + (:documentation "CMU Common Lisp - http://www.cons.org/cmucl/") + (:class cmucl) + (:reexport-from #:system + #:make-fd-stream) + (:reexport-from #:unix + #:unix-rmdir) + (:reexport-from #:extensions + #:connect-to-inet-socket + #:*gc-verbose*)) + +(defvar ql-cmucl:*gc-verbose*) + + +;;; Scieneer CL + +(define-implementation-package :scl #:ql-scl + (:documentation "Scieneer Common Lisp - http://www.scieneer.com/scl/") + (:class scl) + (:reexport-from #:system + #:make-fd-stream) + (:reexport-from #:unix + #:unix-rmdir) + (:reexport-from #:extensions + #:connect-to-inet-socket + #:unix-namestring)) + + +;;; LispWorks + +(define-implementation-package :lispworks #:ql-lispworks + (:documentation "LispWorks - http://www.lispworks.com/") + (:class lispworks) + (:prep + (require "comm")) + (:reexport-from #:lw + #:file-directory-p + #:delete-directory) + (:reexport-from #:comm + #:open-tcp-stream + #:get-host-entry)) + + +;;; ECL + +(define-implementation-package :ecl #:ql-ecl + (:documentation "ECL - http://ecls.sourceforge.net/") + (:class ecl) + (:prep + (require 'sockets)) + (:intern #:host-network-address) + (:reexport-from #:si + #:rmdir + #:file-kind) + (:reexport-from #:sb-bsd-sockets + #:get-host-by-name + #:host-ent-address + #:inet-socket + #:socket-connect + #:socket-make-stream)) + +;;; MKCL + +(define-implementation-package :mkcl #:ql-mkcl + (:documentation "ManKai Common Lisp - http://common-lisp.net/project/mkcl/") + (:class mkcl) + (:prep + (require 'sockets)) + (:intern #:host-network-address) + (:reexport-from #:si + #:rmdir + #:file-kind) + (:reexport-from #:sb-bsd-sockets + #:get-host-by-name + #:host-ent-address + #:inet-socket + #:socket-connect + #:socket-make-stream)) + + +;;; SBCL + +(define-implementation-package :sbcl #:ql-sbcl + (:class sbcl) + (:documentation + "Steel Bank Common Lisp - http://www.sbcl.org/") + (:prep + (require 'sb-posix) + (require 'sb-bsd-sockets)) + (:intern #:host-network-address) + (:reexport-from #:sb-posix + #:rmdir) + (:reexport-from #:sb-ext + #:compiler-note + #:native-namestring) + (:reexport-from #:sb-bsd-sockets + #:get-host-by-name + #:inet-socket + #:host-ent-address + #:socket-connect + #:socket-make-stream)) diff --git a/sbcl/.quicklisp/quicklisp/local-projects.lisp b/sbcl/.quicklisp/quicklisp/local-projects.lisp new file mode 100644 index 0000000..a068c2e --- /dev/null +++ b/sbcl/.quicklisp/quicklisp/local-projects.lisp @@ -0,0 +1,138 @@ +;;;; local-projects.lisp + +;;; +;;; Local project support. +;;; +;;; Local projects can be placed in /local-projects/. New +;;; entries in that directory are automatically scanned for system +;;; files for use with QL:QUICKLOAD. +;;; +;;; This works by keeping a cache of system file pathnames in +;;; /local-projects/system-index.txt. Whenever the +;;; timestamp on the local projects directory is newer than the +;;; timestamp on the system index file, the entire tree is re-scanned +;;; and cached. +;;; +;;; This will pick up system files that are created as a result of +;;; creating new project directory in /local-projects/, +;;; e.g. unpacking a tarball or zip file, checking out a project from +;;; version control, etc. It will NOT pick up a system file that is +;;; added sometime later in a subdirectory; for that, the +;;; REGISTER-LOCAL-PROJECTS function is needed to rebuild the system +;;; file index. +;;; +;;; In the event there are multiple systems of the same name in the +;;; directory tree, the one with the shortest pathname namestring is +;;; used. This is intended to ignore stuff like _darcs pristine +;;; directories. +;;; +;;; Work in progress! +;;; + +(in-package #:quicklisp-client) + +(defparameter *local-project-directories* + (list (qmerge "local-projects/")) + "The default local projects directory.") + +(defun system-index-file (pathname) + "Return the system index file for the directory PATHNAME." + (merge-pathnames "system-index.txt" pathname)) + +(defun matching-directory-files (directory fun) + (let ((result '())) + (map-directory-tree directory + (lambda (file) + (when (funcall fun file) + (push file result)))) + result)) + +(defun local-project-system-files (pathname) + "Return a list of system files under PATHNAME." + (let* ((files (matching-directory-files pathname + (lambda (file) + (equalp (pathname-type file) + "asd"))))) + (setf files (sort files + #'string< + :key #'namestring)) + (stable-sort files + #'< + :key (lambda (file) + (length (namestring file)))))) + +(defun make-system-index (pathname) + "Create a system index file for all system files under +PATHNAME. Current format is one native namestring per line." + (setf pathname (truename pathname)) + (with-open-file (stream (system-index-file pathname) + :direction :output + :if-exists :rename-and-delete) + (dolist (system-file (local-project-system-files pathname)) + (let ((system-path (enough-namestring system-file pathname))) + (write-line (native-namestring system-path) stream))) + (probe-file stream))) + +(defun find-valid-system-index (pathname) + "Find a valid system index file for PATHNAME; one that both exists +and has a newer timestamp than PATHNAME." + (let* ((file (system-index-file pathname)) + (probed (probe-file file))) + (when (and probed + (<= (directory-write-date pathname) + (file-write-date probed))) + probed))) + +(defun ensure-system-index (pathname) + "Find or create a system index file for PATHNAME." + (or (find-valid-system-index pathname) + (make-system-index pathname))) + +(defun find-system-in-index (system index-file) + "If any system pathname in INDEX-FILE has a pathname-name matching +SYSTEM, return its full pathname." + (with-open-file (stream index-file) + (loop for namestring = (read-line stream nil) + while namestring + when (string= system (pathname-name namestring)) + return (or (probe-file (merge-pathnames namestring index-file)) + ;; If the indexed .asd file doesn't exist anymore + ;; then regenerate the index and restart the search. + (find-system-in-index system (make-system-index (directory-namestring index-file))))))) + +(defun local-projects-searcher (system-name) + "This function is added to ASDF:*SYSTEM-DEFINITION-SEARCH-FUNCTIONS* +to use the local project directory and cache to find systems." + (dolist (directory *local-project-directories*) + (when (probe-directory directory) + (let ((system-index (ensure-system-index directory))) + (when system-index + (let ((system (find-system-in-index system-name system-index))) + (when system + (return system)))))))) + +(defun list-local-projects () + "Return a list of pathnames to local project system files." + (let ((result (make-array 16 :fill-pointer 0 :adjustable t)) + (seen (make-hash-table :test 'equal))) + (dolist (directory *local-project-directories* + (coerce result 'list)) + (let ((index (ensure-system-index directory))) + (when index + (with-open-file (stream index) + (loop for line = (read-line stream nil) + while line do + (let ((pathname (merge-pathnames line index))) + (unless (gethash (pathname-name pathname) seen) + (setf (gethash (pathname-name pathname) seen) t) + (vector-push-extend (merge-pathnames line index) + result)))))))))) + +(defun register-local-projects () + "Force a scan of the local projects directory to create the system +file index." + (map nil 'make-system-index *local-project-directories*)) + +(defun list-local-systems () + "Return a list of local project system names." + (mapcar #'pathname-name (list-local-projects))) diff --git a/sbcl/.quicklisp/quicklisp/minitar.lisp b/sbcl/.quicklisp/quicklisp/minitar.lisp new file mode 100644 index 0000000..49cde86 --- /dev/null +++ b/sbcl/.quicklisp/quicklisp/minitar.lisp @@ -0,0 +1,192 @@ +(in-package #:ql-minitar) + +(defconstant +block-size+ 512) +(defconstant +space-code+ 32) +(defconstant +newline-code+ 10) +(defconstant +equals-code+ 61) + +(defun make-block-buffer () + (make-array +block-size+ :element-type '(unsigned-byte 8) :initial-element 0)) + +(defun skip-n-blocks (n stream) + (let ((block (make-block-buffer))) + (dotimes (i n) + (read-sequence block stream)))) + +(defun read-octet-vector (length stream) + (let ((block (make-block-buffer)) + (vector (make-array length :element-type '(unsigned-byte 8))) + (offset 0) + (block-count (ceiling length +block-size+))) + (dotimes (i block-count) + (read-sequence block stream) + (replace vector block :start1 offset) + (incf offset +block-size+)) + vector)) + + +(defun decode-pax-header-record (vector offset) + "Decode VECTOR as pax extended header data. Returns the keyword and +value it specifies as multiple values." + ;; Vector format is: "%d %s=%s\n", , , + ;; See http://pubs.opengroup.org/onlinepubs/009695399/utilities/pax.html + (let* ((length-start offset) + (length-end (position +space-code+ vector :start length-start)) + (length-string (ascii-subseq vector length-start length-end)) + (length (parse-integer length-string)) + (keyword-start (1+ length-end)) + (keyword-end (position +equals-code+ vector :start keyword-start)) + (keyword (ascii-subseq vector keyword-start keyword-end)) + (value-start (1+ keyword-end)) + (value-end (1- (+ offset length))) + (value (ascii-subseq vector value-start value-end))) + (values keyword value (+ offset length)))) + +(defun decode-pax-header (vector) + "Decode VECTOR as a pax header and return it as an alist." + (let ((header nil) + (offset 0) + (length (length vector))) + (loop + (when (<= length offset) + (return header)) + (multiple-value-bind (keyword value new-offset) + (decode-pax-header-record vector offset) + (setf header (acons keyword value header)) + (setf offset new-offset))))) + +(defun pax-header-path (vector) + "Decode VECTOR as a pax header and return its 'path' value, if + any." + (let ((header-alist (decode-pax-header vector))) + (cdr (assoc "path" header-alist :test 'equal)))) + +(defun ascii-subseq (vector start end) + (let ((string (make-string (- end start)))) + (loop for i from 0 + for j from start below end + do (setf (char string i) (code-char (aref vector j)))) + string)) + +(defun block-asciiz-string (block start length) + (let* ((end (+ start length)) + (eos (or (position 0 block :start start :end end) + end))) + (ascii-subseq block start eos))) + +(defun prefix (header) + (when (plusp (aref header 345)) + (block-asciiz-string header 345 155))) + +(defun name (header) + (block-asciiz-string header 0 100)) + +(defun payload-size (header) + (values (parse-integer (block-asciiz-string header 124 12) :radix 8))) + +(defun nth-block (n file) + (with-open-file (stream file :element-type '(unsigned-byte 8)) + (let ((block (make-block-buffer))) + (skip-n-blocks (1- n) stream) + (read-sequence block stream) + block))) + +(defun payload-type (code) + (case code + (0 :file) + (48 :file) + (50 :symlink) + (76 :long-name) + (53 :directory) + (103 :global-header) + (120 :pax-extended-header) + (t :unsupported))) + +(defun full-path (header) + (let ((prefix (prefix header)) + (name (name header))) + (if prefix + (format nil "~A/~A" prefix name) + name))) + +(defun save-file (file size stream) + (multiple-value-bind (full-blocks partial) + (truncate size +block-size+) + (ensure-directories-exist file) + (with-open-file (outstream file + :direction :output + :if-exists :supersede + :element-type '(unsigned-byte 8)) + (let ((block (make-block-buffer))) + (dotimes (i full-blocks) + (read-sequence block stream) + (write-sequence block outstream)) + (when (plusp partial) + (read-sequence block stream) + (write-sequence block outstream :end partial)))))) + +(defun gnu-long-name (size stream) + ;; GNU long names are simply the filename (null terminated) packed into the + ;; payload. + (let ((payload (read-octet-vector size stream))) + (ascii-subseq payload 0 (1- size)))) + +(defun unpack-tarball (tarfile &key (directory *default-pathname-defaults*)) + (let ((block (make-block-buffer)) + (extended-path nil)) + (with-open-file (stream tarfile :element-type '(unsigned-byte 8)) + (loop + (let ((size (read-sequence block stream))) + (when (zerop size) + (return)) + (unless (= size +block-size+) + (error "Bad size on tarfile")) + (when (every #'zerop block) + (return)) + (let* ((payload-code (aref block 156)) + (payload-type (payload-type payload-code)) + (tar-path (or (shiftf extended-path nil) + (full-path block))) + (full-path (merge-pathnames tar-path directory)) + (payload-size (payload-size block)) + (block-count (ceiling (payload-size block) +block-size+))) + (case payload-type + (:file + (save-file full-path payload-size stream)) + (:directory + (ensure-directories-exist full-path)) + ((:symlink :global-header) + ;; These block types aren't required for Quicklisp archives + (skip-n-blocks block-count stream)) + (:long-name + (setf extended-path (gnu-long-name payload-size stream))) + (:pax-extended-header + (let* ((pax-header-data (read-octet-vector payload-size stream)) + (path (pax-header-path pax-header-data))) + (when path + (setf extended-path path)))) + (t + (warn "Unknown tar block payload code -- ~D" payload-code) + (skip-n-blocks block-count stream))))))))) + +(defun contents (tarfile) + (let ((block (make-block-buffer)) + (result '())) + (with-open-file (stream tarfile :element-type '(unsigned-byte 8)) + (loop + (let ((size (read-sequence block stream))) + (when (zerop size) + (return (nreverse result))) + (unless (= size +block-size+) + (error "Bad size on tarfile")) + (when (every #'zerop block) + (return (nreverse result))) + (let* ((payload-type (payload-type (aref block 156))) + (tar-path (full-path block)) + (payload-size (payload-size block))) + (skip-n-blocks (ceiling payload-size +block-size+) stream) + (case payload-type + (:file + (push tar-path result)) + (:directory + (push tar-path result))))))))) diff --git a/sbcl/.quicklisp/quicklisp/misc.lisp b/sbcl/.quicklisp/quicklisp/misc.lisp new file mode 100644 index 0000000..2cfabce --- /dev/null +++ b/sbcl/.quicklisp/quicklisp/misc.lisp @@ -0,0 +1,19 @@ +;;;; misc.lisp + +(in-package #:quicklisp-client) + +;;; +;;; This stuff will probably end up somewhere else. +;;; + +(defun use-only-quicklisp-systems () + (asdf:initialize-source-registry + '(:source-registry :ignore-inherited-configuration)) + (asdf:map-systems 'asdf:clear-system) + t) + +(defun who-depends-on (system-name) + "Return a list of names of systems that depend on SYSTEM-NAME." + (loop for system in (provided-systems t) + when (member system-name (required-systems system) :test 'string=) + collect (name system))) diff --git a/sbcl/.quicklisp/quicklisp/network.lisp b/sbcl/.quicklisp/quicklisp/network.lisp new file mode 100644 index 0000000..d600fcc --- /dev/null +++ b/sbcl/.quicklisp/quicklisp/network.lisp @@ -0,0 +1,137 @@ +;;; +;;; Low-level networking implementations +;;; + +(in-package #:ql-network) + +(definterface host-address (host) + (:implementation t + host) + (:implementation sbcl + (ql-sbcl:host-ent-address (ql-sbcl:get-host-by-name host)))) + +(definterface open-connection (host port) + (:documentation "Open and return a network connection to HOST on the + given PORT.") + (:implementation t + (declare (ignore host port)) + (error "Sorry, quicklisp in implementation ~S is not supported yet." + (lisp-implementation-type))) + (:implementation allegro + (ql-allegro:make-socket :remote-host host + :remote-port port)) + (:implementation abcl + (let ((socket (ql-abcl:make-socket host port))) + (ql-abcl:get-socket-stream socket :element-type '(unsigned-byte 8)))) + (:implementation ccl + (ql-ccl:make-socket :remote-host host + :remote-port port)) + (:implementation clasp + (let* ((endpoint (ql-clasp:host-ent-address + (ql-clasp:get-host-by-name host))) + (socket (make-instance 'ql-clasp:inet-socket + :protocol :tcp + :type :stream))) + (ql-clasp:socket-connect socket endpoint port) + (ql-clasp:socket-make-stream socket + :element-type '(unsigned-byte 8) + :input t + :output t + :buffering :full))) + (:implementation clisp + (ql-clisp:socket-connect port host :element-type '(unsigned-byte 8))) + (:implementation cmucl + (let ((fd (ql-cmucl:connect-to-inet-socket host port))) + (ql-cmucl:make-fd-stream fd + :element-type '(unsigned-byte 8) + :binary-stream-p t + :input t + :output t))) + (:implementation scl + (let ((fd (ql-scl:connect-to-inet-socket host port))) + (ql-scl:make-fd-stream fd + :element-type '(unsigned-byte 8) + :input t + :output t))) + (:implementation ecl + (let* ((endpoint (ql-ecl:host-ent-address + (ql-ecl:get-host-by-name host))) + (socket (make-instance 'ql-ecl:inet-socket + :protocol :tcp + :type :stream))) + (ql-ecl:socket-connect socket endpoint port) + (ql-ecl:socket-make-stream socket + :element-type '(unsigned-byte 8) + :input t + :output t + :buffering :full))) + (:implementation mkcl + (let* ((endpoint (ql-mkcl:host-ent-address + (ql-mkcl:get-host-by-name host))) + (socket (make-instance 'ql-mkcl:inet-socket + :protocol :tcp + :type :stream))) + (ql-mkcl:socket-connect socket endpoint port) + (ql-mkcl:socket-make-stream socket + :element-type '(unsigned-byte 8) + :input t + :output t + :buffering :full))) + (:implementation lispworks + (ql-lispworks:open-tcp-stream host port + :direction :io + :errorp t + :read-timeout nil + :element-type '(unsigned-byte 8) + :timeout 5)) + (:implementation sbcl + (let* ((endpoint (ql-sbcl:host-ent-address + (ql-sbcl:get-host-by-name host))) + (socket (make-instance 'ql-sbcl:inet-socket + :protocol :tcp + :type :stream))) + (ql-sbcl:socket-connect socket endpoint port) + (ql-sbcl:socket-make-stream socket + :element-type '(unsigned-byte 8) + :input t + :output t + :buffering :full)))) + +(definterface read-octets (buffer connection) + (:documentation "Read from CONNECTION into BUFFER. Returns the + number of octets read.") + (:implementation t + (read-sequence buffer connection)) + (:implementation allegro + (ql-allegro:read-vector buffer connection)) + (:implementation clisp + (ql-clisp:read-byte-sequence buffer connection + :no-hang nil + :interactive t))) + +(definterface write-octets (buffer connection) + (:documentation "Write the contents of BUFFER to CONNECTION.") + (:implementation t + (write-sequence buffer connection) + (finish-output connection))) + +(definterface close-connection (connection) + (:implementation t + (ignore-errors (close connection)))) + +(definterface call-with-connection (host port fun) + (:documentation "Establish a network connection to HOST on PORT and + call FUN with that connection as the only argument. Unconditionally + closes the connection afterwareds via CLOSE-CONNECTION in an + unwind-protect. See also WITH-CONNECTION.") + (:implementation t + (let (connection) + (unwind-protect + (progn + (setf connection (open-connection host port)) + (funcall fun connection)) + (when connection + (close-connection connection)))))) + +(defmacro with-connection ((connection host port) &body body) + `(call-with-connection ,host ,port (lambda (,connection) ,@body))) diff --git a/sbcl/.quicklisp/quicklisp/package.lisp b/sbcl/.quicklisp/quicklisp/package.lisp new file mode 100644 index 0000000..da68cd2 --- /dev/null +++ b/sbcl/.quicklisp/quicklisp/package.lisp @@ -0,0 +1,340 @@ +;;;; package.lisp + +(defpackage #:ql-util + (:documentation + "Utility functions used in various places.") + (:use #:cl) + (:export #:write-line-to-file + #:without-prompting + #:press-enter-to-continue + #:replace-file + #:copy-file + #:delete-file-if-exists + #:ensure-file-exists + #:split-spaces + #:first-line + #:file-size + #:safely-read + #:safely-read-file + #:make-versions-url)) + +(defpackage #:ql-setup + (:documentation + "Functions and variables initialized early in the Quicklisp client + configuration.") + (:use #:cl) + (:export #:qmerge + #:qenough + #:*quicklisp-home*)) + +(defpackage #:ql-config + (:documentation + "Getting and setting persistent configuration values.") + (:use #:cl #:ql-util #:ql-setup) + (:export #:config-value)) + +(defpackage #:ql-impl + (:documentation + "Configuration of implementation-specific packages and interfaces.") + (:use #:cl) + (:export #:*implementation*) + (:export #:definterface + #:defimplementation + #:show-interfaces) + (:export #:lisp + #:abcl + #:allegro + #:ccl + #:clasp + #:clisp + #:cmucl + #:cormanlisp + #:ecl + #:gcl + #:lispworks + #:mkcl + #:scl + #:sbcl)) + +(defpackage #:ql-impl-util + (:documentation + "Utility functions that require implementation-specific + functionality.") + (:use #:cl #:ql-impl) + (:export #:call-with-quiet-compilation + #:add-to-init-file + #:rename-directory + #:delete-directory + #:probe-directory + #:directory-entries + #:delete-directory-tree + #:map-directory-tree + #:native-namestring + #:directory-write-date)) + +(defpackage #:ql-network + (:documentation + "Simple, low-level network access.") + (:use #:cl #:ql-impl) + (:export #:open-connection + #:write-octets + #:read-octets + #:close-connection + #:with-connection)) + +(defpackage #:ql-progress + (:documentation + "Displaying a progress bar.") + (:use #:cl) + (:export #:make-progress-bar + #:start-display + #:update-progress + #:finish-display)) + +(defpackage #:ql-http + (:documentation + "A simple HTTP client.") + (:use #:cl #:ql-network #:ql-progress #:ql-config) + (:export #:*proxy-url* + #:fetch + #:http-fetch + #:*fetch-scheme-functions* + #:scheme + #:hostname + #:port + #:path + #:url + #:*maximum-redirects* + #:*default-url-defaults*) + (:export #:fetch-error + #:unexpected-http-status + #:unexpected-http-status-code + #:unexpected-http-status-url + #:too-many-redirects + #:too-many-redirects-url + #:too-many-redirects-count)) + +(defpackage #:ql-minitar + (:documentation + "A simple implementation of unpacking the 'tar' file format.") + (:use #:cl) + (:export #:unpack-tarball)) + +(defpackage #:ql-gunzipper + (:documentation + "An implementation of gunzip.") + (:use #:cl) + (:export #:gunzip)) + +(defpackage #:ql-cdb + (:documentation + "Read and write CDB files; code adapted from ZCDB.") + (:use #:cl) + (:export #:lookup + #:map-cdb + #:convert-index-file)) + +(defpackage #:ql-dist + (:documentation + "Generic functions, variables, and classes for interacting with the + dist system. Documented, exported symbols are intended for public + use.") + (:use #:cl + #:ql-util + #:ql-http + #:ql-setup + #:ql-gunzipper + #:ql-minitar) + (:intern #:dist-version + #:dist-url) + (:import-from #:ql-impl-util + #:delete-directory-tree + #:directory-entries + #:probe-directory) + ;; Install/enable protocol + (:export #:installedp + #:install + #:uninstall + #:ensure-installed + #:enabledp + #:enable + #:disable) + ;; Preference protocol + (:export #:preference + #:preference-file + #:preference-parent + #:forget-preference) + ;; Generic + (:export #:all-dists + #:canonical-distinfo-url + #:enabled-dists + #:find-dist + #:find-dist-or-lose + #:find-system + #:find-release + #:dist + #:system + #:release + #:base-directory + #:relative-to + #:metadata-name + #:install-metadata-file + #:short-description + #:provided-releases + #:provided-systems + #:installed-releases + #:installed-systems + #:name) + ;; Dists + (:export #:dist + #:dist-merge + #:find-system-in-dist + #:find-release-in-dist + #:system-index-url + #:release-index-url + #:available-versions-url + #:available-versions + #:version + #:subscription-url + #:new-version-available-p + #:dist-difference + #:fetch-dist + #:initialize-release-index + #:initialize-system-index + #:with-consistent-dists) + ;; Dist updates + (:export #:available-update + #:update-release-differences + #:show-update-report + #:update-in-place + #:install-dist + #:subscription-inhibition-file + #:inhibit-subscription + #:uninhibit-subscription + #:subscription-inhibited-p + #:subscription-unavailable + #:subscribedp + #:subscribe + #:unsubscribe) + ;; Releases + (:export #:release + #:project-name + #:system-files + #:archive-url + #:archive-size + #:ensure-archive-file + #:archive-content-sha1 + #:archive-md5 + #:prefix + #:local-archive-file + #:ensure-local-archive-file + #:check-local-archive-file + #:invalid-local-archive + #:invalid-local-archive-file + #:invalid-local-archive-release + #:missing-local-archive + #:badly-sized-local-archive + #:delete-and-retry) + ;; Systems + (:export #:dist + #:release + #:preference + #:system-file-name + #:required-systems) + ;; Misc + (:export #:standard-dist-enumeration-function + #:*dist-enumeration-functions* + #:find-asdf-system-file + #:system-definition-searcher + #:system-apropos + #:system-apropos-list + #:dependency-tree + #:clean + #:unknown-dist)) + +(defpackage #:ql-dist-user + (:documentation + "A package that uses QL-DIST; useful for playing around in without + clobbering any QL-DIST internals.") + (:use #:cl + #:ql-dist)) + +(defpackage #:ql-bundle + (:documentation + "A package for supporting the QL:BUNDLE-SYSTEMS function.") + (:use #:cl #:ql-dist #:ql-impl-util) + (:shadow #:find-system + #:find-release) + (:export #:bundle + #:requested-systems + #:ensure-system + #:ensure-release + #:write-bundle + #:add-systems-recursively + #:object-not-found + #:system-not-found + #:system-not-found-system + #:release-not-found + #:bundle-directory-exists + #:bundle-directory-exists-directory)) + +(defpackage #:quicklisp-client + (:documentation + "The Quicklisp client package, intended for end-user Quicklisp + commands and configuration parameters.") + (:nicknames #:quicklisp #:ql) + (:use #:cl + #:ql-util + #:ql-impl-util + #:ql-dist + #:ql-http + #:ql-setup + #:ql-config + #:ql-minitar + #:ql-gunzipper) + (:shadow #:uninstall) + (:shadowing-import-from #:ql-dist + #:dist-version + #:dist-url) + (:export #:dist-version + #:dist-url) + (:export #:quickload + #:*quickload-prompt* + #:*quickload-verbose* + #:*quickload-explain* + #:system-not-found + #:system-not-found-name + #:uninstall + #:uninstall-dist + #:qmerge + #:*quicklisp-home* + #:*initial-dist-url* + #:*proxy-url* + #:config-value + #:setup + #:provided-systems + #:system-apropos + #:system-apropos-list + #:system-list + #:client-version + #:client-url + #:available-client-versions + #:install-client + #:update-client + #:update-dist + #:update-all-dists + #:available-dist-versions + #:add-to-init-file + #:use-only-quicklisp-systems + #:write-asdf-manifest-file + #:where-is-system + #:help + #:register-local-projects + #:local-projects-searcher + #:*local-project-directories* + #:list-local-projects + #:list-local-systems + #:who-depends-on + #:bundle-systems)) + +(in-package #:quicklisp-client) diff --git a/sbcl/.quicklisp/quicklisp/progress.lisp b/sbcl/.quicklisp/quicklisp/progress.lisp new file mode 100644 index 0000000..b4d57e2 --- /dev/null +++ b/sbcl/.quicklisp/quicklisp/progress.lisp @@ -0,0 +1,156 @@ +;;; +;;; A text progress bar +;;; + +(in-package #:ql-progress) + +(defclass progress-bar () + ((start-time + :initarg :start-time + :accessor start-time) + (end-time + :initarg :end-time + :accessor end-time) + (progress-character + :initarg :progress-character + :accessor progress-character) + (character-count + :initarg :character-count + :accessor character-count + :documentation "How many characters wide is the progress bar?") + (characters-so-far + :initarg :characters-so-far + :accessor characters-so-far) + (update-interval + :initarg :update-interval + :accessor update-interval + :documentation "Update the progress bar display after this many + internal-time units.") + (last-update-time + :initarg :last-update-time + :accessor last-update-time + :documentation "The display was last updated at this time.") + (total + :initarg :total + :accessor total + :documentation "The total number of units tracked by this progress bar.") + (progress + :initarg :progress + :accessor progress + :documentation "How far in the progress are we?") + (pending + :initarg :pending + :accessor pending + :documentation "How many raw units should be tracked in the next + display update?")) + (:default-initargs + :progress-character #\= + :character-count 50 + :characters-so-far 0 + :update-interval (floor internal-time-units-per-second 4) + :last-update-time 0 + :total 0 + :progress 0 + :pending 0)) + +(defgeneric start-display (progress-bar)) +(defgeneric update-progress (progress-bar unit-count)) +(defgeneric update-display (progress-bar)) +(defgeneric finish-display (progress-bar)) +(defgeneric elapsed-time (progress-bar)) +(defgeneric units-per-second (progress-bar)) + +(defmethod start-display (progress-bar) + (setf (last-update-time progress-bar) (get-internal-real-time)) + (setf (start-time progress-bar) (get-internal-real-time)) + (fresh-line) + (finish-output)) + +(defmethod update-display (progress-bar) + (incf (progress progress-bar) (pending progress-bar)) + (setf (pending progress-bar) 0) + (setf (last-update-time progress-bar) (get-internal-real-time)) + (let* ((showable (floor (character-count progress-bar) + (/ (total progress-bar) (progress progress-bar)))) + (needed (- showable (characters-so-far progress-bar)))) + (setf (characters-so-far progress-bar) showable) + (dotimes (i needed) + (write-char (progress-character progress-bar))) + (finish-output))) + +(defmethod update-progress (progress-bar unit-count) + (incf (pending progress-bar) unit-count) + (let ((now (get-internal-real-time))) + (when (< (update-interval progress-bar) + (- now (last-update-time progress-bar))) + (update-display progress-bar)))) + +(defmethod finish-display (progress-bar) + (update-display progress-bar) + (setf (end-time progress-bar) (get-internal-real-time)) + (terpri) + (format t "~:D bytes in ~$ seconds (~$KB/sec)~%" + (total progress-bar) + (elapsed-time progress-bar) + (/ (units-per-second progress-bar) 1024)) + (finish-output)) + +(defmethod elapsed-time (progress-bar) + (/ (- (end-time progress-bar) (start-time progress-bar)) + internal-time-units-per-second)) + +(defmethod units-per-second (progress-bar) + (if (plusp (elapsed-time progress-bar)) + (/ (total progress-bar) (elapsed-time progress-bar)) + 0)) + +(defun kb/sec (progress-bar) + (/ (units-per-second progress-bar) 1024)) + + + +(defparameter *uncertain-progress-chars* "?") + +(defclass uncertain-size-progress-bar (progress-bar) + ((progress-char-index + :initarg :progress-char-index + :accessor progress-char-index) + (units-per-char + :initarg :units-per-char + :accessor units-per-char)) + (:default-initargs + :total 0 + :progress-char-index 0 + :units-per-char (floor (expt 1024 2) 50))) + +(defmethod update-progress :after ((progress-bar uncertain-size-progress-bar) + unit-count) + (incf (total progress-bar) unit-count)) + +(defmethod progress-character ((progress-bar uncertain-size-progress-bar)) + (let ((index (progress-char-index progress-bar))) + (prog1 + (char *uncertain-progress-chars* index) + (setf (progress-char-index progress-bar) + (mod (1+ index) (length *uncertain-progress-chars*)))))) + +(defmethod update-display ((progress-bar uncertain-size-progress-bar)) + (setf (last-update-time progress-bar) (get-internal-real-time)) + (multiple-value-bind (chars pend) + (floor (pending progress-bar) (units-per-char progress-bar)) + (setf (pending progress-bar) pend) + (dotimes (i chars) + (write-char (progress-character progress-bar)) + (incf (characters-so-far progress-bar)) + (when (<= (character-count progress-bar) + (characters-so-far progress-bar)) + (terpri) + (setf (characters-so-far progress-bar) 0) + (finish-output))) + (finish-output))) + +(defun make-progress-bar (total) + (if (or (not total) (zerop total)) + (make-instance 'uncertain-size-progress-bar) + (make-instance 'progress-bar :total total))) + diff --git a/sbcl/.quicklisp/quicklisp/quicklisp.asd b/sbcl/.quicklisp/quicklisp/quicklisp.asd new file mode 100644 index 0000000..158a1b4 --- /dev/null +++ b/sbcl/.quicklisp/quicklisp/quicklisp.asd @@ -0,0 +1,36 @@ +;;;; quicklisp.asd + +(defpackage #:ql-info + (:export #:*version*)) + +(defvar ql-info:*version* + (with-open-file (stream (merge-pathnames "version.txt" *load-truename*)) + (read-line stream))) + +(asdf:defsystem #:quicklisp + :description "The Quicklisp client application." + :author "Zach Beane " + :license "BSD-style" + :serial t + :version #.(remove-if-not #'digit-char-p ql-info:*version*) + :components ((:file "package") + (:file "utils") + (:file "config") + (:file "impl") + (:file "impl-util") + (:file "network") + (:file "progress") + (:file "http") + (:file "deflate") + (:file "minitar") + (:file "cdb") + (:file "dist") + (:file "setup") + (:file "client") + (:file "fetch-gzipped") + (:file "client-info") + (:file "client-update") + (:file "dist-update") + (:file "misc") + (:file "local-projects") + (:file "bundle"))) diff --git a/sbcl/.quicklisp/quicklisp/setup.lisp b/sbcl/.quicklisp/quicklisp/setup.lisp new file mode 100644 index 0000000..edbd4c6 --- /dev/null +++ b/sbcl/.quicklisp/quicklisp/setup.lisp @@ -0,0 +1,249 @@ +(in-package #:quicklisp) + +(defun show-wrapped-list (words &key (indent 4) (margin 60)) + (let ((*print-right-margin* margin) + (*print-pretty* t) + (*print-escape* nil) + (prefix (make-string indent :initial-element #\Space))) + (pprint-logical-block (nil words :per-line-prefix prefix) + (pprint-fill *standard-output* (sort (copy-seq words) #'string<) nil)) + (fresh-line) + (finish-output))) + +(defun recursively-install (name) + (labels ((recurse (name) + (let ((system (find-system name))) + (unless system + (error "Unknown system ~S" name)) + (ensure-installed system) + (mapcar #'recurse (required-systems system)) + name))) + (with-consistent-dists + (recurse name)))) + +(defclass load-strategy () + ((name + :initarg :name + :accessor name) + (asdf-systems + :initarg :asdf-systems + :accessor asdf-systems) + (quicklisp-systems + :initarg :quicklisp-systems + :accessor quicklisp-systems))) + +(defmethod print-object ((strategy load-strategy) stream) + (print-unreadable-object (strategy stream :type t) + (format stream "~S (~D asdf, ~D quicklisp)" + (name strategy) + (length (asdf-systems strategy)) + (length (quicklisp-systems strategy))))) + +(defgeneric quicklisp-releases (strategy) + (:method (strategy) + (remove-duplicates (mapcar 'release (quicklisp-systems strategy))))) + +(defgeneric quicklisp-release-table (strategy) + (:method ((strategy load-strategy)) + (let ((table (make-hash-table))) + (dolist (system (quicklisp-systems strategy)) + (push system (gethash (release system) table nil))) + table))) + +(define-condition system-not-found (error) + ((name + :initarg :name + :reader system-not-found-name)) + (:report (lambda (condition stream) + (format stream "System ~S not found" + (system-not-found-name condition)))) + (:documentation "This condition is signaled by QUICKLOAD when a + system given to load is not available via ASDF or a Quicklisp + dist.")) + +(defun compute-load-strategy (name) + (setf name (string-downcase name)) + (let ((asdf-systems '()) + (quicklisp-systems '())) + (labels ((recurse (name) + (let ((asdf-system (asdf:find-system name nil)) + (quicklisp-system (find-system name))) + (cond (asdf-system + (push asdf-system asdf-systems)) + (quicklisp-system + (push quicklisp-system quicklisp-systems) + (dolist (subname (required-systems quicklisp-system)) + (recurse subname))) + (t + (cerror "Try again" + 'system-not-found + :name name) + (recurse name)))))) + (with-consistent-dists + (recurse name))) + (make-instance 'load-strategy + :name name + :asdf-systems (remove-duplicates asdf-systems) + :quicklisp-systems (remove-duplicates quicklisp-systems)))) + +(defun show-load-strategy (strategy) + (format t "To load ~S:~%" (name strategy)) + (let ((asdf-systems (asdf-systems strategy)) + (releases (quicklisp-releases strategy))) + (when asdf-systems + (format t " Load ~D ASDF system~:P:~%" (length asdf-systems)) + (show-wrapped-list (mapcar 'asdf:component-name asdf-systems))) + (when releases + (format t " Install ~D Quicklisp release~:P:~%" (length releases)) + (show-wrapped-list (mapcar 'name releases))))) + +(defvar *macroexpand-progress-in-progress* nil) + +(defun macroexpand-progress-fun (old-hook &key (char #\.) + (chars-per-line 50) + (forms-per-char 250)) + (let ((output-so-far 0) + (seen-so-far 0)) + (labels ((finish-line () + (when (plusp output-so-far) + (dotimes (i (- chars-per-line output-so-far)) + (write-char char)) + (terpri) + (setf output-so-far 0))) + (show-string (string) + (let* ((length (length string)) + (new-output (+ length output-so-far))) + (cond ((< chars-per-line new-output) + (finish-line) + (write-string string) + (setf output-so-far length)) + (t + (write-string string) + (setf output-so-far new-output)))) + (finish-output)) + (show-package (name) + ;; Only show package markers when compiling. Showing + ;; them when loading shows a bunch of ASDF system + ;; package noise. + (when *compile-file-pathname* + (finish-line) + (show-string (format nil "[package ~(~A~)]" name))))) + (lambda (fun form env) + (when (and (consp form) + (eq (first form) 'cl:defpackage) + (ignore-errors (string (second form)))) + (show-package (second form))) + (incf seen-so-far) + (when (<= forms-per-char seen-so-far) + (setf seen-so-far 0) + (write-char char) + (finish-output) + (incf output-so-far) + (when (<= chars-per-line output-so-far) + (setf output-so-far 0) + (terpri) + (finish-output))) + (funcall old-hook fun form env))))) + +(defun call-with-macroexpand-progress (fun) + (let ((*macroexpand-hook* (if *macroexpand-progress-in-progress* + *macroexpand-hook* + (macroexpand-progress-fun *macroexpand-hook*))) + (*macroexpand-progress-in-progress* t)) + (funcall fun) + (terpri))) + +(defun apply-load-strategy (strategy) + (map nil 'ensure-installed (quicklisp-releases strategy)) + (call-with-macroexpand-progress + (lambda () + (format t "~&; Loading ~S~%" (name strategy)) + (asdf:load-system (name strategy) :verbose nil)))) + +(defun autoload-system-and-dependencies (name &key prompt) + "Try to load the system named by NAME, automatically loading any +Quicklisp-provided systems first, and catching ASDF missing +dependencies too if possible." + (setf name (string-downcase name)) + (with-simple-restart (abort "Give up on ~S" name) + (let ((tried-so-far (make-hash-table :test 'equalp))) + (tagbody + retry + (handler-case + (let ((strategy (compute-load-strategy name))) + (show-load-strategy strategy) + (when (or (not prompt) + (press-enter-to-continue)) + (apply-load-strategy strategy))) + (asdf:missing-dependency-of-version (c) + ;; Nothing Quicklisp can do to recover from this, so just + ;; resignal + (error c)) + (asdf:missing-dependency (c) + (let ((parent (asdf::missing-required-by c)) + (missing (asdf::missing-requires c))) + (typecase parent + ((or null asdf:system) + ;; NIL parent comes from :defsystem-depends-on failures + (if (gethash missing tried-so-far) + (error "Dependency looping -- already tried to load ~ + ~A" missing) + (setf (gethash missing tried-so-far) missing)) + (autoload-system-and-dependencies missing + :prompt prompt) + (go retry)) + (t + ;; Error isn't from a system dependency, so there's + ;; nothing to autoload + (error c)))))))) + name)) + +(defvar *initial-dist-url* + "http://beta.quicklisp.org/dist/quicklisp.txt") + +(defun dists-initialized-p () + (not (not (ignore-errors (truename (qmerge "dists/")))))) + +(defun quickstart-parameter (name &optional default) + (let* ((package (find-package '#:quicklisp-quickstart)) + (symbol (and package (find-symbol (string '#:*quickstart-parameters*) + package))) + (plist (and symbol (symbol-value symbol))) + (parameter (and plist (getf plist name)))) + (or parameter default))) + +(defun maybe-initial-setup () + "Run the steps needed when Quicklisp setup is run for the first time +after the quickstart installation." + (let ((quickstart-proxy-url (quickstart-parameter :proxy-url)) + (quickstart-initial-dist-url (quickstart-parameter :initial-dist-url))) + (when (and quickstart-proxy-url (not *proxy-url*)) + (setf *proxy-url* quickstart-proxy-url) + (setf (config-value "proxy-url") quickstart-proxy-url)) + (unless (dists-initialized-p) + (let ((target (qmerge "dists/quicklisp/distinfo.txt")) + (url (or quickstart-initial-dist-url + *initial-dist-url*))) + (ensure-directories-exist target) + (install-dist url :prompt nil))))) + +(defun setup () + (unless (member 'system-definition-searcher + asdf:*system-definition-search-functions*) + (setf asdf:*system-definition-search-functions* + (append asdf:*system-definition-search-functions* + (list 'local-projects-searcher + 'system-definition-searcher)))) + (let ((files (nconc (directory (qmerge "local-init/*.lisp")) + (directory (qmerge "local-init/*.cl"))))) + (with-simple-restart (abort "Stop loading local setup files") + (dolist (file (sort files #'string< :key #'pathname-name)) + (with-simple-restart (skip "Skip local setup file ~S" file) + ;; Don't try to load Emacs lock files, other hidden files + (unless (char= (char (pathname-name file) 0) + #\.) + (load file)))))) + (maybe-initial-setup) + (ensure-directories-exist (qmerge "local-projects/")) + (pushnew :quicklisp *features*) + t) diff --git a/sbcl/.quicklisp/quicklisp/utils.lisp b/sbcl/.quicklisp/quicklisp/utils.lisp new file mode 100644 index 0000000..71a89ef --- /dev/null +++ b/sbcl/.quicklisp/quicklisp/utils.lisp @@ -0,0 +1,124 @@ +;;;; utils.lisp + +(in-package #:ql-util) + +(defun write-line-to-file (string file) + (with-open-file (stream file + :direction :output + :if-exists :supersede) + (write-line string stream))) + +(defvar *do-not-prompt* nil + "When *DO-NOT-PROMPT* is true, PRESS-ENTER-TO-CONTINUE returns true + without user interaction.") + +(defmacro without-prompting (&body body) + "Evaluate BODY in an environment where PRESS-ENTER-TO-CONTINUE + always returns true without prompting for the user to press enter." + `(let ((*do-not-prompt* t)) + ,@body)) + +(defun press-enter-to-continue () + (when *do-not-prompt* + (return-from press-enter-to-continue t)) + (format *query-io* "~&Press Enter to continue.~%") + (let ((result (read-line *query-io*))) + (zerop (length result)))) + +(defun replace-file (from to) + "Like RENAME-FILE, but deletes TO if it exists, first." + (when (probe-file to) + (delete-file to)) + (rename-file from to)) + +(defun copy-file (from to &key (if-exists :rename-and-delete)) + "Copy the file FROM to TO." + (let* ((buffer-size 8192) + (buffer (make-array buffer-size :element-type '(unsigned-byte 8)))) + (with-open-file (from-stream from :element-type '(unsigned-byte 8)) + (with-open-file (to-stream to :element-type '(unsigned-byte 8) + :direction :output + :if-exists if-exists) + (let ((length (file-length from-stream))) + (multiple-value-bind (full leftover) + (floor length buffer-size) + (dotimes (i full) + (read-sequence buffer from-stream) + (write-sequence buffer to-stream)) + (read-sequence buffer from-stream) + (write-sequence buffer to-stream :end leftover))))) + (probe-file to))) + +(defun ensure-file-exists (pathname) + (open pathname :direction :probe :if-does-not-exist :create)) + +(defun delete-file-if-exists (pathname) + (when (probe-file pathname) + (delete-file pathname))) + +(defun split-spaces (line) + (let ((words '()) + (mark 0) + (pos 0)) + (labels ((finish () + (setf pos (length line)) + (save) + (return-from split-spaces (nreverse words))) + (save () + (when (< mark pos) + (push (subseq line mark pos) words))) + (mark () + (setf mark pos)) + (in-word (char) + (case char + (#\Space + (save) + #'in-space) + (t + #'in-word))) + (in-space (char) + (case char + (#\Space + #'in-space) + (t + (mark) + #'in-word)))) + (let ((state #'in-word)) + (dotimes (i (length line) (finish)) + (setf pos i) + (setf state (funcall state (char line i)))))))) + +(defun first-line (file) + (with-open-file (stream file) + (values (read-line stream)))) + +(defun (setf first-line) (line file) + (with-open-file (stream file :direction :output + :if-exists :rename-and-delete) + (write-line line stream))) + +(defun file-size (file) + (with-open-file (stream file :element-type '(unsigned-byte 8)) + (file-length stream))) + +(defun safely-read (stream) + "Read one form from STREAM with *READ-EVAL* bound to NIL." + (let ((*read-eval* nil)) + (read stream))) + +(defun safely-read-file (file) + "Read the first form from FILE with SAFELY-READ." + (with-open-file (stream file) + (safely-read stream))) + +(defun make-versions-url (url) + "Given an URL that looks like http://foo/bar.ext, return +http://foo/bar-versions.txt." + (let ((suffix-pos (position #\. url :from-end t))) + (unless suffix-pos + (error "Can't make a versions URL from ~A" url)) + (let ((extension (subseq url suffix-pos))) + (concatenate 'string + (subseq url 0 suffix-pos) + "-versions" + extension)))) diff --git a/sbcl/.quicklisp/quicklisp/version.txt b/sbcl/.quicklisp/quicklisp/version.txt new file mode 100644 index 0000000..69bd127 --- /dev/null +++ b/sbcl/.quicklisp/quicklisp/version.txt @@ -0,0 +1 @@ +2020-01-04 diff --git a/sbcl/.quicklisp/setup.lisp b/sbcl/.quicklisp/setup.lisp new file mode 100644 index 0000000..0b2847d --- /dev/null +++ b/sbcl/.quicklisp/setup.lisp @@ -0,0 +1,135 @@ +(defpackage #:ql-setup + (:use #:cl) + (:export #:*quicklisp-home* + #:qmerge + #:qenough)) + +(in-package #:ql-setup) + +(unless *load-truename* + (error "This file must be LOADed to set up quicklisp.")) + +(defvar *quicklisp-home* + (make-pathname :name nil :type nil + :defaults *load-truename*)) + +(defun qmerge (pathname) + "Return PATHNAME merged with the base Quicklisp directory." + (merge-pathnames pathname *quicklisp-home*)) + +(defun qenough (pathname) + (enough-namestring pathname *quicklisp-home*)) + +;;; ASDF is a hard requirement of quicklisp. Make sure it's either +;;; already loaded or load it from quicklisp's bundled version. + +(defvar *required-asdf-version* "2.26") + +;;; Put ASDF's fasls in a separate directory + +(defun implementation-signature () + "Return a string suitable for discriminating different +implementations, or similar implementations with possibly-incompatible +FASLs." + ;; XXX Will this have problems with stuff like threads vs + ;; non-threads fasls? + (let ((*print-pretty* nil)) + (format nil "lisp-implementation-type: ~A~%~ + lisp-implementation-version: ~A~%~ + machine-type: ~A~%~ + machine-version: ~A~%" + (lisp-implementation-type) + (lisp-implementation-version) + (machine-type) + (machine-version)))) + +(defun dumb-string-hash (string) + "Produce a six-character hash of STRING." + (let ((hash #xD13CCD13)) + (loop for char across string + for value = (char-code char) + do + (setf hash (logand #xFFFFFFFF + (logxor (ash hash 5) + (ash hash -27) + value)))) + (subseq (format nil "~(~36,6,'0R~)" (mod hash 88888901)) + 0 6))) + +(defun asdf-fasl-pathname () + "Return a pathname suitable for storing the ASDF FASL, separated +from ASDF FASLs from incompatible implementations. Also, save a file +in the directory with the implementation signature, if it doesn't +already exist." + (let* ((implementation-signature (implementation-signature)) + (original-fasl (compile-file-pathname (qmerge "asdf.lisp"))) + (fasl + (qmerge (make-pathname + :defaults original-fasl + :directory + (list :relative + "cache" + "asdf-fasls" + (dumb-string-hash implementation-signature))))) + (signature-file (merge-pathnames "signature.txt" fasl))) + (ensure-directories-exist fasl) + (unless (probe-file signature-file) + (with-open-file (stream signature-file :direction :output) + (write-string implementation-signature stream))) + fasl)) + +(defun ensure-asdf-loaded () + "Try several methods to make sure that a sufficiently-new ASDF is +loaded: first try (require 'asdf), then loading the ASDF FASL, then +compiling asdf.lisp to a FASL and then loading it." + (let ((source (qmerge "asdf.lisp"))) + (labels ((asdf-symbol (name) + (let ((asdf-package (find-package '#:asdf))) + (when asdf-package + (find-symbol (string name) asdf-package)))) + (version-satisfies (version) + (let ((vs-fun (asdf-symbol '#:version-satisfies)) + (vfun (asdf-symbol '#:asdf-version))) + (when (and vs-fun vfun + (fboundp vs-fun) + (fboundp vfun)) + (funcall vs-fun (funcall vfun) version))))) + (block nil + (macrolet ((try (&body asdf-loading-forms) + `(progn + (handler-bind ((warning #'muffle-warning)) + (ignore-errors + ,@asdf-loading-forms)) + (when (version-satisfies *required-asdf-version*) + (return t))))) + (try) + (try (require 'asdf)) + (let ((fasl (asdf-fasl-pathname))) + (try (load fasl :verbose nil)) + (try (load (compile-file source :verbose nil :output-file fasl)))) + (error "Could not load ASDF ~S or newer" *required-asdf-version*)))))) + +(ensure-asdf-loaded) + +;;; +;;; Quicklisp sometimes must upgrade ASDF. Ugrading ASDF will blow +;;; away existing ASDF methods, so e.g. FASL recompilation :around +;;; methods would be lost. This config file will make it possible to +;;; ensure ASDF can be configured before loading Quicklisp itself via +;;; ASDF. Thanks to Nikodemus Siivola for pointing out this issue. +;;; + +(let ((asdf-init (probe-file (qmerge "asdf-config/init.lisp")))) + (when asdf-init + (with-simple-restart (skip "Skip loading ~S" asdf-init) + (load asdf-init :verbose nil :print nil)))) + +(push (qmerge "quicklisp/") asdf:*central-registry*) + +(let ((*compile-print* nil) + (*compile-verbose* nil) + (*load-verbose* nil) + (*load-print* nil)) + (asdf:oos 'asdf:load-op "quicklisp" :verbose nil)) + +(quicklisp:setup) diff --git a/sbcl/.quicklisp/tmp/install-dist-distinfo.txt b/sbcl/.quicklisp/tmp/install-dist-distinfo.txt new file mode 100644 index 0000000..86798cc --- /dev/null +++ b/sbcl/.quicklisp/tmp/install-dist-distinfo.txt @@ -0,0 +1,7 @@ +name: quicklisp +version: 2019-12-27 +system-index-url: http://beta.quicklisp.org/dist/quicklisp/2019-12-27/systems.txt +release-index-url: http://beta.quicklisp.org/dist/quicklisp/2019-12-27/releases.txt +archive-base-url: http://beta.quicklisp.org/ +canonical-distinfo-url: http://beta.quicklisp.org/dist/quicklisp/2019-12-27/distinfo.txt +distinfo-subscription-url: http://beta.quicklisp.org/dist/quicklisp.txt diff --git a/sbcl/.quicklisp/tmp/quicklisp.tar b/sbcl/.quicklisp/tmp/quicklisp.tar new file mode 100644 index 0000000000000000000000000000000000000000..77e7ed7b9194bef4bd8911b08f199965ec4b52c0 GIT binary patch literal 256000 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�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 I0z)bU0RODTQvd(} literal 0 HcmV?d00001 diff --git a/sbcl/.quicklisp/tmp/release-install.tar b/sbcl/.quicklisp/tmp/release-install.tar new file mode 100644 index 0000000000000000000000000000000000000000..6ad0c2175bdf4e8b5a7ec3540f5beb84714d6d73 GIT binary patch literal 20480 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 literal 0 HcmV?d00001 diff --git a/sbcl/.sbclrc b/sbcl/.sbclrc new file mode 100644 index 0000000..c6658cd --- /dev/null +++ b/sbcl/.sbclrc @@ -0,0 +1,8 @@ + +;;; The following lines added by ql:add-to-init-file: +#-quicklisp +(let ((quicklisp-init (merge-pathnames ".quicklisp/setup.lisp" + (user-homedir-pathname)))) + (when (probe-file quicklisp-init) + (load quicklisp-init))) + diff --git a/sbcl/quicklisp.lisp b/sbcl/quicklisp.lisp new file mode 100644 index 0000000..6cda472 --- /dev/null +++ b/sbcl/quicklisp.lisp @@ -0,0 +1,1757 @@ +;;;; +;;;; This is quicklisp.lisp, the quickstart file for Quicklisp. To use +;;;; it, start Lisp, then (load "quicklisp.lisp") +;;;; +;;;; Quicklisp is beta software and comes with no warranty of any kind. +;;;; +;;;; For more information about the Quicklisp beta, see: +;;;; +;;;; http://www.quicklisp.org/beta/ +;;;; +;;;; If you have any questions or comments about Quicklisp, please +;;;; contact: +;;;; +;;;; Zach Beane +;;;; + +(cl:in-package #:cl-user) +(cl:defpackage #:qlqs-user + (:use #:cl)) +(cl:in-package #:qlqs-user) + +(defpackage #:qlqs-info + (:export #:*version*)) + +(defvar qlqs-info:*version* "2015-01-28") + +(defpackage #:qlqs-impl + (:use #:cl) + (:export #:*implementation*) + (:export #:definterface + #:defimplementation) + (:export #:lisp + #:abcl + #:allegro + #:ccl + #:clasp + #:clisp + #:cmucl + #:cormanlisp + #:ecl + #:gcl + #:lispworks + #:mkcl + #:scl + #:sbcl)) + +(defpackage #:qlqs-impl-util + (:use #:cl #:qlqs-impl) + (:export #:call-with-quiet-compilation)) + +(defpackage #:qlqs-network + (:use #:cl #:qlqs-impl) + (:export #:open-connection + #:write-octets + #:read-octets + #:close-connection + #:with-connection)) + +(defpackage #:qlqs-progress + (:use #:cl) + (:export #:make-progress-bar + #:start-display + #:update-progress + #:finish-display)) + +(defpackage #:qlqs-http + (:use #:cl #:qlqs-network #:qlqs-progress) + (:export #:fetch + #:*proxy-url* + #:*maximum-redirects* + #:*default-url-defaults*)) + +(defpackage #:qlqs-minitar + (:use #:cl) + (:export #:unpack-tarball)) + +(defpackage #:quicklisp-quickstart + (:use #:cl #:qlqs-impl #:qlqs-impl-util #:qlqs-http #:qlqs-minitar) + (:export #:install + #:help + #:*proxy-url* + #:*asdf-url* + #:*quicklisp-tar-url* + #:*setup-url* + #:*help-message* + #:*after-load-message* + #:*after-initial-setup-message*)) + + +;;; +;;; Defining implementation-specific packages and functionality +;;; + +(in-package #:qlqs-impl) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defun error-unimplemented (&rest args) + (declare (ignore args)) + (error "Not implemented"))) + +(defmacro neuter-package (name) + `(eval-when (:compile-toplevel :load-toplevel :execute) + (let ((definition (fdefinition 'error-unimplemented))) + (do-external-symbols (symbol ,(string name)) + (unless (fboundp symbol) + (setf (fdefinition symbol) definition)))))) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defun feature-expression-passes-p (expression) + (cond ((keywordp expression) + (member expression *features*)) + ((consp expression) + (case (first expression) + (or + (some 'feature-expression-passes-p (rest expression))) + (and + (every 'feature-expression-passes-p (rest expression))))) + (t (error "Unrecognized feature expression -- ~S" expression))))) + + +(defmacro define-implementation-package (feature package-name &rest options) + (let* ((output-options '((:use) + (:export #:lisp))) + (prep (cdr (assoc :prep options))) + (class-option (cdr (assoc :class options))) + (class (first class-option)) + (superclasses (rest class-option)) + (import-options '()) + (effectivep (feature-expression-passes-p feature))) + (dolist (option options) + (ecase (first option) + ((:prep :class)) + ((:import-from + :import) + (push option import-options)) + ((:export + :shadow + :intern + :documentation) + (push option output-options)) + ((:reexport-from) + (push (cons :export (cddr option)) output-options) + (push (cons :import-from (cdr option)) import-options)))) + `(eval-when (:compile-toplevel :load-toplevel :execute) + ,@(when effectivep + prep) + (defclass ,class ,superclasses ()) + (defpackage ,package-name ,@output-options + ,@(when effectivep + import-options)) + ,@(when effectivep + `((setf *implementation* (make-instance ',class)))) + ,@(unless effectivep + `((neuter-package ,package-name)))))) + +(defmacro definterface (name lambda-list &body options) + (let* ((forbidden (intersection lambda-list lambda-list-keywords)) + (gf-options (remove :implementation options :key #'first)) + (implementations (set-difference options gf-options))) + (when forbidden + (error "~S not allowed in definterface lambda list" forbidden)) + (flet ((method-option (class body) + `(:method ((*implementation* ,class) ,@lambda-list) + ,@body))) + (let ((generic-name (intern (format nil "%~A" name)))) + `(eval-when (:compile-toplevel :load-toplevel :execute) + (defgeneric ,generic-name (lisp ,@lambda-list) + ,@gf-options + ,@(mapcar (lambda (implementation) + (destructuring-bind (class &rest body) + (rest implementation) + (method-option class body))) + implementations)) + (defun ,name ,lambda-list + (,generic-name *implementation* ,@lambda-list))))))) + +(defmacro defimplementation (name-and-options + lambda-list &body body) + (destructuring-bind (name &key (for t) qualifier) + (if (consp name-and-options) + name-and-options + (list name-and-options)) + (unless for + (error "You must specify an implementation name.")) + (let ((generic-name (find-symbol (format nil "%~A" name)))) + (unless (and generic-name + (fboundp generic-name)) + (error "~S does not name an implementation function" name)) + `(defmethod ,generic-name + ,@(when qualifier (list qualifier)) + ,(list* `(*implementation* ,for) lambda-list) ,@body)))) + + +;;; Bootstrap implementations + +(defvar *implementation* nil) +(defclass lisp () ()) + + +;;; Allegro Common Lisp + +(define-implementation-package :allegro #:qlqs-allegro + (:documentation + "Allegro Common Lisp - http://www.franz.com/products/allegrocl/") + (:class allegro) + (:reexport-from #:socket + #:make-socket) + (:reexport-from #:excl + #:read-vector)) + + +;;; Armed Bear Common Lisp + +(define-implementation-package :abcl #:qlqs-abcl + (:documentation + "Armed Bear Common Lisp - http://common-lisp.net/project/armedbear/") + (:class abcl) + (:reexport-from #:system + #:make-socket + #:get-socket-stream)) + +;;; Clozure CL + +(define-implementation-package :ccl #:qlqs-ccl + (:documentation + "Clozure Common Lisp - http://www.clozure.com/clozurecl.html") + (:class ccl) + (:reexport-from #:ccl + #:make-socket)) + + +;;; CLASP + +(define-implementation-package :clasp #:qlqs-clasp + (:documentation "CLASP - http://github.com/drmeister/clasp") + (:class clasp) + (:prep + (require 'sockets)) + (:intern #:host-network-address) + (:reexport-from #:sb-bsd-sockets + #:get-host-by-name + #:host-ent-address + #:socket-connect + #:socket-make-stream + #:inet-socket)) + + +;;; GNU CLISP + +(define-implementation-package :clisp #:qlqs-clisp + (:documentation "GNU CLISP - http://clisp.cons.org/") + (:class clisp) + (:reexport-from #:socket + #:socket-connect) + (:reexport-from #:ext + #:read-byte-sequence)) + + +;;; CMUCL + +(define-implementation-package :cmu #:qlqs-cmucl + (:documentation "CMU Common Lisp - http://www.cons.org/cmucl/") + (:class cmucl) + (:reexport-from #:ext + #:*gc-verbose*) + (:reexport-from #:system + #:make-fd-stream) + (:reexport-from #:extensions + #:connect-to-inet-socket)) + +(defvar qlqs-cmucl:*gc-verbose* nil) + + +;;; Scieneer CL + +(define-implementation-package :scl #:qlqs-scl + (:documentation "Scieneer Common Lisp - http://www.scieneer.com/scl/") + (:class scl) + (:reexport-from #:system + #:make-fd-stream) + (:reexport-from #:extensions + #:connect-to-inet-socket)) + +;;; ECL + +(define-implementation-package :ecl #:qlqs-ecl + (:documentation "ECL - http://ecls.sourceforge.net/") + (:class ecl) + (:prep + (require 'sockets)) + (:intern #:host-network-address) + (:reexport-from #:sb-bsd-sockets + #:get-host-by-name + #:host-ent-address + #:socket-connect + #:socket-make-stream + #:inet-socket)) + + +;;; LispWorks + +(define-implementation-package :lispworks #:qlqs-lispworks + (:documentation "LispWorks - http://www.lispworks.com/") + (:class lispworks) + (:prep + (require "comm")) + (:reexport-from #:comm + #:open-tcp-stream + #:get-host-entry)) + + +;;; SBCL + +(define-implementation-package :sbcl #:qlqs-sbcl + (:class sbcl) + (:documentation + "Steel Bank Common Lisp - http://www.sbcl.org/") + (:prep + (require 'sb-bsd-sockets)) + (:intern #:host-network-address) + (:reexport-from #:sb-ext + #:compiler-note) + (:reexport-from #:sb-bsd-sockets + #:get-host-by-name + #:inet-socket + #:host-ent-address + #:socket-connect + #:socket-make-stream)) + +;;; MKCL + +(define-implementation-package :mkcl #:qlqs-mkcl + (:class mkcl) + (:documentation + "ManKai Common Lisp - http://common-lisp.net/project/mkcl/") + (:prep + (require 'sockets)) + (:intern #:host-network-address) + (:reexport-from #:sb-bsd-sockets + #:get-host-by-name + #:inet-socket + #:host-ent-address + #:socket-connect + #:socket-make-stream)) + +;;; +;;; Utility function +;;; + +(in-package #:qlqs-impl-util) + +(definterface call-with-quiet-compilation (fun) + (:implementation t + (let ((*load-verbose* nil) + (*compile-verbose* nil) + (*load-print* nil) + (*compile-print* nil)) + (handler-bind ((warning #'muffle-warning)) + (funcall fun))))) + +(defimplementation (call-with-quiet-compilation :for sbcl :qualifier :around) + (fun) + (declare (ignorable fun)) + (handler-bind ((qlqs-sbcl:compiler-note #'muffle-warning)) + (call-next-method))) + +(defimplementation (call-with-quiet-compilation :for cmucl :qualifier :around) + (fun) + (declare (ignorable fun)) + (let ((qlqs-cmucl:*gc-verbose* nil)) + (call-next-method))) + + +;;; +;;; Low-level networking implementations +;;; + +(in-package #:qlqs-network) + +(definterface host-address (host) + (:implementation t + host) + (:implementation mkcl + (qlqs-mkcl:host-ent-address (qlqs-mkcl:get-host-by-name host))) + (:implementation sbcl + (qlqs-sbcl:host-ent-address (qlqs-sbcl:get-host-by-name host)))) + +(definterface open-connection (host port) + (:implementation t + (declare (ignorable host port)) + (error "Sorry, quicklisp in implementation ~S is not supported yet." + (lisp-implementation-type))) + (:implementation allegro + (qlqs-allegro:make-socket :remote-host host + :remote-port port)) + (:implementation abcl + (let ((socket (qlqs-abcl:make-socket host port))) + (qlqs-abcl:get-socket-stream socket :element-type '(unsigned-byte 8)))) + (:implementation ccl + (qlqs-ccl:make-socket :remote-host host + :remote-port port)) + (:implementation clasp + (let* ((endpoint (qlqs-clasp:host-ent-address + (qlqs-clasp:get-host-by-name host))) + (socket (make-instance 'qlqs-clasp:inet-socket + :protocol :tcp + :type :stream))) + (qlqs-clasp:socket-connect socket endpoint port) + (qlqs-clasp:socket-make-stream socket + :element-type '(unsigned-byte 8) + :input t + :output t + :buffering :full))) + (:implementation clisp + (qlqs-clisp:socket-connect port host :element-type '(unsigned-byte 8))) + (:implementation cmucl + (let ((fd (qlqs-cmucl:connect-to-inet-socket host port))) + (qlqs-cmucl:make-fd-stream fd + :element-type '(unsigned-byte 8) + :binary-stream-p t + :input t + :output t))) + (:implementation scl + (let ((fd (qlqs-scl:connect-to-inet-socket host port))) + (qlqs-scl:make-fd-stream fd + :element-type '(unsigned-byte 8) + :input t + :output t))) + (:implementation ecl + (let* ((endpoint (qlqs-ecl:host-ent-address + (qlqs-ecl:get-host-by-name host))) + (socket (make-instance 'qlqs-ecl:inet-socket + :protocol :tcp + :type :stream))) + (qlqs-ecl:socket-connect socket endpoint port) + (qlqs-ecl:socket-make-stream socket + :element-type '(unsigned-byte 8) + :input t + :output t + :buffering :full))) + (:implementation lispworks + (qlqs-lispworks:open-tcp-stream host port + :direction :io + :errorp t + :read-timeout nil + :element-type '(unsigned-byte 8) + :timeout 5)) + (:implementation mkcl + (let* ((endpoint (qlqs-mkcl:host-ent-address + (qlqs-mkcl:get-host-by-name host))) + (socket (make-instance 'qlqs-mkcl:inet-socket + :protocol :tcp + :type :stream))) + (qlqs-mkcl:socket-connect socket endpoint port) + (qlqs-mkcl:socket-make-stream socket + :element-type '(unsigned-byte 8) + :input t + :output t + :buffering :full))) + (:implementation sbcl + (let* ((endpoint (qlqs-sbcl:host-ent-address + (qlqs-sbcl:get-host-by-name host))) + (socket (make-instance 'qlqs-sbcl:inet-socket + :protocol :tcp + :type :stream))) + (qlqs-sbcl:socket-connect socket endpoint port) + (qlqs-sbcl:socket-make-stream socket + :element-type '(unsigned-byte 8) + :input t + :output t + :buffering :full)))) + +(definterface read-octets (buffer connection) + (:implementation t + (read-sequence buffer connection)) + (:implementation allegro + (qlqs-allegro:read-vector buffer connection)) + (:implementation clisp + (qlqs-clisp:read-byte-sequence buffer connection + :no-hang nil + :interactive t))) + +(definterface write-octets (buffer connection) + (:implementation t + (write-sequence buffer connection) + (finish-output connection))) + +(definterface close-connection (connection) + (:implementation t + (ignore-errors (close connection)))) + +(definterface call-with-connection (host port fun) + (:implementation t + (let (connection) + (unwind-protect + (progn + (setf connection (open-connection host port)) + (funcall fun connection)) + (when connection + (close connection)))))) + +(defmacro with-connection ((connection host port) &body body) + `(call-with-connection ,host ,port (lambda (,connection) ,@body))) + + +;;; +;;; A text progress bar +;;; + +(in-package #:qlqs-progress) + +(defclass progress-bar () + ((start-time + :initarg :start-time + :accessor start-time) + (end-time + :initarg :end-time + :accessor end-time) + (progress-character + :initarg :progress-character + :accessor progress-character) + (character-count + :initarg :character-count + :accessor character-count + :documentation "How many characters wide is the progress bar?") + (characters-so-far + :initarg :characters-so-far + :accessor characters-so-far) + (update-interval + :initarg :update-interval + :accessor update-interval + :documentation "Update the progress bar display after this many + internal-time units.") + (last-update-time + :initarg :last-update-time + :accessor last-update-time + :documentation "The display was last updated at this time.") + (total + :initarg :total + :accessor total + :documentation "The total number of units tracked by this progress bar.") + (progress + :initarg :progress + :accessor progress + :documentation "How far in the progress are we?") + (pending + :initarg :pending + :accessor pending + :documentation "How many raw units should be tracked in the next + display update?")) + (:default-initargs + :progress-character #\= + :character-count 50 + :characters-so-far 0 + :update-interval (floor internal-time-units-per-second 4) + :last-update-time 0 + :total 0 + :progress 0 + :pending 0)) + +(defgeneric start-display (progress-bar)) +(defgeneric update-progress (progress-bar unit-count)) +(defgeneric update-display (progress-bar)) +(defgeneric finish-display (progress-bar)) +(defgeneric elapsed-time (progress-bar)) +(defgeneric units-per-second (progress-bar)) + +(defmethod start-display (progress-bar) + (setf (last-update-time progress-bar) (get-internal-real-time)) + (setf (start-time progress-bar) (get-internal-real-time)) + (fresh-line) + (finish-output)) + +(defmethod update-display (progress-bar) + (incf (progress progress-bar) (pending progress-bar)) + (setf (pending progress-bar) 0) + (setf (last-update-time progress-bar) (get-internal-real-time)) + (let* ((showable (floor (character-count progress-bar) + (/ (total progress-bar) (progress progress-bar)))) + (needed (- showable (characters-so-far progress-bar)))) + (setf (characters-so-far progress-bar) showable) + (dotimes (i needed) + (write-char (progress-character progress-bar))) + (finish-output))) + +(defmethod update-progress (progress-bar unit-count) + (incf (pending progress-bar) unit-count) + (let ((now (get-internal-real-time))) + (when (< (update-interval progress-bar) + (- now (last-update-time progress-bar))) + (update-display progress-bar)))) + +(defmethod finish-display (progress-bar) + (update-display progress-bar) + (setf (end-time progress-bar) (get-internal-real-time)) + (terpri) + (format t "~:D bytes in ~$ seconds (~$KB/sec)" + (total progress-bar) + (elapsed-time progress-bar) + (/ (units-per-second progress-bar) 1024)) + (finish-output)) + +(defmethod elapsed-time (progress-bar) + (/ (- (end-time progress-bar) (start-time progress-bar)) + internal-time-units-per-second)) + +(defmethod units-per-second (progress-bar) + (if (plusp (elapsed-time progress-bar)) + (/ (total progress-bar) (elapsed-time progress-bar)) + 0)) + +(defun kb/sec (progress-bar) + (/ (units-per-second progress-bar) 1024)) + + + +(defparameter *uncertain-progress-chars* "?") + +(defclass uncertain-size-progress-bar (progress-bar) + ((progress-char-index + :initarg :progress-char-index + :accessor progress-char-index) + (units-per-char + :initarg :units-per-char + :accessor units-per-char)) + (:default-initargs + :total 0 + :progress-char-index 0 + :units-per-char (floor (expt 1024 2) 50))) + +(defmethod update-progress :after ((progress-bar uncertain-size-progress-bar) + unit-count) + (incf (total progress-bar) unit-count)) + +(defmethod progress-character ((progress-bar uncertain-size-progress-bar)) + (let ((index (progress-char-index progress-bar))) + (prog1 + (char *uncertain-progress-chars* index) + (setf (progress-char-index progress-bar) + (mod (1+ index) (length *uncertain-progress-chars*)))))) + +(defmethod update-display ((progress-bar uncertain-size-progress-bar)) + (setf (last-update-time progress-bar) (get-internal-real-time)) + (multiple-value-bind (chars pend) + (floor (pending progress-bar) (units-per-char progress-bar)) + (setf (pending progress-bar) pend) + (dotimes (i chars) + (write-char (progress-character progress-bar)) + (incf (characters-so-far progress-bar)) + (when (<= (character-count progress-bar) + (characters-so-far progress-bar)) + (terpri) + (setf (characters-so-far progress-bar) 0) + (finish-output))) + (finish-output))) + +(defun make-progress-bar (total) + (if (or (not total) (zerop total)) + (make-instance 'uncertain-size-progress-bar) + (make-instance 'progress-bar :total total))) + +;;; +;;; A simple HTTP client +;;; + +(in-package #:qlqs-http) + +;;; Octet data + +(deftype octet () + '(unsigned-byte 8)) + +(defun make-octet-vector (size) + (make-array size :element-type 'octet + :initial-element 0)) + +(defun octet-vector (&rest octets) + (make-array (length octets) :element-type 'octet + :initial-contents octets)) + +;;; ASCII characters as integers + +(defun acode (char) + (cond ((eql char :cr) + 13) + ((eql char :lf) + 10) + (t + (let ((code (char-code char))) + (if (<= 0 code 127) + code + (error "Character ~S is not in the ASCII character set" + char)))))) + +(defvar *whitespace* + (list (acode #\Space) (acode #\Tab) (acode :cr) (acode :lf))) + +(defun whitep (code) + (member code *whitespace*)) + +(defun ascii-vector (string) + (let ((vector (make-octet-vector (length string)))) + (loop for char across string + for code = (char-code char) + for i from 0 + if (< 127 code) do + (error "Invalid character for ASCII -- ~A" char) + else + do (setf (aref vector i) code)) + vector)) + +(defun ascii-subseq (vector start end) + "Return a subseq of octet-specialized VECTOR as a string." + (let ((string (make-string (- end start)))) + (loop for i from 0 + for j from start below end + do (setf (char string i) (code-char (aref vector j)))) + string)) + +(defun ascii-downcase (code) + (if (<= 65 code 90) + (+ code 32) + code)) + +(defun ascii-equal (a b) + (eql (ascii-downcase a) (ascii-downcase b))) + +(defmacro acase (value &body cases) + (flet ((convert-case-keys (keys) + (mapcar (lambda (key) + (etypecase key + (integer key) + (character (char-code key)) + (symbol + (ecase key + (:cr 13) + (:lf 10) + ((t) t))))) + (if (consp keys) keys (list keys))))) + `(case ,value + ,@(mapcar (lambda (case) + (destructuring-bind (keys &rest body) + case + `(,(if (eql keys t) + t + (convert-case-keys keys)) + ,@body))) + cases)))) + +;;; Pattern matching (for finding headers) + +(defclass matcher () + ((pattern + :initarg :pattern + :reader pattern) + (pos + :initform 0 + :accessor match-pos) + (matchedp + :initform nil + :accessor matchedp))) + +(defun reset-match (matcher) + (setf (match-pos matcher) 0 + (matchedp matcher) nil)) + +(define-condition match-failure (error) ()) + +(defun match (matcher input &key (start 0) end error) + (let ((i start) + (end (or end (length input))) + (match-end (length (pattern matcher)))) + (with-slots (pattern pos) + matcher + (loop + (cond ((= pos match-end) + (let ((match-start (- i pos))) + (setf pos 0) + (setf (matchedp matcher) t) + (return (values match-start (+ match-start match-end))))) + ((= i end) + (return nil)) + ((= (aref pattern pos) + (aref input i)) + (incf i) + (incf pos)) + (t + (if error + (error 'match-failure) + (if (zerop pos) + (incf i) + (setf pos 0))))))))) + +(defun ascii-matcher (string) + (make-instance 'matcher + :pattern (ascii-vector string))) + +(defun octet-matcher (&rest octets) + (make-instance 'matcher + :pattern (apply 'octet-vector octets))) + +(defun acode-matcher (&rest codes) + (make-instance 'matcher + :pattern (make-array (length codes) + :element-type 'octet + :initial-contents + (mapcar 'acode codes)))) + + +;;; "Connection Buffers" are a kind of callback-driven, +;;; pattern-matching chunky stream. Callbacks can be called for a +;;; certain number of octets or until one or more patterns are seen in +;;; the input. cbufs automatically refill themselves from a +;;; connection as needed. + +(defvar *cbuf-buffer-size* 8192) + +(define-condition end-of-data (error) ()) + +(defclass cbuf () + ((data + :initarg :data + :accessor data) + (connection + :initarg :connection + :accessor connection) + (start + :initarg :start + :accessor start) + (end + :initarg :end + :accessor end) + (eofp + :initarg :eofp + :accessor eofp)) + (:default-initargs + :data (make-octet-vector *cbuf-buffer-size*) + :connection nil + :start 0 + :end 0 + :eofp nil) + (:documentation "A CBUF is a connection buffer that keeps track of + incoming data from a connection. Several functions make it easy to + treat a CBUF as a kind of chunky, callback-driven stream.")) + +(define-condition cbuf-progress () + ((size + :initarg :size + :accessor cbuf-progress-size + :initform 0))) + +(defun call-processor (fun cbuf start end) + (signal 'cbuf-progress :size (- end start)) + (funcall fun (data cbuf) start end)) + +(defun make-cbuf (connection) + (make-instance 'cbuf :connection connection)) + +(defun make-stream-writer (stream) + "Create a callback for writing data to STREAM." + (lambda (data start end) + (write-sequence data stream :start start :end end))) + +(defgeneric size (cbuf) + (:method ((cbuf cbuf)) + (- (end cbuf) (start cbuf)))) + +(defgeneric emptyp (cbuf) + (:method ((cbuf cbuf)) + (zerop (size cbuf)))) + +(defgeneric refill (cbuf) + (:method ((cbuf cbuf)) + (when (eofp cbuf) + (error 'end-of-data)) + (setf (start cbuf) 0) + (setf (end cbuf) + (read-octets (data cbuf) + (connection cbuf))) + (cond ((emptyp cbuf) + (setf (eofp cbuf) t) + (error 'end-of-data)) + (t (size cbuf))))) + +(defun process-all (fun cbuf) + (unless (emptyp cbuf) + (call-processor fun cbuf (start cbuf) (end cbuf)))) + +(defun multi-cmatch (matchers cbuf) + (let (start end) + (dolist (matcher matchers (values start end)) + (multiple-value-bind (s e) + (match matcher (data cbuf) + :start (start cbuf) + :end (end cbuf)) + (when (and s (or (null start) (< s start))) + (setf start s + end e)))))) + +(defun cmatch (matcher cbuf) + (if (consp matcher) + (multi-cmatch matcher cbuf) + (match matcher (data cbuf) :start (start cbuf) :end (end cbuf)))) + +(defun call-until-end (fun cbuf) + (handler-case + (loop + (process-all fun cbuf) + (refill cbuf)) + (end-of-data () + (return-from call-until-end)))) + +(defun show-cbuf (context cbuf) + (format t "cbuf: ~A ~D - ~D~%" context (start cbuf) (end cbuf))) + +(defun call-for-n-octets (n fun cbuf) + (let ((remaining n)) + (loop + (when (<= remaining (size cbuf)) + (let ((end (+ (start cbuf) remaining))) + (call-processor fun cbuf (start cbuf) end) + (setf (start cbuf) end) + (return))) + (process-all fun cbuf) + (decf remaining (size cbuf)) + (refill cbuf)))) + +(defun call-until-matching (matcher fun cbuf) + (loop + (multiple-value-bind (start end) + (cmatch matcher cbuf) + (when start + (call-processor fun cbuf (start cbuf) end) + (setf (start cbuf) end) + (return))) + (process-all fun cbuf) + (refill cbuf))) + +(defun ignore-data (data start end) + (declare (ignore data start end))) + +(defun skip-until-matching (matcher cbuf) + (call-until-matching matcher 'ignore-data cbuf)) + + +;;; Creating HTTP requests as octet buffers + +(defclass octet-sink () + ((storage + :initarg :storage + :accessor storage)) + (:default-initargs + :storage (make-array 1024 :element-type 'octet + :fill-pointer 0 + :adjustable t)) + (:documentation "A simple stream-like target for collecting + octets.")) + +(defun add-octet (octet sink) + (vector-push-extend octet (storage sink))) + +(defun add-octets (octets sink &key (start 0) end) + (setf end (or end (length octets))) + (loop for i from start below end + do (add-octet (aref octets i) sink))) + +(defun add-string (string sink) + (loop for char across string + for code = (char-code char) + do (add-octet code sink))) + +(defun add-strings (sink &rest strings) + (mapc (lambda (string) (add-string string sink)) strings)) + +(defun add-newline (sink) + (add-octet 13 sink) + (add-octet 10 sink)) + +(defun sink-buffer (sink) + (subseq (storage sink) 0)) + +(defvar *proxy-url* nil) + +(defun full-proxy-path (host port path) + (format nil "~:[http~;https~]://~A~:[:~D~;~*~]~A" + (= port 443) + host + (or (= port 80) + (= port 443)) + port + path)) + +(defun make-request-buffer (host port path &key (method "GET")) + (setf method (string method)) + (when *proxy-url* + (setf path (full-proxy-path host port path))) + (let ((sink (make-instance 'octet-sink))) + (flet ((add-line (&rest strings) + (apply #'add-strings sink strings) + (add-newline sink))) + (add-line method " " path " HTTP/1.1") + (add-line "Host: " host (if (= port 80) "" + (format nil ":~D" port))) + (add-line "Connection: close") + ;; FIXME: get this version string from somewhere else. + (add-line "User-Agent: quicklisp-bootstrap/" + qlqs-info:*version*) + (add-newline sink) + (sink-buffer sink)))) + +(defun sink-until-matching (matcher cbuf) + (let ((sink (make-instance 'octet-sink))) + (call-until-matching + matcher + (lambda (buffer start end) + (add-octets buffer sink :start start :end end)) + cbuf) + (sink-buffer sink))) + + +;;; HTTP headers + +(defclass header () + ((data + :initarg :data + :accessor data) + (status + :initarg :status + :accessor status) + (name-starts + :initarg :name-starts + :accessor name-starts) + (name-ends + :initarg :name-ends + :accessor name-ends) + (value-starts + :initarg :value-starts + :accessor value-starts) + (value-ends + :initarg :value-ends + :accessor value-ends))) + +(defmethod print-object ((header header) stream) + (print-unreadable-object (header stream :type t) + (prin1 (status header) stream))) + +(defun matches-at (pattern target pos) + (= (mismatch pattern target :start2 pos) (length pattern))) + +(defun header-value-indexes (field-name header) + (loop with data = (data header) + with pattern = (ascii-vector (string-downcase field-name)) + for start across (name-starts header) + for i from 0 + when (matches-at pattern data start) + return (values (aref (value-starts header) i) + (aref (value-ends header) i)))) + +(defun ascii-header-value (field-name header) + (multiple-value-bind (start end) + (header-value-indexes field-name header) + (when start + (ascii-subseq (data header) start end)))) + +(defun all-field-names (header) + (map 'list + (lambda (start end) + (ascii-subseq (data header) start end)) + (name-starts header) + (name-ends header))) + +(defun headers-alist (header) + (mapcar (lambda (name) + (cons name (ascii-header-value name header))) + (all-field-names header))) + +(defmethod describe-object :after ((header header) stream) + (format stream "~&Decoded headers:~% ~S~%" (headers-alist header))) + +(defun content-length (header) + (let ((field-value (ascii-header-value "content-length" header))) + (when field-value + (let ((value (ignore-errors (parse-integer field-value)))) + (or value + (error "Content-Length header field value is not a number -- ~A" + field-value)))))) + +(defun chunkedp (header) + (string= (ascii-header-value "transfer-encoding" header) "chunked")) + +(defun location (header) + (ascii-header-value "location" header)) + +(defun status-code (vector) + (let* ((space (position (acode #\Space) vector)) + (c1 (- (aref vector (incf space)) 48)) + (c2 (- (aref vector (incf space)) 48)) + (c3 (- (aref vector (incf space)) 48))) + (+ (* c1 100) + (* c2 10) + (* c3 1)))) + +(defun force-downcase-field-names (header) + (loop with data = (data header) + for start across (name-starts header) + for end across (name-ends header) + do (loop for i from start below end + for code = (aref data i) + do (setf (aref data i) (ascii-downcase code))))) + +(defun skip-white-forward (pos vector) + (position-if-not 'whitep vector :start pos)) + +(defun skip-white-backward (pos vector) + (let ((nonwhite (position-if-not 'whitep vector :end pos :from-end t))) + (if nonwhite + (1+ nonwhite) + pos))) + +(defun contract-field-value-indexes (header) + "Header field values exclude leading and trailing whitespace; adjust +the indexes in the header accordingly." + (loop with starts = (value-starts header) + with ends = (value-ends header) + with data = (data header) + for i from 0 + for start across starts + for end across ends + do + (setf (aref starts i) (skip-white-forward start data)) + (setf (aref ends i) (skip-white-backward end data)))) + +(defun next-line-pos (vector) + (let ((pos 0)) + (labels ((finish (&optional (i pos)) + (return-from next-line-pos i)) + (after-cr (code) + (acase code + (:lf (finish pos)) + (t (finish (1- pos))))) + (pending (code) + (acase code + (:cr #'after-cr) + (:lf (finish pos)) + (t #'pending)))) + (let ((state #'pending)) + (loop + (setf state (funcall state (aref vector pos))) + (incf pos)))))) + +(defun make-hvector () + (make-array 16 :fill-pointer 0 :adjustable t)) + +(defun process-header (vector) + "Create a HEADER instance from the octet data in VECTOR." + (let* ((name-starts (make-hvector)) + (name-ends (make-hvector)) + (value-starts (make-hvector)) + (value-ends (make-hvector)) + (header (make-instance 'header + :data vector + :status 999 + :name-starts name-starts + :name-ends name-ends + :value-starts value-starts + :value-ends value-ends)) + (mark nil) + (pos (next-line-pos vector))) + (unless pos + (error "Unable to process HTTP header")) + (setf (status header) (status-code vector)) + (labels ((save (value vector) + (vector-push-extend value vector)) + (mark () + (setf mark pos)) + (clear-mark () + (setf mark nil)) + (finish () + (if mark + (save mark value-ends) + (save pos value-ends)) + (force-downcase-field-names header) + (contract-field-value-indexes header) + (return-from process-header header)) + (in-new-line (code) + (acase code + ((#\Tab #\Space) (setf mark nil) #'in-value) + (t + (when mark + (save mark value-ends)) + (clear-mark) + (save pos name-starts) + (in-name code)))) + (after-cr (code) + (acase code + (:lf #'in-new-line) + (t (in-new-line code)))) + (pending-value (code) + (acase code + ((#\Tab #\Space) #'pending-value) + (:cr #'after-cr) + (:lf #'in-new-line) + (t (save pos value-starts) #'in-value))) + (in-name (code) + (acase code + (#\: + (save pos name-ends) + (save (1+ pos) value-starts) + #'in-value) + ((:cr :lf) + (finish)) + ((#\Tab #\Space) + (error "Unexpected whitespace in header field name")) + (t + (unless (<= 0 code 127) + (error "Unexpected non-ASCII header field name")) + #'in-name))) + (in-value (code) + (acase code + (:lf (mark) #'in-new-line) + (:cr (mark) #'after-cr) + (t #'in-value)))) + (let ((state #'in-new-line)) + (loop + (incf pos) + (when (<= (length vector) pos) + (error "No header found in response")) + (setf state (funcall state (aref vector pos)))))))) + + +;;; HTTP URL parsing + +(defclass url () + ((hostname + :initarg :hostname + :accessor hostname + :initform nil) + (port + :initarg :port + :accessor port + :initform 80) + (path + :initarg :path + :accessor path + :initform "/"))) + +(defun parse-urlstring (urlstring) + (setf urlstring (string-trim " " urlstring)) + (let* ((pos (mismatch urlstring "http://" :test 'char-equal)) + (mark pos) + (url (make-instance 'url))) + (labels ((save () + (subseq urlstring mark pos)) + (mark () + (setf mark pos)) + (finish () + (return-from parse-urlstring url)) + (hostname-char-p (char) + (position char "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_." + :test 'char-equal)) + (at-start (char) + (case char + (#\/ + (setf (port url) nil) + (mark) + #'in-path) + (t + #'in-host))) + (in-host (char) + (case char + ((#\/ :end) + (setf (hostname url) (save)) + (mark) + #'in-path) + (#\: + (setf (hostname url) (save)) + (mark) + #'in-port) + (t + (unless (hostname-char-p char) + (error "~S is not a valid URL" urlstring)) + #'in-host))) + (in-port (char) + (case char + ((#\/ :end) + (setf (port url) + (parse-integer urlstring + :start (1+ mark) + :end pos)) + (mark) + #'in-path) + (t + (unless (digit-char-p char) + (error "Bad port in URL ~S" urlstring)) + #'in-port))) + (in-path (char) + (case char + ((#\# :end) + (setf (path url) (save)) + (finish))) + #'in-path)) + (let ((state #'at-start)) + (loop + (when (<= (length urlstring) pos) + (funcall state :end) + (finish)) + (setf state (funcall state (aref urlstring pos))) + (incf pos)))))) + +(defun url (thing) + (if (stringp thing) + (parse-urlstring thing) + thing)) + +(defgeneric request-buffer (method url) + (:method (method url) + (setf url (url url)) + (make-request-buffer (hostname url) (port url) (path url) + :method method))) + +(defun urlstring (url) + (format nil "~@[http://~A~]~@[:~D~]~A" + (hostname url) + (and (/= 80 (port url)) (port url)) + (path url))) + +(defmethod print-object ((url url) stream) + (print-unreadable-object (url stream :type t) + (prin1 (urlstring url) stream))) + +(defun merge-urls (url1 url2) + (setf url1 (url url1)) + (setf url2 (url url2)) + (make-instance 'url + :hostname (or (hostname url1) + (hostname url2)) + :port (or (port url1) + (port url2)) + :path (or (path url1) + (path url2)))) + + +;;; Requesting an URL and saving it to a file + +(defparameter *maximum-redirects* 10) +(defvar *default-url-defaults* (url "http://src.quicklisp.org/")) + +(defun read-http-header (cbuf) + (let ((header-data (sink-until-matching (list (acode-matcher :lf :lf) + (acode-matcher :cr :cr) + (acode-matcher :cr :lf :cr :lf)) + cbuf))) + (process-header header-data))) + +(defun read-chunk-header (cbuf) + (let* ((header-data (sink-until-matching (acode-matcher :cr :lf) cbuf)) + (end (or (position (acode :cr) header-data) + (position (acode #\;) header-data)))) + (values (parse-integer (ascii-subseq header-data 0 end) :radix 16)))) + +(defun save-chunk-response (stream cbuf) + "For a chunked response, read all chunks and write them to STREAM." + (let ((fun (make-stream-writer stream)) + (matcher (acode-matcher :cr :lf))) + (loop + (let ((chunk-size (read-chunk-header cbuf))) + (when (zerop chunk-size) + (return)) + (call-for-n-octets chunk-size fun cbuf) + (skip-until-matching matcher cbuf))))) + +(defun save-response (file header cbuf) + (with-open-file (stream file + :direction :output + :if-exists :supersede + :element-type 'octet) + (let ((content-length (content-length header))) + (cond ((chunkedp header) + (save-chunk-response stream cbuf)) + (content-length + (call-for-n-octets content-length + (make-stream-writer stream) + cbuf)) + (t + (call-until-end (make-stream-writer stream) cbuf)))))) + +(defun call-with-progress-bar (size fun) + (let ((progress-bar (make-progress-bar size))) + (start-display progress-bar) + (flet ((update (condition) + (update-progress progress-bar + (cbuf-progress-size condition)))) + (handler-bind ((cbuf-progress #'update)) + (funcall fun))) + (finish-display progress-bar))) + +(defun fetch (url file &key (follow-redirects t) quietly + (maximum-redirects *maximum-redirects*)) + "Request URL and write the body of the response to FILE." + (setf url (merge-urls url *default-url-defaults*)) + (setf file (merge-pathnames file)) + (let ((redirect-count 0) + (original-url url) + (connect-url (or (url *proxy-url*) url)) + (stream (if quietly + (make-broadcast-stream) + *trace-output*))) + (loop + (when (<= maximum-redirects redirect-count) + (error "Too many redirects for ~A" original-url)) + (with-connection (connection (hostname connect-url) (port connect-url)) + (let ((cbuf (make-instance 'cbuf :connection connection)) + (request (request-buffer "GET" url))) + (write-octets request connection) + (let ((header (read-http-header cbuf))) + (loop while (= (status header) 100) + do (setf header (read-http-header cbuf))) + (cond ((= (status header) 200) + (let ((size (content-length header))) + (format stream "~&; Fetching ~A~%" url) + (if (and (numberp size) + (plusp size)) + (format stream "; ~$KB~%" (/ size 1024)) + (format stream "; Unknown size~%")) + (if quietly + (save-response file header cbuf) + (call-with-progress-bar (content-length header) + (lambda () + (save-response file header cbuf)))))) + ((not (<= 300 (status header) 399)) + (error "Unexpected status for ~A: ~A" + url (status header)))) + (if (and follow-redirects (<= 300 (status header) 399)) + (let ((new-urlstring (ascii-header-value "location" header))) + (when (not new-urlstring) + (error "Redirect code ~D received, but no Location: header" + (status header))) + (incf redirect-count) + (setf url (merge-urls new-urlstring + url)) + (format stream "~&; Redirecting to ~A~%" url)) + (return (values header (and file (probe-file file))))))))))) + + +;;; A primitive tar unpacker + +(in-package #:qlqs-minitar) + +(defun make-block-buffer () + (make-array 512 :element-type '(unsigned-byte 8) :initial-element 0)) + +(defun skip-n-blocks (n stream) + (let ((block (make-block-buffer))) + (dotimes (i n) + (read-sequence block stream)))) + +(defun ascii-subseq (vector start end) + (let ((string (make-string (- end start)))) + (loop for i from 0 + for j from start below end + do (setf (char string i) (code-char (aref vector j)))) + string)) + +(defun block-asciiz-string (block start length) + (let* ((end (+ start length)) + (eos (or (position 0 block :start start :end end) + end))) + (ascii-subseq block start eos))) + +(defun prefix (header) + (when (plusp (aref header 345)) + (block-asciiz-string header 345 155))) + +(defun name (header) + (block-asciiz-string header 0 100)) + +(defun payload-size (header) + (values (parse-integer (block-asciiz-string header 124 12) :radix 8))) + +(defun nth-block (n file) + (with-open-file (stream file :element-type '(unsigned-byte 8)) + (let ((block (make-block-buffer))) + (skip-n-blocks (1- n) stream) + (read-sequence block stream) + block))) + +(defun payload-type (code) + (case code + (0 :file) + (48 :file) + (53 :directory) + (t :unsupported))) + +(defun full-path (header) + (let ((prefix (prefix header)) + (name (name header))) + (if prefix + (format nil "~A/~A" prefix name) + name))) + +(defun save-file (file size stream) + (multiple-value-bind (full-blocks partial) + (truncate size 512) + (ensure-directories-exist file) + (with-open-file (outstream file + :direction :output + :if-exists :supersede + :element-type '(unsigned-byte 8)) + (let ((block (make-block-buffer))) + (dotimes (i full-blocks) + (read-sequence block stream) + (write-sequence block outstream)) + (when (plusp partial) + (read-sequence block stream) + (write-sequence block outstream :end partial)))))) + +(defun unpack-tarball (tarfile &key (directory *default-pathname-defaults*)) + (let ((block (make-block-buffer))) + (with-open-file (stream tarfile :element-type '(unsigned-byte 8)) + (loop + (let ((size (read-sequence block stream))) + (when (zerop size) + (return)) + (unless (= size 512) + (error "Bad size on tarfile")) + (when (every #'zerop block) + (return)) + (let* ((payload-code (aref block 156)) + (payload-type (payload-type payload-code)) + (tar-path (full-path block)) + (full-path (merge-pathnames tar-path directory)) + (payload-size (payload-size block))) + (case payload-type + (:file + (save-file full-path payload-size stream)) + (:directory + (ensure-directories-exist full-path)) + (t + (warn "Unknown tar block payload code -- ~D" payload-code) + (skip-n-blocks (ceiling (payload-size block) 512) stream))))))))) + +(defun contents (tarfile) + (let ((block (make-block-buffer)) + (result '())) + (with-open-file (stream tarfile :element-type '(unsigned-byte 8)) + (loop + (let ((size (read-sequence block stream))) + (when (zerop size) + (return (nreverse result))) + (unless (= size 512) + (error "Bad size on tarfile")) + (when (every #'zerop block) + (return (nreverse result))) + (let* ((payload-type (payload-type (aref block 156))) + (tar-path (full-path block)) + (payload-size (payload-size block))) + (skip-n-blocks (ceiling payload-size 512) stream) + (case payload-type + (:file + (push tar-path result)) + (:directory + (push tar-path result))))))))) + + +;;; +;;; The actual bootstrapping work +;;; + +(in-package #:quicklisp-quickstart) + +(defvar *home* + (merge-pathnames (make-pathname :directory '(:relative "quicklisp")) + (user-homedir-pathname))) + +(defun qmerge (pathname) + (merge-pathnames pathname *home*)) + +(defun renaming-fetch (url file) + (let ((tmpfile (qmerge "tmp/fetch.dat"))) + (fetch url tmpfile) + (rename-file tmpfile file))) + +(defvar *quickstart-parameters* nil + "This plist is populated with parameters that may carry over to the + initial configuration of the client, e.g. :proxy-url + or :initial-dist-url") + +(defvar *quicklisp-hostname* "beta.quicklisp.org") + +(defvar *client-info-url* + (format nil "http://~A/client/quicklisp.sexp" + *quicklisp-hostname*)) + +(defclass client-info () + ((setup-url + :reader setup-url + :initarg :setup-url) + (asdf-url + :reader asdf-url + :initarg :asdf-url) + (client-tar-url + :reader client-tar-url + :initarg :client-tar-url) + (version + :reader version + :initarg :version) + (plist + :reader plist + :initarg :plist) + (source-file + :reader source-file + :initarg :source-file))) + +(defmethod print-object ((client-info client-info) stream) + (print-unreadable-object (client-info stream :type t) + (prin1 (version client-info) stream))) + +(defun safely-read (stream) + (let ((*read-eval* nil)) + (read stream))) + +(defun fetch-client-info-plist (url) + "Fetch and return the client info data at URL." + (let ((local-client-info-file (qmerge "tmp/client-info.sexp"))) + (ensure-directories-exist local-client-info-file) + (renaming-fetch url local-client-info-file) + (with-open-file (stream local-client-info-file) + (list* :source-file local-client-info-file + (safely-read stream))))) + +(defun fetch-client-info (url) + (let ((plist (fetch-client-info-plist url))) + (destructuring-bind (&key setup asdf client-tar version + source-file + &allow-other-keys) + plist + (unless (and setup asdf client-tar version) + (error "Invalid data from client info URL -- ~A" url)) + (make-instance 'client-info + :setup-url (getf setup :url) + :asdf-url (getf asdf :url) + :client-tar-url (getf client-tar :url) + :version version + :plist plist + :source-file source-file)))) + +(defun client-info-url-from-version (version) + (format nil "http://~A/client/~A/client-info.sexp" + *quicklisp-hostname* + version)) + +(defun distinfo-url-from-version (version) + (format nil "http://~A/dist/~A/distinfo.txt" + *quicklisp-hostname* + version)) + +(defvar *help-message* + (format nil "~&~% ==== quicklisp quickstart install help ====~%~% ~ + quicklisp-quickstart:install can take the following ~ + optional arguments:~%~% ~ + :path \"/path/to/installation/\"~%~% ~ + :proxy \"http://your.proxy:port/\"~%~% ~ + :client-url ~%~% ~ + :client-version ~%~% ~ + :dist-url ~%~% ~ + :dist-version ~%~%")) + +(defvar *after-load-message* + (format nil "~&~% ==== quicklisp quickstart ~A loaded ====~%~% ~ + To continue with installation, evaluate: (quicklisp-quickstart:install)~%~% ~ + For installation options, evaluate: (quicklisp-quickstart:help)~%~%" + qlqs-info:*version*)) + +(defvar *after-initial-setup-message* + (with-output-to-string (*standard-output*) + (format t "~&~% ==== quicklisp installed ====~%~%") + (format t " To load a system, use: (ql:quickload \"system-name\")~%~%") + (format t " To find systems, use: (ql:system-apropos \"term\")~%~%") + (format t " To load Quicklisp every time you start Lisp, use: (ql:add-to-init-file)~%~%") + (format t " For more information, see http://www.quicklisp.org/beta/~%~%"))) + +(defun initial-install (&key (client-url *client-info-url*) dist-url) + (setf *quickstart-parameters* + (list :proxy-url *proxy-url* + :initial-dist-url dist-url)) + (ensure-directories-exist (qmerge "tmp/")) + (let ((client-info (fetch-client-info client-url)) + (tmptar (qmerge "tmp/quicklisp.tar")) + (setup (qmerge "setup.lisp")) + (asdf (qmerge "asdf.lisp"))) + (renaming-fetch (client-tar-url client-info) tmptar) + (unpack-tarball tmptar :directory (qmerge "./")) + (renaming-fetch (setup-url client-info) setup) + (renaming-fetch (asdf-url client-info) asdf) + (rename-file (source-file client-info) (qmerge "client-info.sexp")) + (load setup :verbose nil :print nil) + (write-string *after-initial-setup-message*) + (finish-output))) + +(defun help () + (write-string *help-message*) + t) + +(defun non-empty-file-namestring (pathname) + (let ((string (file-namestring pathname))) + (unless (or (null string) + (equal string "")) + string))) + +(defun install (&key ((:path *home*) *home*) + ((:proxy *proxy-url*) *proxy-url*) + client-url + client-version + dist-url + dist-version) + (setf *home* (merge-pathnames *home* (truename *default-pathname-defaults*))) + (let ((name (non-empty-file-namestring *home*))) + (when name + (warn "Making ~A part of the install pathname directory" + name) + ;; This corrects a pathname like "/foo/bar" to "/foo/bar/" and + ;; "foo" to "foo/" + (setf *home* + (make-pathname :defaults *home* + :directory (append (pathname-directory *home*) + (list name)))))) + (let ((setup-file (qmerge "setup.lisp"))) + (when (probe-file setup-file) + (multiple-value-bind (result proceed) + (with-simple-restart (load-setup "Load ~S" setup-file) + (error "Quicklisp has already been installed. Load ~S instead." + setup-file)) + (declare (ignore result)) + (when proceed + (return-from install (load setup-file)))))) + (if (find-package '#:ql) + (progn + (write-line "!!! Quicklisp has already been set up. !!!") + (write-string *after-initial-setup-message*) + t) + (call-with-quiet-compilation + (lambda () + (let ((client-url (or client-url + (and client-version + (client-info-url-from-version client-version)) + *client-info-url*)) + ;; It's ok for dist-url to be nil; there's a default in + ;; the client + (dist-url (or dist-url + (and dist-version + (distinfo-url-from-version dist-version))))) + (initial-install :client-url client-url + :dist-url dist-url)))))) + +(write-string *after-load-message*) + +;;; End of quicklisp.lisp diff --git a/vim/.vimrc b/vim/.vimrc index d742d12..5f6c995 100755 --- a/vim/.vimrc +++ b/vim/.vimrc @@ -31,8 +31,9 @@ Plug 'wolf-dog/lightline-sceaduhelm.vim' Plug 'unblevable/quick-scope' Plug 'tpope/vim-fugitive' + Plug 'l04m33/vlime', {'rtp': 'vim/'} + Plug 'kovisoft/paredit' " Plug 'metakirby5/codi.vim' - call plug#end() "}}}