| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
After "years of trouble-free operation" a bug in the UTF-8
decoder was found, which violates its property that any
sequence of bytes will decode to some kind of string, which
will encode to the original bytes.
When the UTF-8 data prematurely ends in the middle of a valid
character, the decoder just drops that data as if it didn't
exist. So for instance the two-byte sequence E6 BC should
decode to "\xDCE6\xDCBC", since it is a fragment of a three-byte
UTF-8 sequence. It actually decodes to the empty string.
* utf8.c (utf8_bfom_buffer): When the buffer is exhausted, if we are
not in the utf8_init state, it means we were in the middle of a
UTF-8 sequence. Walk the bytes from the backtrack point to the end
of the buffer and store them into the string as U+DCxx codes.
* tests/012/buf.tl: Tests added for this via buf-str, str-buf.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* ffi.c (ffi_transform_pack): Fix: return the original syntax in
the situation when no cases are recognized, rather than
the cdr of the syntax. When the struct/union syntax has no
members, return the original syntax to indicate no transformation
took place.
* txr.1: Document the feature that pack on a typedef name or struct
name with no members will do the alignment adjustment only, without
the syntactic transformation.
* tests/017/pack-align.tl: New file.
|
|
|
|
|
|
|
| |
* eval.c (error_trace): Don't mention that --backtrace can be
used to enable backtraces. This is not only a nuisance, but
appears in packaged programs which do not support such an option,
making it highly misleading.
|
|
|
|
|
| |
* txr.1: fix broken quoting which results in stray "
character appearing in rendered output.
|
|
|
|
|
|
|
| |
* txr.1: The documentation for array and zarray wrongly states
that if the dimension is omitted, the type may not be used
as a structure member. In fact, it may be used as the last
member of a flexible structure.
|
|
|
|
| |
* txr.1: two instances of "an incomplete arrays" in FFI doc.
|
|
|
|
|
|
|
| |
* ffi.c (ffi_type_compile): Allow align to weaken (lower) alignment
if compatibility 275 or lower is requested.
* txr.1: Compat note added.
|
|
|
|
|
|
|
|
|
|
|
| |
* ffi.c (ffi_pack_members): Static function removed.
(ffi_transform_pack): New static function.
(ffi_type_compile): Rely on ffi_transform_pack to recognize
and perform all necessary transformations.
Cosmetic issue: when a struct is compiled, and the individual
member types undergo transformation during member compilation,
the syntax for the struct is nevertheless the original one
with the untransformed members.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* stream.c (trim_path_seps): New function.
(stream_init): trim-path-seps intrinsic registered.
* stream.c (trim_path_seps): Declared.
* tests/018/path.tl: New tests.
* txr.1: Documented.
* stdlib/doc-syms.tl: Updated.
|
|
|
|
|
|
|
|
|
|
|
|
| |
* ffi.c (ffi_type_copy, ffi_type_copy_new_ops): The cloned txr_ffi_type
structure must have a self member which points to the new cobj,
not the original one. Otherwise things are inconsistent. For instance
if the clone is being made for the purposes of adjusting alignment,
any operation which chases the self pointer will be accessing incorrect
attributes. One example of this is (alignof foo.bar) where if bar
is the clone of a type, this will incorrectly report the alignment of
the original from which bar was cloned, and the original alignment,
not the adjusted alignment is reported.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* ffi.c (pack_s): New symbol variable.
(ffi_type_compile): Handle new pack type operator together with
align. Allow a one-argument form of align and pack in which
the value is defaulted. The behavior of align changes: align
can only increase alignment now, never decrease, so for
instance (align 1 ...) does nothing. pack must be used to
decrease alignment. Furthermore, for certain argument types,
pack performs transformations of the type syntax, rather than
compiling the argument type and producing a variant of it with
altered alignment.
* txr.1: Documented.
* stdlib/doc-syms.tl: Updated.
|
|
|
|
|
|
|
|
|
| |
* ffi.c (make_ffi_type_struct): When a bitfield is declared for
a type whose alignment is different from that of the previous
member, then we start the new bitfield on a fresh alignment.
As usual, if the previous member is a bitfield which left a
partially filled byte, we skip to the next byte and then do the
alignment. This seems to match GCC behavior.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
In gcc, bitfields can be declared with overridden alignment;
for instance when the entire structure is packed.
We must modify the algorithm to make this work.
Firstly, we must must pretend that we are filling from the start
of the containing alignment unit, not size based unit. For
instance, if the cell is an 8 byte type, but the alignment is 1,
then we are just filling the current byte, not the current 8 byte
multiple. However, the number of bits left (room) is still
calculated from the size: so if the byte has been filled with 3 bits,
we have 4 left in that byte, and then 7 more bytes, and so 61 bits.
Secondly, the case of the zero-bit field is special: it does
perform an alignment calculation in terms of multiples of the
size, ignoring the declared alignment of the field.
Thirdly, when the bits do not fit into the existing room, the
offset does not move by the size of the bitfield, but by the
alignment unit. For instance, if we have 63 bits left in an 8
byte field that has alignment 1, and we want to place 64 bits
into another 8 byte field, then we will just move to the next
byte, not to the next 64 bit cell. Starting at the next byte,
we pretend we have a fres 64 bit cell, albeit misaligned.
* ffi.c (make_ffi_type_struct): Make the above adjustments to
the algorithm. Some common values size, alignment, mask)
are declared in a wider scope and adjustments made.
|
|
|
|
|
|
|
|
| |
* ffi.c (make_ffi_type_struct, make_ffi_type_union): Initialize
most_align local variable to 1, so the lower bound of alignment
is that, rather than zero.
* tests/017/ffi-misc.tl: Tests added.
|
|
|
|
|
|
|
| |
* ffi.c (make_ffi_type_struct, make_ffi_type_union): Do not fall
back from the fat (64 bit) bitfield case to the regular (32 bit)
case when the number of bits is less than 32. This is completely
wrong.
|
|
|
|
|
|
|
|
|
| |
* ffi.c (ffi_type_compile): Show the original bitfield syntax
in the invalid size diagnostics. In the case of the (bit n type)
syntax, restrict the maximum bits to the width of the type,
not just to 32 or 64. I realize the 8 * tft->size calculation
can overflow for huge array types, but it makes no sense to use
them as bitfields.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* ffi.c (struct txr_ffi_type): Replace unsigned mask member
with a union m which holds unsigned mask and 64-bit fmask (fat
mask).
(ffi_sbit_put, ffi_sbit_get, ffi_ubit_put, ffi_ubit_get):
Refer to m.mask.
(ffi_fat_sbit_put, ffi_fat_sbit_get, ffi_fat_ubit_put,
ffi_fat_ubit_get): New static functions.
(ffi_generic_fat_sbit_put, ffi_generic_fat_sbit_get,
ffi_generic_fat_ubit_put, ffi_generic_fat_ubit_get):
Likewise.
(make_ffi_type_struct, make_ffi_type_union): Set up fat
mask for bitfields that are wider than int.
(ffi_type_compile): Refer to m.mask for the int and unsigned
int based bitfields declared with sbit and ubit that don't
mention a type. The bit operator now allows int64 and uint64
to be valid types for a bitfield. In this case, the "fat"
get and put functions are selected which use 64 bit operations.
Thus there is no efficiency impact on non-fat bitfields which
continue to use code with 32 bit operands.
(ffi_offsetof): Use the bitfield flag in the member's type
structure to detect bitfields, rather than the mask.
|
|
|
|
|
|
| |
ffi.c (ffi_init_extra_types): Use longlong_t and ulonglong_t, subject
to HAVE_LONGLONG_T. If there is no intmax_t and no longlong_t,
don't define intmax-t and uintmax-t.
|
|
|
|
|
|
| |
* ffi.c (ffi_generic_sbit_put, ffi_generic_sbit_get,
ffi_generic_ubit_put, ffi_generic_ubit_get): Replace int-sized
alloca with declared int object.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Because the varray behavior for undimensioned arrays was introduced
in dubious commit 7880c9b565ab438e1bf0250a967acdbf8d04cb42
in 2017, which used make_ffi_type_pointer to register the type,
claiming that the C representation is pointer (which was not true
in that commit, nor ever since).
As a result, though, undimensioned arrays received the alignment
of pointers, rather than deriving it from the element type.
Thus (array char) has 4 or 8 byte alignment whereas (array 4 char)
correctly has 1 byte alignment.
* ffi.c (ffi_type_compile): Use make_ffi_type_array for the two-element
array syntax, just like for the dimensioned case with three elements.
Then override some of the functions with the varray versions.
* tests/017/ffi-misc.tl: Fix the test case which exposed this.
In the type (struct flex (a char) (b (zarray char)), the array
b must be at offset 1. I didn't notice that the offset of 4
being confirmed by the test case was wrong, but this showed up
when running the test case on a platform with 8 byte pointers.
|
|
|
|
|
|
|
| |
* tests/017/ffi-misc.tl: Fix incorrect test whose loop body
does not execute. A remaining issue here is why the diagnostics
about unbound functions and variables in the loop body get
swept under the rug.
|
|
|
|
|
|
|
|
|
| |
* stdlib/copy-file.tl (copy-path-rec): When from-path has
a trailing slash, the starts-with test fails, and the operation
fails without doing anything. Let's just get rid of that test.
It's probably only there because of the ad-hoc path munging
that is calculating rel-path. Why don't we just use the rel-path
function for that.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* eval.c (eval_init): Fix up registration of split-str to
account for new parameter.
* lib.c (split_str_keep): Implement new optional count
argument.
(spl): Pass nil value to split_str_keep for new argument.
I'd like this function to benefit from this argument also,
but the design isn't settled.
(split_str): Pass nil argument to split_str_keep.
* lib.h (split_str_keep): Declaration updated.
* tests/015/split.tl: New tests.
* txr.1: Documented.
|
|
|
|
| |
* txr.1: agreement between "body" and "consist".
|
|
|
|
|
|
|
|
|
|
|
|
| |
* ffi.c (ffi_char_array_get, ffi_zchar_array_get, ffi_wchar_array_get,
ffi_bchar_array_get): Rearrange so that we test for tft->null_term
first, and not nelem == 0. If nelem happens to be zero, but we are
supposed to decode a null-terminated string, we will do the wrong
thing and return the null string.
(ffi_varray_in): The body can't be conditional on vec being non-nil,
because then we do nothing if we don't have a Lisp object, which means
we skip the cases when we should decode a null-terminated array.
Now if vec is nil, we must guard against calling ffi_varray_dynsize.
|
| |
|
|
|
|
|
|
|
|
|
| |
* txr.c (help): Mention new options.
(do_compile_opt, do_in_package_opt): New static functions.
(txr_main): Implement options.
* Makefile (COMPILE_TL): Use the options instead of -e.
* txr.1: Document.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* eval.c (do_expand): When a function call's arguments are
expanded and produce a transformation, then if that function
call had been produced by a macro, the transformed function
call is tried again as a macro. This is necessary because
TXR Lisp allows a symbol to be both a function and macro.
When a macro-produced function call's arguments are expanded,
the macro version of that function may, as a result of the
argument transformations, have more opportunities for expansion.
* txr.1: New section outlining how macro expansion generally
works, with a special focus on this unusual new rule.
|
|
|
|
|
|
|
|
|
|
|
| |
This change fixes objects like (@a @b . @c) being printed
as (@a @b sys:var c). This is piggybacked into the logic
which renders dotted unquotes. In other words, we are already
printing (x . ,y) in that from rather than (x sys:unquote y);
we just recognize sys:var, and sys:expr in the same code.
* lib.c (obj_print_impl): Recognize dotted metavariables and
metaexpressions similarly to dotted unquotes.
|
|
|
|
|
|
|
|
|
|
|
|
| |
* stdlib/match.tl (expand-lambda-match): A pattern that
is shorter than the maximum number of arguments is
augmented with a check ensuring that no fixed arguments
are present beyond those that the pattern requires.
However, this check must be omitted if the pattern is
variadic, because those excess arguments match its tail
pattern.
* tests/011/patmatch.tl: Cases added.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* RELNOTES: Updated.
* configure (txr_ver): Bumped version.
* stdlib/ver.tl (lib-version): Bumped.
* txr.1: Bumped version and date.
* txr.vim, tl.vim: Regenerated.
* protsym.c: Likewise.
|
|
|
|
|
|
|
|
|
|
|
| |
* tests/017/str-s.tl: Use (libc) not nil in with-dyn-lib.
* tests/018/forkflush.tl: On Cygwin, produce canned output for first
test case, because the real test case produces some DOS line endings
that cause a mismatch.
* tests/019/load-search.tl: Skip test case involving a directory
with bad permissions being in the load search path.
|
|
|
|
|
|
| |
* jmp.S (jmp_save, jmp_restore): Define for Loongarch.
* unwind.h (struct jmp): Likewise.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* ffi.c (pad_retval): Remove the special case of zero mapping
to zero, which occurs when the return type is void. It's not
clear whether this is correct at all, on any platform. It
hasn't showed up as a problem until now, but on RISC-V,
we have hit a situation in which ffi_call writes a value into
that zero-byte space for the void return value, causing that
to overwrite values[0]: the first element of the argument
array. For reasons not understood, this happens in the qsort
test cases in which which the callback function performs a
block return. It is strange because the block return is
handled entirely in the closure dispatching function.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Everything compiles, and most tests pass. Failing test are:
- tests/014/dgram-stream.tl:
- tests/017/glob-carray.tl:
- tests/017/qsort.tl:
The datagram test is not able to bind a UDP socket to a port.
On the gcc402 machine of the GCC Compile Farm, attempts bind a
UDP socket to any of the ports 1024-65535 all fail with errno
99 (EADDRNOTAVAIL).
The FFI test cases are segfaulting. The qosrt.tl case has
the problem in the test cases which abort the callback with
a return-from.
* unwind.h (struct jmp): Define for RISC-V.
* jmp.S (DEFUN): Define macro for RISC-V.
(jmp_save, jmp_restore): Define for RISC-V.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
I realized this issue while implementing Ctrl-Z for the pw
(Pipe Watch) program. Sending the SIGTSTP signal just to the
calling process is not enough. Only that process gets
suspended, which results in a weird behavior. It can be
tested like this, for instance:
txr | tee file
Ctrl-Z must be issued twice: once to sort of suspend txr, and
then again to send it to the tee program. Then the job
actually suspends and the shell prompt appears. With this fix,
the above situation requires only one Ctrl-Z, as expected.
* linenoise/linenoise.c (history_search, show_help, edit):
Don't raise(SIGTSTP), but kill(0, SIGTSTP) to send the suspend
signal to all processes in the process group.
|
|
|
|
|
|
| |
* txr.1: Document the existing behavior that the various
FFI string types map between the null pointer and the nil
object.
|
|
|
|
|
| |
* txr.1: Document the (ptr (array 1 <type>)) trick needed for
out or in-out parameters.
|
|
|
|
|
|
|
| |
* eval.c (load): Use path_cat and dir_name instead of ad hoc
path munging.
* match.c (v_load): Likewise.
|
|
|
|
|
| |
* tests/019/load-search.tl: Add some cases that explore
the load search path.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* eval.c (load_search_dirs_s): New symbol variable.
(load): Initialize the name variable whose address is passed
as the third argument of open_txr_file, which is now
an in-out parameter. Pass t for the new search_dirs parameter,
so that load benefits from the searching.
(eval_init): Initialize load_search_dirs_s and register the
*load-search-dirs* special variable.
* eval.h (load_search_dirs_s): Declared.
(load_search_dirs): New macro.
* match.c (v_load): Initialize the variable passed as third argument
of open_txr_file.
* parser.c (open_txr_file): Take a new argument, search_dirs.
If this is t, it tells the function "if the path is not found,
then recurse on the *load-search-dirs* variable. Otherwise,
if the value is not t, it is a list of the remaining directories
to try. The existing parameter orig_in_resolved_out must now
point to a location which is initialized. It is assumed to hold
the original target that was passed to the load function.
The first_try_path is a the path to actually try, derived from
that one. Thus, the caller of open_txr_file gets to determine
the initial try path using its own algorithm. Then any recursive
calls that go through *load-search-dirs* will pass a first argument
which is made of the original name, combined with a search dir.
(load_rcfile): Pass pointer to initialized location as third
argument of open-txr_file, and pass a nil value for search_dirs:
no search takes place when looking for that file, which is at a
single, fixed location.
* parser.h (open_txr_file): Declaration updated.
* txr.c (sysroot_init): Initialize *load-search-dirs*.
(txr_main): Ensure third argument in all calls to open_txr_file
points to initialized variable, with the correct value,
and pass t for the search_dirs argument.
* txr.1: Documented.
* stdlib/doc-syms.tl: Updated.
New: load can search multiple directories.
* eval.c (load_search_dirs_s): New symbol variable.
(load): Initialize the name variable whose address is passed as
the third argument of open_txr_file, which is now an in-out
parameter. Pass t for the new search_dirs parameter, so that
load benefits from the searching.
(eval_init): Initialize load_search_dirs_s and register the
*load-search-dirs* special variable.
* eval.h (load_search_dirs_s): Declared.
(load_search_dirs): New macro.
* match.c (v_load): Initialize the variable passed as third
* argument
of open_txr_file.
* parser.c (open_txr_file): Take a new argument, search_dirs.
If this is t, it tells the function "if the path is not found,
then recurse on the *load-search-dirs* variable. Otherwise, if
the value is not t, it is a list of the remaining directories
to try. The existing parameter orig_in_resolved_out must now
point to a location which is initialized. It is assumed to hold
the original target that was passed to the load function. The
first_try_path is a the path to actually try, derived from that
one. Thus, the caller of open_txr_file gets to determine the
initial try path using its own algorithm. Then any recursive
calls that go through *load-search-dirs* will pass a first
argument which is made of the original name, combined with a
search dir.
(load_rcfile): Pass pointer to initialized location as third
argument of open-txr_file, and pass a nil value for
search_dirs: no search takes place when looking for that file,
which is at a single, fixed location.
* parser.h (open_txr_file): Declaration updated.
* txr.c (sysroot_init): Initialize *load-search-dirs*.
(txr_main): Ensure third argument in all calls to open_txr_file
points to initialized variable, with the correct value, and
pass t for the search_dirs argument.
* txr.1: Documented.
* stdlib/doc-syms.tl: Updated.
|
|
|
|
|
|
| |
* parser.[ch] (open_txr_file): spec_file is now called first_try_path.
The name parameter is called orig_in_resolved_out. Currently it has
just the resolved_out semantics, but that is about to change.
|
|
|
|
|
|
| |
* stream.c (open_subprocess, open_commad): Only flush standard
output for non-input pipes. If we are capturing the output of
the process, then it is unrelated to our standard output.
|
|
|
|
|
|
| |
* stream.c (open-subprocess, open_command, run): Flush the standard
output stream before forking or spawning the child process.
This gets tests/018/forkflush.tl to pass.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This test case exemplifies code that will work as expected
when *stdout* is a TTY device, such that line buffering is
in effect, but then break when standard output is redirected
to a file.
The issue is that the controlling process is not flushing its
standard output when calling the external script, so the
script's output gets placed ahead of the process' own earlier
output.
* tests/018/forkflush.tl: New file.
* tests/018/forkflush.expected: New file.
|
|
|
|
|
|
|
| |
* txr.1: The Top-Level Forms and File Compilation Model
sections now reference back to eval, noting its similar
treatment of top-level forms. Without this, it looks like
top-level forms are just a compilation concept.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This is a partial revert of the May 1, 2019 commit
065dde19dfbe50e91e313e5b3ccc033cfbe47f74,
titled "loading: try unsuffixed files directly last".
Test cases added in prior commit now pass.
* parser.c (open_txr_file); Like before the 2019 commit, we
try the exact path that is specified first. Only if that is
not found do we try adding suffixes to a file which has no
recognizable suffix. This does mean that (load "foo") will
probe the filesystem twice in order to find "foo.tl" or
"foo.tlo" there is no obvious way around that that doesn't
cause a problem.
* txr.1: Update documentation that is outdated, incomplete,
incorrect, or that is has become incorrect because of this
fix.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This test currently fails because when we execute an
unsuffixed file like test/019/a, which exists,
another file is executed instead, like test/019/a.txr.
* tests/019/data/a,
* tests/019/data/a.tl,
* tests/019/data/a.tlo,
* tests/019/data/a.txr
* tests/019/data/b.tl
* tests/019/data/b.tlo
* tests/019/data/b.txr
* tests/019/data/c.tl
* tests/019/data/c.txr
* tests/019/load-search.tl: New files.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* stdlib/compiler.tl (compile-file-conditionally): Recognize a
potential package-manipulating form not checking whether its
main operator is in %pakage-manip% list, but whether any
global functions that its compiled image references are in
that list. This is the same approach that is used in
dump-compiled-objects. This fix is needed for correctly
recognizing defpackage as a package-manipulating form.
defpackage macro-expands to a let form which contains a call
to make-package. Testing whether let is in %package-manip% is
useless; of course it isn't, and the test overlooks
make-package.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* eval.c (eval_init): Register isecp intrinsic.
* lib.c (isecp): New function.
* lib.h (isecp): Declared.
* stdlib/compiler.tl (lambda-apply-transform,
dump-compiled-objects): Use isecp instead of isec, since the
actual intersection of symbols isn't needed, only whether it
exists.
* txr.1: Documented.
* stdlib/doc-syms.tl: Updated.
|