summaryrefslogtreecommitdiffstats
Commit message (Collapse)AuthorAgeFilesLines
...
* compiler: inlined chain: simplify variadic lambdas.Kaz Kylheku2024-02-081-2/+15
| | | | | | | | | | | | | | | The opip syntax often generates lambdas that have a trailing parameter and use [sys:apply ...]. This is wasteful in the second and subsequent argument positions of a chain, because we know that only a single value is coming from the previous function. We can pattern match these lambdas and convert the trailing argument to a single fixed parameter. * stdlib/compiler.tl (simplify-variadic-lambda): New function. (inline-chain-rec): Try to simplify every function through simplify-variadic-lambda. The leftmost function is treated in inline-chain, so these are all second and subsequent functions.
* compiler: implement inlining for chain expressions.Kaz Kylheku2024-02-072-2/+40
| | | | | | | | | | | | | | | | | | | | The opip syntax and its variants transforms into chain expressions. Currently, we emit actual chain function calls, and so all the chain arguments that are lambda expressions have become closures. In this commit, an inlining optimization is introduced which turns some chain function calls into chained expressions. The lambdas are then immediately called, and so succumb to the lambda-eliminating optimization. * stdlib/compiler.tl (compiler comp-fun-form): Handle chain forms. At optimization level 6 or higher, if the form is eligible for the transform, perform it. (inline-chain-rec, can-inline-chain, inline-chain): New functions. * txr.1: Mention that *opt-level* 6 does this chain optimization.
* compiler: whitespace issue.Kaz Kylheku2024-02-071-1/+1
| | | | | * stdlib/compiler (lambda-apply-transform): Fix misleading indentation.
* doc: missing plural.Kaz Kylheku2024-02-041-1/+1
| | | | | * txr.1: Under Pattern-Matching Notation: subject-verb agreement.
* New function: hist-sort-by.Kaz Kylheku2024-02-025-3/+37
| | | | | | | | | | | | | * eval.c (eval_init): Register hist-sort-by intrinsic. * lib.c (hist_sort_by): New function. (hist_sort): Wrapper for hist_sort_by now. * lib.h (hist_sort_by): Declared. * tests/012/sort.tl: Tests. * txr.1: Documented.
* hash-eql: regression: always returns zero.Kaz Kylheku2024-02-012-1/+7
| | | | | | | | | | | * hash.c (hash_eql): Use hash_traversal_limit for the initial value of the limit rather than zero. Commit 84e9903c27ede099e2361e15b16a05c6aa4dc819 in October 2019 fixed eql_hash to actually make use of the limit, which broke the assumption that we could use zero. * tests/010/hash.tl: Add a few tests for hash-equal and hash-eql.
* quips: new bad pun.Kaz Kylheku2024-01-201-0/+1
| | | | * stdlib/quips.tl (%quips%): New entry.
* We need a length-< special method.Kaz Kylheku2024-01-197-5/+67
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Structure objects can be used to implement lazy structures such as sequences. It is undesirable to take the length of a lazy sequence because it forces all of its elements to exist. Moreover, if the sequence is infinite, it is impossible. There are situations in which it is only necessary to know whether the length is less than a certain bound, and for that we have the length-< function. That works on infinite sequence such as lazy lists, requiring them to be forced only so far as to determine the truth value of the test. We need objects that implement lazy sequences to work with this function. * struct.h (enum special_slot): New member length_lt_m. * lib.h (length_lt_s): Symbol variable declared. * struct.c (special_sym): New entry in this table, associating the length_lt_m enum with the length_lt_s symbol variable. * lib.c (length_lt_s): Symbol variable defined. (length_lt): Handle COBJ objects that are structures. we test whether they have a length-< method, or else length method. If they don't have either, we throw. We don't fall back on the default case for objects that don't have a length-< method, because the diagnostic won't be good if they don't have a length method either; the programmer will be informed that the length function couldn't find a length method, without mentioning that it was actually length-< that is being used. * eval.c (eval_init): Register length-< using the length_lt_s symbol variable rather than using intern. * txr.1: Documented. * tests/012/oop-seq.tl: New tests.
* mmap: bug: low length diagnosed as "zero-sized element type"Kaz Kylheku2024-01-181-1/+1
| | | | | | | * ffi.c (mmap_wrap): Make the diagnostic depend on the actual condition that it's wording is about. If the element type is nonzero, but the length is too low for the array to have any elements, that is not strictly an error; we can let that pass.
* doc: mmap: document source parameter.Kaz Kylheku2024-01-181-0/+34
| | | | | | * txr.1: The source argument of mmap is not adequately documented. It can be an integer descriptor, stream or filename string.
* Copyright year bump 2024.Kaz Kylheku2024-01-18138-140/+140
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * LICENSE, LICENSE-CYG, METALICENSE, Makefile, alloca.h, args.c, args.h, arith.c, arith.h, autoload.c, autoload.h, buf.c, buf.h, cadr.c, cadr.h, chksum.c, chksum.h, chksums/crc32.c, chksums/crc32.h, combi.c, combi.h, configure, debug.c, debug.h, eval.c, eval.h, ffi.c, ffi.h, filter.c, filter.h, ftw.c, ftw.h, gc.c, gc.h, glob.c, glob.h, gzio.c, gzio.h, hash.c, hash.h, itypes.c, itypes.h, jmp.S, lib.c, lib.h, linenoise/linenoise.c, linenoise/linenoise.h, match.c, match.h, parser.c, parser.h, parser.l, parser.y, psquare.h, rand.c, rand.h, regex.c, regex.h, signal.c, signal.h, socket.c, socket.h, stdlib/arith-each.tl, stdlib/asm.tl, stdlib/awk.tl, stdlib/build.tl, stdlib/cadr.tl, stdlib/compiler.tl, stdlib/constfun.tl, stdlib/conv.tl, stdlib/copy-file.tl, stdlib/csort.tl, stdlib/debugger.tl, stdlib/defset.tl, stdlib/doloop.tl, stdlib/each-prod.tl, stdlib/error.tl, stdlib/except.tl, stdlib/expander-let.tl, stdlib/ffi.tl, stdlib/getopts.tl, stdlib/getput.tl, stdlib/glob.tl, stdlib/hash.tl, stdlib/ifa.tl, stdlib/keyparams.tl, stdlib/load-args.tl, stdlib/match.tl, stdlib/op.tl, stdlib/optimize.tl, stdlib/package.tl, stdlib/param.tl, stdlib/path-test.tl, stdlib/pic.tl, stdlib/place.tl, stdlib/pmac.tl, stdlib/quips.tl, stdlib/save-exe.tl, stdlib/socket.tl, stdlib/stream-wrap.tl, stdlib/struct.tl, stdlib/tagbody.tl, stdlib/termios.tl, stdlib/trace.tl, stdlib/txr-case.tl, stdlib/type.tl, stdlib/vm-param.tl, stdlib/with-resources.tl, stdlib/with-stream.tl, stdlib/yield.tl, stream.c, stream.h, struct.c, struct.h, strudel.c, strudel.h, sysif.c, sysif.h, syslog.c, syslog.h, termios.c, termios.h, time.c, time.h, tree.c, tree.h, txr.1, txr.c, txr.h, unwind.c, unwind.h, utf8.c, utf8.h, vm.c, vm.h, vmop.h, win/cleansvg.txr, y.tab.c.shipped: Copyright year bumped to 2024.
* lib: avoid realloc with zero size.Kaz Kylheku2024-01-161-3/+13
| | | | | | | | | | | | | I spotted in the N3096 draft of ISO C (April 2023) that a zero size in realloc is no longer defined behavior, like it used to be. I don't know exactly when it changed; in C99 it is not mentioned. We call realloc only in one place, so we can defend agains this. * lib.c (chk_realloc): If the new size is zero, we implement the C99 and older semantics: deallocate the object, and then behave like malloc(0). In other cases, we use realloc.
* ppc64/clang: save/restore vector register vr31.Kaz Kylheku2024-01-112-1/+22
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This fixes crashes in the test cases when TXR is built with clang on little-endian PPC64. Clang uses vector instructions, but our jmp.S does not save any vector registers. In some places this causes a problem. I've noticed much of the code just uses vrs0, vrs1 and vrs63 for doing small things, like initializing small structures with a single instruction. The functions that use more of these registers don't call anything that saves and restores a context. In this patch we just save/restore vrs63, which maps to vr31. The vrs0 and vrs1 don't have to be saved and restored; the setjmp function doesn't do it. Everything is conditional on __ALTIVEC__. * unwind.h (jmp): We add vr31 to the PPC64 version of struct jmp. The instructions which load and store this requires 32 byte alignment, so we assert that. Note that the alignment leaves 8 bytes of padding at the end of the structure since there are 23 other registers to save. * jmp.S (jmp_save, jmp_restore): We save and restore v31 first and then move the pointer past it by 32 bytes to do the rest of the registers exactly as before. In jmp_save, we save an extra copy of the r11 register into the padding so that it is initialized. We don't like to encourage padding in the stack because in light of our GC's conservative scan of the stack, it promotes spurious retention of objects.
* lib: review cobj calls for gc incorrectness and fix.Kaz Kylheku2024-01-064-2/+13
| | | | | | | | | | | | | | | | | | | | | | | | | | | | I looked at all cobj calls to see if there is a potential problem, looking for situations whereby the cobj call could trigger a gc that would destroy Lisp objects that the new object either stores, or that its continued initialization depends on. * stream.c (make_strlist_input_stream): call cobj earlier, then fill in the structure. Use chk_calloc to allocate the structure so any Lisp objects in it look like nil until it is initialized. * struct.c (make_struct_impl, make_lazy_struct): Use gc_hint on the type argument, to pin down the st structure that we use in initializations after the cobj call. If the type object were to disappear, the st structure would become invalid. * tree.c (copy_search_tree, make_similar_tree): Use gc_hint on the tree argument to pin down the otr structure that we reference in initializations (copy_tree_iter): Use gc_hint on iter, for similar reasons. * vm.c (vm_copy_closure): Use gc_hint on oclosure, to pin down the environment we are copying from it.
* eval: potential gc problem in binding.Kaz Kylheku2024-01-061-1/+1
| | | | | | | | | | * eval.c (reparent_env): This function is used in bindings helper, when special variables are involved. It makes a new environment the parent of an existing one, just by assigning the pointer. This is wrong under generational GC if it makes a mature object point to a new object. We fix it with the set macro. I've not seen a crash because of this; I caught it by inspection.
* gc: bug in sub-str on lazy string argument.Kaz Kylheku2024-01-061-0/+1
| | | | | | | | | | | This showed up as an intermittent segfault on OpenBSD of the test case tests/006/freeform-5.txr, reproducible quite often, around 30% to 60%. This was with gcc 4.2.1. * lib.c (lazy_sub_str): We need a gc_hint here on the prefix hend in pfxcopy. The garbage collector is scavenging that object, not seeing that we planted it into a malloced structure.
* sysif: unused parameter warning on solaris.Kaz Kylheku2024-01-051-0/+1
| | | | | * sysif.c (link_wrap_common): Cast the follow_link argument to void in the #else case to suppress warning.
* tests: fix tests/007/except-4.txr for Solaris, BSD.Kaz Kylheku2024-01-052-5/+2
| | | | | | | | | | | | | | | | | * tests/007/except-4.txr: The portable way to get a shell command that exits with a signal is to execute kill -KILL $$. If we use a signal that the shell catch like SIGTERM or SIGINT, we get nonportable behaviors. Some shells seem to catch the signal and then raise it again so they terminate with that signal. Some shells terminate normally, but create an exit status by OR-ing 0x80 with the caught signal. Let's use kill -KILL here and drop the tests for BSD and Solaris. * tests/007/except-3.txr: Fix the kill command here also. While this test wasn't failing on those platforms, it succeeds vacuously, since the exception being ignored by :nothrow is not actually thrown.
* openbsd: more tests fixes.Kaz Kylheku2024-01-055-5/+5
| | | | | | | | | | | | | * tests/014/socket-basic.tl: Test for :openbsd also were we test for :bsd. * tests/014/glob-carray.tl: Likewise. * tests/017/glob-zarray.tl: Likewise. * tests/017/mmap.tl: Likewise. * tests/018/chmod.tl: Likewise.
* build: wrong build order of STDLIB_EARLY_TLOS.Kaz Kylheku2024-01-051-5/+2
| | | | | | | | | | | | | | | | | The STDLIB_EARLY_TLOS are not being built in the intended order for several reasons. Firstly, the list is built by filtering STDLIB_TLOS which are in an order pulled by the wildcard command. Secondly, the order-only rule isn't preserving the order among the early tlos, only ensuring that those members of STDLIB_TLOS which occur in STDLIB_EARLY_TLOS are built before the others. * Makefile (STDLIB_EARLY_PATS): Variable removed. (STDLIB_EARLY_TLOS): Specified directly rather than via filtering. (all): Don't depend on $(STDLIB_TLOS) but rather on $(STDLIB_EARLY_TLOS) and $(STDLIB_LATE_TLOS) in that order. ($(STDLIB_LATE_TLOS):): Ordering rule removed.
* tests: fix on OpenBSD.Paul A. Patience2024-01-054-5/+11
| | | | | | | | * tests/common.tl (os-symbol): Add :openbsd. * tests/007/except-4.txr: Skip. * tests/018/crypt.tl: Skip unsupported salts, i.e., without leading "$". * tests/018/gzip.tl: Add -f to gzip command to force compression even if it does not make the file smaller.
* sysif: fix build on OpenBSD.Paul A. Patience2024-01-041-0/+2
| | | | | | | OpenBSD is missing RLIMIT_AS. * sysif.c (sysif_init): Register rlimit-as variable only if RLIMIT_AS is defined.
* doc: formatting under compiler-let.Kaz Kylheku2024-01-041-1/+1
| | | | * txr.1: Fix markup of syntax, invalid due to missing space.
* doc: clarification regarding sort stability.Kaz Kylheku2024-01-031-1/+3
| | | | | * txr.1: Clarify that both sort and nsort are not stable for vectors and strings.
* configure: capitalize diagnostic line.Paul A. Patience2024-01-031-1/+1
| | | | * configure: Capitalize first word "detecting" of diagnostic line.
* configure: normalize spacing in diagnosticsPaul A. Patience2024-01-011-14/+14
| | | | | * configure: Add space after ellipses where missing, and prefer putting the space in the initial printf.
* iter_begin: gc problem.Kaz Kylheku2024-01-011-0/+2
| | | | | | | | | | Also affects seq_begin. * lib.c (seq_begin, iter_begin): We must gc_protect the incoming obj also, not only the iter. Both these pointers are in the seq_info_t structure which is no longer used at the time the iterator is being allocated by the call to cobj, and so may be prematurely garbage collected.
* configure: fix for BSD grep.Paul A. Patience2024-01-011-2/+2
| | | | | * configure: Pipe output of strings into grep in endianness test, like is done for ubsan.
* Version 293.txr-293Kaz Kylheku2023-12-286-659/+709
| | | | | | | | | | | | * RELNOTES: Updated. * configure (txr_ver): Bumped version. * stdlib/ver.tl (lib-version): Bumped. * txr.1: Bumped version and date. * txr.vim, tl.vim: Regenerated.
* build: automate clean-up of shipped scanner and parserKaz Kylheku2023-12-285-9/+44
| | | | | | | | | | * Makefile (shipped): Copy the shipped materials unconditionally, rather than checking if they are different. If a patch exists for a shipped file, then apply it. * lex.yy.c.shipped, y.tab.c.shipped: Updated. * lex.yy.c.patch, y.tab.c.patch: New files.
* read-objects: clean up working, but odd code.Kaz Kylheku2023-12-281-3/+2
| | | | | | | | | | | | | This was prompted by a misleading indentation warning. * parser.c (read_objects_common): The indented statment "return error_return_val;" belongs with the if. This works anyway because if lisp_parse_impl returned unique_s, it means that either pi->syntax_tree is nao, or pi->errors is positive. So, let's take advantage of that and don't bother checking for pi->syntax_tree == nao. If unique_s was returned and there are no errors, we hit EOF and so break out of the loop.
* cygwin: run, sh: mangle termination status word.Kaz Kylheku2023-12-281-0/+10
| | | | | | | | | | * stream.c (run): On Cygwin, the spawnvp function is returning a 16 bit termination status word where the upper 8 bits is the termination status if the termination is normal, otherwise the lower 8 bits holds a termination signal. Let's massage it so that the function returns an integer termnation status, or nil if the termination was abnormal, same as we do on POSIX platforms with fork/wait.
* perm, rperm, comb, rcomb: test generic sequences, bugfixes.Kaz Kylheku2023-12-272-28/+36
| | | | | | | | | | | | | | | | | | | | | | | | perm doesn't generate items of the right type. We need to add the original sequence to the state vector and use make_like. The new generic sequence support in rperm is broken, too. * combi.c (perm_while_fun, perm_gen_fun_common): Rename p variable to vec. (perm_init_common): Rename to perm_init. Take one more argument and store in new fourth element of state vector. (perm_vec, perm_list, perm_str): Pass nil to new parameter of perm_init. (perm_seq_gen_fun): Use perm_list_gen_fun to get list permutations, and coerce each one to the same type as the sequence with make_like. (rcomb_seq_gen_fun): Remove redundant call to rcomb_gen_fun_common. The rcomb_list_gen_fun function is called, which does this already, so we lose every other sequence element. * tests/015/comb.tl: New tests.
* rcomb: support general sequences.Kaz Kylheku2023-12-271-1/+17
| | | | | | * combi.c (rcomb_seq_gen_fun, rcomb_seq): New static functions. (rcomb): Replace error throw in default case with call to rcomb_seq.
* comb: support general sequences.Kaz Kylheku2023-12-271-1/+16
| | | | | | | * combi.c (comb_seq_gen_fun, comb_seq): New static functions. (comb): Call comb_seq in default case rather than throwing error.
* comb: eliminate comb_hash_while_fun.Kaz Kylheku2023-12-271-8/+3
| | | | | | | | * combi.c (comb_hash_while_fun): Function removed. (comb_hash): For the while function, use the unwrapped state, and just comb_while_fun. The augmented state with hash is used only with comb_hash_gen_fun.
* rperm: support general sequences.Kaz Kylheku2023-12-271-6/+23
| | | | | | | | | | | | | | | | * combi.c (rperm_init): Take one more parameter. Allocate the state vector to three elements and put the extra value there. (rperm_list, rperm_vec, rperm_str): Pass nil for the extra value to rperm_init; these do not use it. (rperm_seq_gen_fun, rperm_seq): New functions. These use the extra value to store the original seq in the state, so that the elements of the output sequence can be converted to the same type of sequence as the input. (rperm): Replace error throw in default case with call to rperm_seq.
* rperm: change state representation to vector.Kaz Kylheku2023-12-271-8/+15
| | | | | | | | * combi.c (rperm_init): New static function. (rperm_while_fun, rperm_gen_fun): Retrieve state info from vector-based state rather than cons. (rperm_list, rperm_vec, rperm_str): Call rperm_init to allocate state.
* rcomb, perm, rperm: test.Kaz Kylheku2023-12-271-0/+317
| | | | * tests/015/comb.tl: New tests.
* doc: fix comb reference under rcomb.Kaz Kylheku2023-12-271-1/+1
| | | | | * txr.1: Section describing rcomb function wrongly refers to comb.
* comb: bug: missing combinations.Kaz Kylheku2023-12-262-39/+174
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The comb function is broken; some combinations of items are missing in the output. This is because the iteration reset step in comb_gen_fun_common handles only one column of the state, neglecting to reset the other columns: what is now done by the for (j = i ... loop. I'm changing the representation of the state from a list of lists to a vector of lists. Moreover, it is not reversed. This allows the loop in comb_gen_fun_common to perform random access. * combi.c (k_conses): Return a vector, that is not reversed. (comb_init): New helper function to slightly abstract the use of k_conses. (comb_while_fun): Termination now occurs if the state vector is nil (degenerate case, like k items chosen from n, when k > n), or if the vector has nil in element zero (special flag situation). (comb_gen_fun_common): Rewritten, with correction. The logic is similar. Since we have random access, we don't need the "prev" variable. When we reset a column iterator, we now also populate all the columns to the right of it. For instance, if a given column resets to (a b c), the one to the right must reset to (b c), and so on. In the broken function, this is what was not done, resulting in missing items due to, say, a column resetting to (a b c) but the one next to it remaining at (c). (comb_list_gen_fun): Drop nreverse. (comb_vec_gen_fun, comb_str_gen_fun, comb_hash_gen_fun): Use the same i iterator for the state and the output object, accessing the vector directly. (comb_list, comb_vec, comb_str, comb_hash): Use comb_init. * tests/015/comb.tl: New file.
* perm: support general sequences.Kaz Kylheku2023-12-261-1/+24
| | | | | | * combi.c (perm_seq_gen_fun, perm_seq): New functions. (perm): Call perm_seq in default case to handle more sequence kinds.
* doc: in Math Library mention User-Defined ArithmeticKaz Kylheku2023-12-201-0/+28
| | | | | | | | | * txr.1: The Math Library is documented in a way that is oblivious to User-Defined Arithmetic. This is now clarified. When some of the argument types of a math function are user-defined arithmetic structures, the stated conversions and restrictions don't apply, since it defers all semantics to the method invoked.
* Makefile: operands reversed in abbreviated output.Kaz Kylheku2023-12-201-1/+1
| | | | | | * Makefile (shipped): This rule works correctly but shows, for instance, COPY lex.yy.c.shipped -> lex.yy.c. which is backwards. Let's fix it.
* json: support Lisp comments.Kaz Kylheku2023-12-204-3594/+3645
| | | | | | | | | | | | | | | I've run into situations in which I wanted a comment in a big JSON quasiliteral to explain some embedded piece of code. We support only semicolon comments, and no #; ignore notation. * parser.l (grammar): Recognize Lisp comments in the JSON state also. That does it. * tests/010/json.tl: One modest little test. * txr.1: Documented. * lex.yy.c.shipped: Regenerated.
* compiler: optimizer must watch for throwing constant exprsKaz Kylheku2023-12-202-11/+27
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | We have these issues, which are regressions: 1> (compile-toplevel '(/ 1 0)) ** expr-1:1: warning: sys:b/: constant expression (sys:b/ 1 0) throws ** /: division by zero ** during evaluation at expr-1:1 of form (sys:b/ 1 0) 1> (compile-toplevel '(let ((a 1) (b 0)) (/ a b))) ** /: division by zero ** during evaluation at expr-1:1 of form (compile-toplevel [...]) While the compiler's early pass constant folding is careful to detect constant expressions that throw, care was not taken in the optimizer's later constant folding which takes place after constant values are propagated around. After the fix: 1> (compile-toplevel '(let ((a 1) (b 0) (c t)) (if c (/ a b)))) ** expr-1:1: warning: let: function sys:b/ with arguments (1 0) throws #<sys:vm-desc: 9aceb20> 2> (compile-toplevel '(let ((a 1) (b 0) (c nil)) (if c (/ a b)))) #<sys:vm-desc: 9aef9f0> * stdlib/compiler.tl (compiler): New slot top-form. (compile-toplevel): Initialize the top-form slot of the compiler. The optimizer uses this to issue a warning now. Since the warning is based on analyzing generated code, we cannot trace it to the code more precisely than to the top-level form. * stdlib/optimize.tl (basic-blocks): New slot, warned-insns. List of instructions that have been warned about. (basic-blocks do-peephole-block): Rearrange the constant folding case so that as part of the pattern match condition, we include the fact that the function will not throw when called with those constant arguments. Only in that case do we do the optimization. We warn in the case when the function call does throw. A function rejected due to throwing could be processed through this rule multiple times, under multiple peephole passes, so for that reason we use the warned-insns list to suppress duplicate warnings.
* compiler: don't retain last form if it's an atom.Kaz Kylheku2023-12-201-1/+2
| | | | | | * stdlib/compiler.tl (compiler compile): Don't store form into me.last-form if it's an atom; it won't be useful or error reporting.
* New functions: read-objects, file-get-objects, ...Kaz Kylheku2023-12-197-8/+169
| | | | | | | | | | | | | | | | | | | | | | * parser.c (read_objects_common): New static function, formed from read_objects_from-string. (read_objects_from_string): Now wrapper for read_objects_common. (read_objects): New function. * parser.h (read_objects): Declared. * eval.c (eval_init): Register read-objects intrinsic. * autoload.c (getput_set_entries): Add three new symbols: file-get-objects, file-put-objects and file-append-objects. * stdlib/getput.tl (put-objects): New system function. (file-get-objects, file-put-objects, file-append-objects): New functions. * txr.1: Documented. * tests/018/getput.tl: New file.
* hash: new function, hash-join.Kaz Kylheku2023-12-184-0/+90
| | | | | | | | | | | * hash.c (hash_join): New function. (hash_init): hash-join intrinsic registered. * hash.h (hash_join): Declared. * tests/010/hash.tl: New tests. * txr.1: Documented.
* hash: test cases and small doc fix.Kaz Kylheku2023-12-182-1/+22
| | | | | | | * tests/010/hash.tl: Add test cases for the hash set operations. * txr.1: Clarify that in hash-uni, the mapping functions are used on all items, not just ones subject to joinfun.