From 9d6e025304ad1c965fb5712e6075af0841c81ea2 Mon Sep 17 00:00:00 2001 From: Lovro Lugovic <lovro.lugovic@memgraph.io> Date: Fri, 10 May 2019 13:54:23 +0200 Subject: [PATCH] LCP: SLIME debugging support when used as a tool Reviewers: teon.banek Reviewed By: teon.banek Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D1929 --- src/lisp/CMakeLists.txt | 2 ++ src/lisp/debug.lisp | 48 +++++++++++++++++++++++++++++++++++++++++ src/lisp/lcp-compile | 2 +- src/lisp/lcp.asd | 5 +++-- tools/lcp | 32 ++++++++++++++++++++------- 5 files changed, 78 insertions(+), 11 deletions(-) create mode 100644 src/lisp/debug.lisp diff --git a/src/lisp/CMakeLists.txt b/src/lisp/CMakeLists.txt index d54678b1c..6c2e41db7 100644 --- a/src/lisp/CMakeLists.txt +++ b/src/lisp/CMakeLists.txt @@ -10,6 +10,7 @@ set(lcp_src_files ${CMAKE_SOURCE_DIR}/src/lisp/code-gen.lisp ${CMAKE_SOURCE_DIR}/src/lisp/slk.lisp ${CMAKE_SOURCE_DIR}/src/lisp/lcp.lisp + ${CMAKE_SOURCE_DIR}/src/lisp/debug.lisp ${CMAKE_SOURCE_DIR}/src/lisp/lcp-test.lisp ${CMAKE_SOURCE_DIR}/tools/lcp) @@ -59,6 +60,7 @@ macro(define_add_lcp name main_src_files generated_lcp_files) ${CMAKE_SOURCE_DIR}/src/lisp/slk.lisp ${CMAKE_SOURCE_DIR}/src/lisp/lcp.lisp ${CMAKE_SOURCE_DIR}/src/lisp/lcp-test.lisp + ${CMAKE_SOURCE_DIR}/src/lisp/debug.lisp ${CMAKE_SOURCE_DIR}/tools/lcp) add_custom_command(OUTPUT ${h_file} ${cpp_file} COMMAND ${CMAKE_SOURCE_DIR}/tools/lcp ${lcp_file} ${slk_serialize} diff --git a/src/lisp/debug.lisp b/src/lisp/debug.lisp new file mode 100644 index 000000000..2a7a134d0 --- /dev/null +++ b/src/lisp/debug.lisp @@ -0,0 +1,48 @@ +(defpackage #:lcp.debug + (:use #:cl #:lcp) + (:export #:lcp-debugger-hook)) + +(in-package #:lcp.debug) + +(defparameter *swank-port* 4010 + "A port on which the Swank server should be started.") + +(defun swank-started-p () + "Test whether at least one Swank server was started." + (and swank::*servers* t)) + +(defun swank-has-connections-p () + "Test whether at least one SLIME connection is still alive." + (and swank::*connections* t)) + +(defun invoke-slime-debugger (condition) + "Invoke the SLIME debugger if at least one SLIME connection is active. +Otherwise invoke the standard debugger." + (let ((*debugger-hook* #'swank:swank-debugger-hook)) + (invoke-debugger condition))) + +(defun lcp-debugger-hook (condition hook) + "This debugger hook will start a Swank server in order to facilitate the +debugging of Lisp images which were not started with Swank running. + +Upon first invocation of this hook, a Swank server will be started on the port +equal to the value of *SWANK-PORT*. Then, the restart SLIME-DEBUGGER will be +established and the standard debugger will be invoked. + +Before invoking the SLIME-DEBUGGER restart the user should connect to the +started Swank server using SLIME. If the restart is invoked and no connections +exist, the standard debugger is invoked. + +If this hook is called and Swank connections already exist, the SLIME debugger +is immediately entered without establishing any restarts." + (declare (ignore hook)) + (if (swank-has-connections-p) + (invoke-slime-debugger condition) + (progn + (unless (swank-started-p) + (swank:create-server :port *swank-port* :dont-close t)) + (restart-case (invoke-debugger condition) + (slime-debugger () + :report (lambda (stream) + (format stream "SLIME debugger (port ~S)" *swank-port*)) + (invoke-slime-debugger condition)))))) diff --git a/src/lisp/lcp-compile b/src/lisp/lcp-compile index dc4002f3f..2d224ebcf 100755 --- a/src/lisp/lcp-compile +++ b/src/lisp/lcp-compile @@ -9,4 +9,4 @@ echo \ " (load \"${quicklisp_install_dir}/setup.lisp\") (ql:quickload :lcp :silent t) -" | sbcl --script \ No newline at end of file +" | sbcl --script diff --git a/src/lisp/lcp.asd b/src/lisp/lcp.asd index e8aeb47fa..ba2b7a314 100644 --- a/src/lisp/lcp.asd +++ b/src/lisp/lcp.asd @@ -2,7 +2,7 @@ :description "LCP: The Lisp C++ Preprocessor" :version "0.0.1" :author "Teon Banek <teon.banek@memgraph.io>" - :depends-on ("cl-ppcre" "named-readtables") + :depends-on ("cl-ppcre" "named-readtables" "swank") :serial t :components ((:file "package") (:file "reader") @@ -10,7 +10,8 @@ (:file "code-gen") (:file "slk") (:file "clone") - (:file "lcp")) + (:file "lcp") + (:file "debug")) :in-order-to ((test-op (test-op "lcp/test")))) (defsystem "lcp/test" diff --git a/tools/lcp b/tools/lcp index b74f9e0ed..6eb580e5f 100755 --- a/tools/lcp +++ b/tools/lcp @@ -1,12 +1,18 @@ #!/bin/bash -e -if [[ $# -ne 1 && $# -ne 2 ]]; then - echo "Usage: $0 LCP_FILE" +if [[ ! ($# -ge 1 && $# -le 3) ]]; then + echo "Usage: $0 [--debug] LCP_FILE [SLK_SERIALIZE]" echo "Convert a LCP_FILE to C++ header file and output to stdout." echo "If SLK_SERIALIZE is provided, then SLK serialization is generated." exit 1 fi +debug=false +if [[ "$1" == "--debug" ]]; then + debug=true + shift +fi + if [[ ! -r "$1" ]]; then echo "File '$1' doesn't exist or isn't readable" exit 1 @@ -25,12 +31,22 @@ if [[ "$2" == "SLK_SERIALIZE" ]]; then slk_serialize=":slk-serialize t" fi -echo \ -" -(load \"${quicklisp_install_dir}/setup.lisp\") -(ql:quickload :lcp :silent t) -(lcp:process-file \"$lcp_file\" $slk_serialize) -" | sbcl --script +if [[ $debug == "true" ]]; then + echo \ + " + (load \"${quicklisp_install_dir}/setup.lisp\") + (ql:quickload :lcp :silent t) + (let ((*debugger-hook* #'lcp.debug:lcp-debugger-hook)) + (lcp:process-file \"$lcp_file\" $slk_serialize)) + " | sbcl --noinform --noprint +else + echo \ + " + (load \"${quicklisp_install_dir}/setup.lisp\") + (ql:quickload :lcp :silent t) + (lcp:process-file \"$lcp_file\" $slk_serialize) + " | sbcl --script +fi filename=`basename $lcp_file .lcp` hpp_file="$(dirname $lcp_file)/$filename.hpp"