I'm using ASDF load cl-ppcre in a script file. The issue is (progn (require :asdf) (require :cl-ppcre)) is perfectly fine in a top level, but if the same codes wrapped in a handler-case, a system-out-of-date condition will be caught by handler-case and the whole evaluation stops, and required packages won't be loaded. I just confirm the same issue also happens in a REPL. No matter what library I try to load, the same issue just happen in a handler-case. The following is a complete session:
; SLIME 2.27
CL-USER> (require :asdf)
NIL
CL-USER> (find-package :cl-ppcre)
NIL
CL-USER> (handler-case (require :cl-ppcre) (t (c) (format t "~a: ~a~%" (type-of c) c)))
SYSTEM-OUT-OF-DATE: system cl-ppcre is out of date
NIL
CL-USER> (find-package :cl-ppcre)
NIL
CL-USER> (require :cl-ppcre)
NIL
CL-USER> (find-package :cl-ppcre)
#<PACKAGE "CL-PPCRE">
CL-USER> (handler-case (require :cl-ppcre) (t (c) (format t "~a: ~a~%" (type-of c) c)))
NIL
CL-USER> (list (lisp-implementation-type) (lisp-implementation-version))
("SBCL" "2.2.4")
CL-USER> (asdf:asdf-version)
"3.3.1"
CL-USER> (directory "/home/pxie/common-lisp/*" :resolve-symlinks nil)
(#P"/home/pxie/common-lisp/alexandria/" #P"/home/pxie/common-lisp/cl-ppcre/")
According to ASDF manual, I put my libraries in ~/common-lisp directory, and the libraries already compiled and saved in the ~/.cache/common-lisp directory.
Any insight of what is going on in ASDF?
If you ask handler-case to catch any condition that is signalled, as you have done, it will do that, whether or not the condition is an error. You almost never want to do that.
In particular if you look at plan.lisp in the ASDF sources you will find
;; NB: This is not an error, not a warning, but a normal expected condition,
;; to be to signaled by FIND-SYSTEM when it detects an out-of-date system,
;; *before* it tries to replace it with a new definition.
(define-condition system-out-of-date (condition)
...)
Related
In SBCL 2.0.1, (macroexpand '(dolist (x '(1 2 3)) (princ x))) returns:
(BLOCK NIL
(LET ((#:N-LIST385 '(1 2 3)))
(TAGBODY
#:START386
(UNLESS (ENDP #:N-LIST385)
(LET ((X (TRULY-THE (MEMBER 3 2 1) (CAR #:N-LIST385))))
(SETQ #:N-LIST385 (CDR #:N-LIST385))
(TAGBODY (PRINC X)))
(GO #:START386))))
NIL)
T
What is TRULY-THE? It appears to be non-standard because I could not find it in the Common Lisp HyperSpec.
What is the difference between TRULY-THE and THE?
From the SBCL manual:
Special Operator: truly-the [sb-ext] value-type form
Specifies that the values returned by form conform to the value-type, and causes the compiler to trust this information unconditionally.
Consequences are undefined if any result is not of the declared type -- typical symptoms including memory corruptions. Use with great care.
In other words, the the operator in certain cases (for instance with a high level of debugging) compiles to a test to check the correctness of the type specified, while truly-the instructs the compiler to NEVER perform this check.
I am learning Common Lisp using Emacs, SBCL and Slime.
I would like to know exactly what is the code definition of the built-in functions.
I know how to use (documentation ...) and (describe ...). However, they provide only high level information. I would like to see the code details.
For instance, take the nth built-in function.
Documentation gives us:
CL-USER> (documentation 'nth 'function)
"Return the nth object in a list where the car is the zero-th element."
Describe gives me:
CL-USER> (describe 'nth)
COMMON-LISP:NTH
[symbol]
NTH names a compiled function:
Lambda-list: (SB-IMPL::N LIST)
Declared type: (FUNCTION (UNSIGNED-BYTE LIST) (VALUES T &OPTIONAL))
Derived type: (FUNCTION (T T) (VALUES T &OPTIONAL))
Documentation:
Return the nth object in a list where the car is the zero-th element.
Inline proclamation: MAYBE-INLINE (inline expansion available)
Known attributes: foldable, flushable, unsafely-flushable
Source file: SYS:SRC;CODE;LIST.LISP
(SETF NTH) names a compiled function:
Lambda-list: (SB-KERNEL::NEWVAL SB-IMPL::N LIST)
Derived type: (FUNCTION (T UNSIGNED-BYTE LIST) (VALUES T &OPTIONAL))
Inline proclamation: INLINE (inline expansion available)
Source file: SYS:SRC;CODE;SETF-FUNS.LISP
(SETF NTH) has a complex setf-expansion:
Lambda-list: (SB-IMPL::N LIST)
(undocumented)
Source file: SYS:SRC;CODE;DEFSETFS.LISP
; No value
I would like to see something like:
(unknown-command 'nth)
Which would return something like:
(defun nth (x xs)
(if (equal x 0)
(car xs)
(my-nth (- x 1) (cdr xs))))
Lisp languages are fantastic and have a huge ecossystem built by awesome programmers. I hope there is some tool or command for that.
Thanks
First, some general clarifications
In your own code, hitting Meta-. should take you to the source of the code
This will also "just work" for libraries installed via Quicklisp.
Now for SBCL code itself:
If the code is in the "expected place", hitting Meta-. on built-in functions (like nth in your example above) will also take you to its source. I believe the default is /usr/share/sbcl-source/src/code/ but there's possibly a way to configure it.
However, there's another practical way to view this: if you look at the output of (describe ...) above, the line was:
Source file: SYS:SRC;CODE;LIST.LISP
Note: not the last line, that is for (setf nth), something slightly different
This tells you which file in the SBCL source code you can expect to find the function definition.
So, within [the repo](https:/ /github.com/sbcl/sbcl/tree/master/src), if you locate src/code/list.lisp, you should find the definition you're looking for; reproducing here:
(defun nth (n list)
"Return the nth object in a list where the car is the zero-th element."
(declare (explicit-check)
(optimize speed))
(typecase n
((and fixnum unsigned-byte)
(block nil
(let ((i n)
(result list))
(tagbody
loop
(the list result)
(if (plusp i)
(psetq i (1- i)
result (cdr result))
(return (car result)))
(go loop)))))
(t
(car (nthcdr n list)))))
When such information is available, it should be accessible via function-lambda-expression :
* (FUNCTION-LAMBDA-EXPRESSION #'nth)
(LAMBDA (SB-IMPL::N LIST)
(DECLARE (SB-INT:EXPLICIT-CHECK)
(OPTIMIZE SPEED))
(BLOCK NTH
(TYPECASE SB-IMPL::N
((AND FIXNUM UNSIGNED-BYTE)
(BLOCK NIL
(LET ((SB-IMPL::I SB-IMPL::N) (SB-IMPL::RESULT LIST))
(TAGBODY
LOOP
(THE LIST SB-IMPL::RESULT)
(IF (PLUSP SB-IMPL::I)
(PSETQ SB-IMPL::I (1- SB-IMPL::I)
SB-IMPL::RESULT (CDR SB-IMPL::RESULT))
(RETURN (CAR SB-IMPL::RESULT)))
(GO LOOP)))))
(T (CAR (NTHCDR SB-IMPL::N LIST))))))
NIL
NTH
However, it is not always available, in which case you would have to go to the SBCL source code repository.
Thanks to Common Lisp's powerful macro system, I can write lots of code template to generate functions avoid writing redundant code manually. What's more, it can generate different code based on configure file, so I can implement many kinds of feature just apply different configure file.
However, I have no idea how to deliver the project (It's a library):
In my opinion, maybe every config file corresponds to a package?
For example, there is a common lisp file common.lisp, it generate different functions based different configure file in compile-time.
It reads a.conf in compile-time and generate functions for PackageA and reads config b.conf in compile-time for PackageB. But in-place statement must specify only one package, the common.lisp can't both in Package A and B.
By the way, I still can't find out a proper method to get the configure path of project (So I can read and use it in compile-time to generate functions) I have tried *load-truename* for it points to the cache path which contains .fasl file on SBCLv2.0.1. But it looks like the staic files are not contained in it, so it doesn't works.
For macro-expansion the thing you care about is compile time, not load time, and the variables you want are therefore *compile-file-pathname* &/or *compile-file-truename*. ASDF likes to stash compiled files (and hence the files being loaded) somewhere known to it, which you can turn off (I do) but defaultly they end up somewhere far from their sources.
Here's an example macro which should (I have not really tested it) let you enable debugging output on a per-file basis. In real life it would be better to cache the read of the config file/s but this is mildly fiddly to get right.
(declaim (inline mutter))
(defun mutter (format &rest arguments)
(declare (ignore format arguments))
(values))
(defmacro maybe-debugging (&body forms)
(let ((config-file (and *compile-file-truename*
(make-pathname :name "debug"
:type "cf"
:defaults *compile-file-truename*))))
(multiple-value-bind (debugging cond)
(if (and config-file (probe-file config-file))
(ignore-errors
(with-standard-io-syntax
(let ((*read-eval* nil))
(with-open-file (in config-file)
(values (assoc (pathname-name *compile-file-truename*)
(read in)
:test #'string-equal)
nil)))))
(values nil nil))
(when cond
(warn "bogons reading ~A for ~A: ~A"
config-file *compile-file-truename* cond))
(if debugging
`(flet ((mutter (format &rest arguments)
(apply #'format *debug-io* format arguments)))
,#forms)
`(progn
,#forms)))))
For the single-source-file-resulting-in-multiple-object-files you could do something like this (note this repeats a variant of the above code):
(eval-when (:load-toplevel :compile-toplevel :execute)
(defvar *package-compilation-configuration*
nil
"Compile-time configuration for a package")
(defun package-config-value (key &optional (default nil))
(getf *package-compilation-configuration* key default)))
(declaim (inline mutter))
(defun mutter (format &rest args)
(declare (ignore format args))
(values))
(defmacro with-muttering (&body forms)
(if (package-config-value ':mutter)
`(flet ((mutter (fmt &rest args)
(apply #'format *debug-io* fmt args)))
,#forms)
`(progn
,#forms)))
(defun compile-file-for-package (file package &rest kws
&key (output-file nil output-file-p)
&allow-other-keys)
(with-muttering
(let* ((sf-pathname (pathname file))
(package-file (make-pathname :name (string package)
:type "cf"
:defaults sf-pathname))
(the-output-file
(if output-file-p
output-file
(compile-file-pathname
(make-pathname :name (format nil "~A-~A"
(pathname-name sf-pathname)
package)
:defaults sf-pathname))))
(*package-compilation-configuration*
(if (probe-file package-file)
(with-standard-io-syntax
(mutter "~&Compile ~A -> ~A using ~A~%"
sf-pathname the-output-file package-file)
(let ((*read-eval* nil))
(with-open-file (in package-file)
(read in))))
(progn
(mutter "~&Compile ~A -> ~A (no package)~%"
sf-pathname the-output-file)
nil))))
(apply #'compile-file file
:output-file the-output-file
kws))))
Then (compile-file-for-package "x.lisp" "y") will compile x.lisp having read configuration for package "y".
To use something like this in anger you would need to integrate it with ASDF and I don't know how to do that.
An alternative idea is just to use symlinks for the source files, and have the filename-dependent configuration depend on the symlink name, not the target name.
For my case:
project-a.asd:
(asdf:defsystem #:project-a
:components ((:static-file "my-config-file.conf")
(:static-file "common.lisp") ; shared common lisp file
(:file "project-a-package")
(:file "project-a-setup")
;; other components
)
)
project-a-setup.lisp:
(in-package #:project-a)
(eval-when (:compile-toplevel)
(defvar *mypackage* (find-package 'project-a))
(defvar *source-home* (path:dirname *compile-file-truename*))
;; read configure file
(defparameter *myconf*
(with-open-file (stream (merge-pathnames *source-home* #P"my-config-file.conf"))
(read stream)))
)
(load (merge-pathnames *source-home* #P"common.lisp"))
common.lisp:
(let ((*package* *mypackage*))
;; intern symbol
)
How to evaluate some lisp code using eval in not null lexical environment ? I need this feature for proper interpolation functionality.
If you model your environment as bindings like those found in let:
((x 3) (y 2))
... then you can evaluate any form f with those bindings in place, like so:
(eval `(let ,e ,f))
This is the simplest case, but you can easily convert your data to fit this syntax. You can also bind functions, macros, etc. if needed.
Note that if you need values at runtime, then maybe dynamic bindings are better. You can use hash-tables, etc. but note that there is also the lesser-known PROGV special operator:
Among other things, progv is useful when writing interpreters for languages embedded in Lisp; it provides a handle on the mechanism for binding dynamic variables.
Although I think the OP knows the answer already, let me try to give a somewhat more descriptive solution, hoping more experienced lispers can point to mistakes I may make below:
As #coredump mentions, progv is an option as well as a let form in eval. Here is an example:
Let's create a list with some numbers and a cons that has a lambda form, bypassing the reader lambda conversion:
(setf list1 '(1
1
(lambda ()
(print a))))
we can eval:
(eval
`(let ((a 3))
;; statement after comma is turned to a function by the reader.
;; same effect with explicit (funcall (function ,(third list1)))
;; because of the (lambda ..) macro form
(funcall ,(third list1))))
3
3
Note that variable a above is lexical, not special.
now, with progv we can create special variables and eval will use them.
Let's first start with a mistake:
(progv '(a) '(4)
(funcall (function (third list1))))
Error: (THIRD LIST1) is not a valid argument for FUNCTION.
or similarly:
(progv '(a) '(4)
(funcall (third list1)))
Error: Argument to apply/funcall is not a function: (LAMBDA NIL (PRINT A)).
Then, let's evaluate or compile:
(progv '(a) '(4)
(funcall (eval (third list1))))
4
4
or
(progv '(a) '(4)
(funcall (compile nil (third list1))))
Warning in 246: A assumed special
4
4
Above is the behaviour I got with LispWorks 7.1. eval didn't give the warning for special assumption, because:
(eval (third list1))
#<anonymous interpreted function 40600009EC>
eval returned an interpreted function, not compiled. If we further compile, then we'll see the same warning:
(eval (third list1))
#<anonymous interpreted function 40600009EC>
(compile nil *)
;;;*** Warning in 248: A assumed special
To make things right with progv, since it creates special variables, change the function:
(setf list1 '(1
1
(lambda ()
(declare (special a))
(print a))))
(progv '(a) '(4)
(funcall (compile nil (third list1))))
4
4
Note that to make the example politically correct, as CLHS does in progv page, we should better use (progv '(*a*) '(4) ...) and the lambda function should be defined with the *a* variable.
It seems there is NO ANSI standard way to execute an external program and get its output as the following SBCL special code does:
(defmacro with-input-from-program ((stream program program-args environment)
&body body)
"Creates an new process of the specified by PROGRAM using
PROGRAM-ARGS as a list of the arguments to the program. Binds the
stream variable to an input stream from which the output of the
process can be read and executes body as an implicit progn."
#+sbcl
(let ((process (gensym)))
`(let ((,process (sb-ext::run-program ,program
,program-args
:output :stream
:environment ,environment
:wait nil)))
(when ,process
(unwind-protect
(let ((,stream (sb-ext:process-output ,process)))
,#body)
(sb-ext:process-wait ,process)
(sb-ext:process-close ,process))))))
The following CCL code reports "ERROR: value # is not of the expected type (AND CCL::BINARY-STREAM INPUT-STREAM)"
#+clozure
(let ((process (gensym)))
`(let ((,process (ccl:run-program "/bin/sh" (list "-c" (namestring ,program))
:input nil :output :stream :error :stream
:wait nil)))
(when ,process
(unwind-protect
(let ((,stream (ccl::external-process-output-stream ,process)))
,#body)
;(ccl:process-wait (ccl:process-whostate ,process) nil)
(close (ccl::external-process-output-stream ,process))
(close (ccl::external-process-error-stream ,process))))))
I know little CCL. I want to know how i can modify this code to support CCL ?
Any suggestion is appreciated !
Apparently trivial-shell:shell-command doesn't allow exactly what you want (it executes the external command synchronously and returns the whole output).
You could look into CCL's run-program. See:
run-program;
Does there exist standard way to run external program in Common Lisp? (this is a question that is similar to your question);
external-program (suggested in one of the answers in the question above) is supported by Quicklisp and it seems to have better support for executing external programs.
You should use trivial-shell.
Trivial shell is a simple platform independent interface to the underlying Operating System.