The comment mentioned that aux variables (the sixth value) are returned the
same way as requireds, optionals and keywords however factually that was not
the case - the number of variables was not the first element of the list. This
commit updates the function and all its callers.
For functions already compiled and loaded, we simply check if the
definition is a closure. For functions defined in the same file, we
don't store their definition in the compiler environment but instead
use *global-funs*. The advantage is that this directly allows us to
determine whether a function is a closure or not and we don't have to
run the first compiler pass again each time we inline the function.
This commit also fixes some minor issues with the inline policy,
described in detail as follows:
1. The inline policy differed subtly between `proclaim` and `declaim`.
If a file like
(eval-when (:compile-toplevel)
(proclaim '(inline f)))
(defun f ...)
was compiled (but not loaded), subsequent compilations would inline
`f` but for
(declaim (inline f))
(defun f ...)
the function `f` would only get inlined if the file was compiled _and_
loaded. We now use the latter approach for both cases. Thus, calling
`compile-file` without `load` has no side-effects regarding whether
functions are inlined or not.
2. We did not distinguish between functions which were declared inline
at a global versus local level such that e.g. in
(locally
(declare (inline f))
(defun f ...))
the function f would get inlined outside the scope of the `locally`
form. This is changed now such that local inline declarations only
apply to the scope in which they are made.
3. Inline declarations were made by expanding into statements like
(eval-when (:compile-toplevel)
(c::declare-inline ...))
during the macroexpansion of `defun`. However this only works if the
`defun` appears at the toplevel and hence in code like
(declaim (inline f))
(let (...)
(defun f ...))
the function `f` could not get inlined later on in the same file. This
is fixed now by calling the code which should run during compilation
directly when macro expanding defun.
Due to rounding issues the exponent can be different than what we
guessed. For example in the following only one digit should appear
before the decimal point such that
(format nil "~,1e" 9.9) => 9.9e+0
is correct but
(format nil "~,1e" 9.9) => 10.0e+0
is incorrect, has to be 1.0e+1.
Previously we've checked whether the new defstruct is compatible with the old
one like this:
(let ((old-desc (old-descriptions struct)))
(when (and old-desc (null (compat old-desc new-desc)))
(error "incompatible")))
This was to allow new definitions. This is incorrect, because allows first
defining a structure without slots and then adding some, like
(defstruct foo)
(defstruct foo xxx)
The new check verifies whether the structure is a structure and then compares
slot, so the verification is not inhibited when the first definition doesn't
have slots.
Moreover we now test for slot names being string= because:
a) initargs and functions ignore the package (so functions will be redefined)
b) we want to match gensymed slot names
This is compatible with what sbcl does.
On top of that check for duplicated names and signal an error if there are
such.
Let the sign of zero determine from which side branch cuts are
approached, no matter whether we use C99 complex numbers or not.
Disable the (acosh -∞) test. This test fails with the new code, but
was supposed to be commented out anyway. In general, we don't
guarantee anything about infinity if complex numbers are involved.
Closes#661.
We already have a race condition between mp:get-lock and
mp:holding-lock-p, there is no point in trying to make sure the lock
is released at all costs during an interrupt.
Replace slow homegrown mutex implementation by standard OS functions.
We try our best to be interrupt safe, however a completely safe
implementation is impossible (unless one completely removes the ability
to interrupt a thread waiting on a mutex). There is always a window
after the OS specific function has returned, but before we can set
the owner, in which interrupts will see an inconsistent state of the
mutex with regards to owner and count.
Condition variables are now based on OS functions as well. Timed
waiting on condition variables has also been implemented.
On Unix, pathnames are converted into the default encoding specified
by ext:*default-external-format* and back. On Windows, the operating
system already gives us utf16 encoded pathnames, so we use those.
ecl_namestring with ECL_NAMESTRING_FORCE_BASE_STRING encodes with the
specified encoding. Decoding is handled individually in the filesystem
functions.
Includes a minor refactor of list_directory, changing the
PARSE_DIRECTORY_ENTRY macro into an inline function.
Closes#609, #549.
We have already registered a finalizer for the external process object
which calls external-process-wait. This in turn calls si::waitpid
which closes the handle once the process has exited.
define-setf-expander takes a macro lambda-list. Previously, we handled
the &environment part of this list manually, but &body, &whole
parameters and destructuring did not work.
To fix this, we use sys::expand-defmacro in define-setf-expander. This
necessitates a change in the arguments of the setf-methods stored by
do-define-setf-function: we now pass the whole form (including the
name of the access-function) in the first argument and the environment
in the second argument, like in an ordinary macro function.
Fixes#627.
Simple MAPCAR must be replaced by a slightly more complicated DO, because the
list may not be a proper list. I want to dedicate this ballad to myself.
This is a tale of a sorry quest
To master pure code at the T guru's behest
I enrolled in a class that appealing did seem
For it promised to teach fine things like T3 and Scheme
The first day went fine; we learned of cells
And symbols and lists and functions as well
Lisp I had mastered and excited was I
For to master T3 my hackstincts did cry
I sailed through the first week with no problems at all
And I even said "closure" instead of "function call"
Then said the master that ready were we
To start real hacking instead of simple theory
Will you, said he, write me a function please
That in lists would associate values with keys
I went home and turned on my trusty Apollo
And wrote a function whose definition follows:
(cdr (assq key a-list))
A one-liner I thought, fool that I was
Just two simple calls without a COND clause
But when I tried this function to run
CDR didn't think that NIL was much fun
So I tried again like the good King of yore
And of code I easily generated some more:
(cond ((assq key a-list) => cdr))
It got longer but purer, and it wasn't too bad
But then COND ran out and that was quite sad
Well, that isn't hard to fix, I was told
Just write some more code, my son, be bold
Being young, not even a moment did I pause
I stifled my instincts and added a clause
(cond ((assq key a-list) => cdr)
(else nil))
Sometimes this worked and sometimes it broke
I debugged and prayed and even had a stroke
Many a guru tried valiantly to help
But undefined datums their efforts did squelch.
I returneth once more to the great sage of T
For no way out of the dilemma I could see
He said it was easy -- more lines must I fill
with code, for FALSE was no longer NIL.
(let ((val (assq key a-list)))
(cond (val (cdr val))
(else nil)))
You'd think by now I might be nearing the end
Of my ballad which seems bad things to portend
You'd think that we could all go home scot-free
But COND eschewed VAL; it wanted #T
So I went back to the master and appealed once again
I said, pardon me, but now I'm really insane
He said, no you're not really going out of your head
Instead of just VAL, you must use NOT NULL instead
(let ((val (assq key a-list)))
(cond ((not (null? val)) (cdr val))
(else nil)))
My song is over and I'm going home to bed
With this ineffable feeling that I've been misled
And just in case my point you have missed
Somehow I preferred (CDR (ASSQ KEY A-LIST))
-- Ashwin Ram,
"A Short Ballad Dedicated to Program Growth"
That makes lambda with a declaration si:function-block-name behave
consistently with ext:lambda-block (and in eval-macros
ext:lambda-block expands to have this declaration too to behave in
turn consistently with how the compiler treats ext:lambda-block).
Fix#576, Related to !197, 72560efa5a
with-output-to-string is required to close the output stream that it provides
for the extent of the body forms [1]. The current definition does not do that.
This change wraps the body forms in unwind-protect clauses to ensure the stream
is always closed on exit. Because declarations cannot appear at the beginning of
progn forms, any potential declarations are extracted from the body forms and
moved to the beginning of the surrounding let form's body.
element-type is no longer bound to a gensym, but evaluated inside the let body.
The uppercased names are downcased for a more coherent appearance.
[1]: http://www.lispworks.com/documentation/HyperSpec/Body/m_w_out_.htm
Announcement proposal. When this is merged to the develop branch, then
we should make a PR against master and merge. Then we shall publish
tarballs and the announcement on the website.
The Common Lisp Standard defines that with-input-from-string always closes the
input stream that it creates. But with the current definition it would only be
closed in the case of an index variable being provided.
This change wraps the code for both cases (index given or not) in a unified
unwind-protect form, updates the index if present, and always closes the
stream. It also unifies the processing of declarations.
Downcase code & fix indentation:
Set the uppercased code in lower case to harmonise appearance and increase
readability. Differentiated indentation for the first forms in unwind-protect
and multiple-value-prog1 helps to understand their special meaning.
I think that the old method is a relic from the past when bytecodes
had a different representation. bytecompiled functions also have
proper annotations so there is no need to attempt to disassemble their
lambda lists manually. Closes#561.
According to the documentation, we were supposed to return nil, but
instead we signaled a bogus error like
:INPUT argument to RUN-PROGRAM does not have a file handle:
#<output stream "/dev/null" 0x5645a22a5280>
- normalize return-type from NIL to :void, ARRAY and '* in interpreted
dffi implementation -- it is already normalized in sffi
- remove invalid path where argument type was not a valid elementary
FFI type
when it was not c1-defcallback pushed result of add-object to
arg-type-constants and tried to pass the data as opaque
pointers. That said it could never work, because:
1. add-object could return a string (i.e for known symbols expanding
to ECL_SYM) and they were fed as elementary FFI type leading to
errors during compilation by C compiler (invalid enum type)
2. when ecl_make_foreign_data was called to pass opaque objects a
function FFI:SIZE-OF-FOREIGN-TYPE was called which resulted in
error (because return type is not a valid elementary FFI type
what this code path was meant to be)
Moreover we validate both return type and argument types during the
first compiler to fail as early as possible (previously only argument
types were validated early).
- some cosmetic fixes like indentation or redundant PROGN