summaryrefslogtreecommitdiffstats
Commit message (Collapse)AuthorAgeFilesLines
* freeform: bug: account for consumed prefix.Kaz Kylheku2022-01-043-1/+13
| | | | | | | | | | | | | | | | | | | | This was reported by user vapnik spaknik. The @(freeform), when reconstituting the unmatched trailing portion of the virtual line back into a list of lines, uses the abstract match position, neglecting to account for the fact that a prefix of the line may have been physically consumed to save memory. * match.c (v_freeform): When calling lazy_str_get_trailing_list, indicate the correct amount of prefix material, by subtracting, from the matching length, the base variable, which indicates how much of the prefix had been consumed. This consumption takes place above 4000 bytes, which is why the freeform test cases are not catching this. * tests/006/freeform-5.txr: New file. * tests/006/freeform-5.expected: New file.
* sysif: rlim constants: use signed/unsigned-agnostic macro.Kaz Kylheku2022-01-022-3/+5
| | | | | | | | | | | | * lib.h (num_ex): New macro. Uses unum if the argument is out of range for the signed type. Thus we can use this with unsigned constants that would wrap negative if passed to num. This is useful if some type in a system header file might be signed or unsigned. * sysif.c (sysif_init): Use num_ex for the RLIM_* constants. I'm observing values of -1 which should really be large, positive values in the rlim_t type, that being unsigned.
* ffi: allow enumed bitfield.Kaz Kylheku2022-01-023-22/+64
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * ffi.c (ffi_type_copy): Function moved earlier in file without change. (ffi_type_copy_new_ops): New stati function. (make_ffi_type_enum): Do not create a new type object using cobj; copy the existing base_type, and then tweak its properties, just like what is done with bool. Thus if base_type is a bitfield, the enum will be a bitfield. Add check against doign this to anything but an FFI_KIND_NUM, with the awareness that this does include floating-point types. Since tft is now a copy, we no longer have to copy a number of things from btft. We do set he kind field to FFI_KIND_ENUM. (ffi_type_compile): In the two bitfield cases, we now calculate the mask field for the bitfield type (leaving the shift at zero). The struct or union type into which the bitfield is embedded will still re-calculate this. The reason is that when an (enumed (bit ...) ...) type is defined, it constructs hash tables for converting between the symbolic and numeric values. It calls the put function of the underlying type to test whether each enumeration value can be converted (i.e. is in range). So the bitfield type must have a valid mask at that time, or else it will reject every nonzero value as being out of range for the bitfield. I'm also replacing the max_int variable with bits_int. Since bitfields are restricted to no wider than int, why pretend? * tests/017/ffi-misc.tl: New test cases. * txr.1: Documented.
* rlimit: var init problem due to large file offset.Kaz Kylheku2022-01-022-0/+17
| | | | | | | | | | | | | | | | Now that we fixed the regression in detecting whether to use -D_FILE_OFFSET_BITS=64, this has unmasked an issue in newer code. In sysif.c, the RLIM_INFINITY, and related constants, are being passed to num_fast: but they are 64 bit unsigned constants under the large file offset, which don't fit into a cnum or unum on a 32 bit system. * configure: When we detect large file offset, we deposit the tell-tale configuration constant CONFIG_LARGE_FILE_OFFSET into config.h. * sysif.c (sysif_init): Under CONFIG_LARGE_FILE_OFFSET, treat the RLIM_ constants using bignum_dbl_uipt.
* configure: support 64 bit time_t on glibc.Kaz Kylheku2021-12-301-11/+36
| | | | | | | | | | | | | | | | | There is a new feature in glibc: -D_TIME_BITS=64 makes time_t 64 bits wide, as part of a solution to Y2038. Let's detect this together with _FILE_OFFSET_BITS in the same test. I've not tested this because I need a system with a bleeding edge glibc that supports _TIME_BITS. * configure (time_bits_define): New variable. Test which searches some known command line options for 64 bit off_t expanded to also check for 64 bit time_t. This complicates the loop only slightly; it is much better than copy and pasting the code
* configure: broken file offset bits detection.Kaz Kylheku2021-12-301-1/+1
| | | | | | | | | | | | | We are not detecting the need to do -D_FILE_OFFSET_BITS=64 correct, resulting in no large file support on 32 bit platforms based on Glibc. This is a regression since TXR 244. * configure: We must pass EXTRA_FLAGS=-D$try to actually try the options we are looping over. This argument was accidentally removed in commit 3d80caccafc27ac812bbf8226eba6d8e529c63ff on October 9, 2020, when the conftest_symns command was changed to conftest_o.
* configure: file offset test: don't change config.hKaz Kylheku2021-12-301-2/+0
| | | | | | | | * configure: The file offset test has no reason to be writing anything into config.h. The SIZEOF_OFF_T symbol isn't used anywhere, and SIZEOF_BYTE already exists in the header. Because this command is in a loop, it ends up writing multiple definitions of SIZEOF_BYTE, and SIZEOF_OFF_T into config.h.
* doc: "sme" typo under :delegate.Kaz Kylheku2021-12-301-1/+1
| | | | | | * txr.1: Fix sme -> same. This creeps in because "sme" is whitelisted due to the @(sme ...) pattern notation (start/middle/end).
* configure: detect warning opts missing in older compilers.Kaz Kylheku2021-12-301-2/+16
| | | | | | | | | | | | * configure (diag_flags): Remove -Wvla and -Werror=declaration-after-statement. (diag_flags_given): New variable. New test: if diag_flags_given indicates that diag_flags were not specified by the user, then we try to add additional flags, subject to them being available, which we test by compiling the hello-world program with those flags. We rely on the hello-world program being left over by the previous compiler sanity check.
* Eliminate declaration-after-statement everywhere.Kaz Kylheku2021-12-2920-151/+215
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The use of -ansi doesn't by itself diagnose instances of some constructs we don't want in the project, like mixed declarations and statements. * configure (diag_flags): Add -Werror=declaration-after-statement. This is C only, so filter it out for C++. Also add -Werror=vla. * HACKING: Update inaccurate statements about what dialect we are using. TXR isn't pure C90: some GCC extensions are used. We even use long long if the configure script detects it as working, and some C99 library features. * buf.c (replace_buf, buf_list): Fix by reordering. * eval.c (op_dohash, op_load_time_lit): Fix by reordering. * ffi.c (ffi_simple_release): Fix by reordering. (align_sw_get): Fix empty macro to expand to dummy declaration so a semicolon after it isn't interpreted as a statement. On platforms with alignment, remove a semicolon from the macro so that it requires one. (ffi_i8_put, ffi_u8_put): Fix by reordering. * gc.c (gc_init): Fix with extra braces. * hash.c (hash_init): Fix by reordering. * lib.c (list_collect_revappend, sub_iter, replace_str, replace_vec, mapcar_listout, mappend, mapdo, window_map_list, subst): Fix by reordering. (gensym, find, rfind, pos, rpos, in, search_common): Fix by renaming optional argument and using declaration instead of assignment. * linenoise/linenoise.c (edit_in_editor): Fix by reordering. * parser.c (is_balanced_line): Fix by reordering. * regex.c (nfa_count_one, print_rec): Fix by reordering. * signal.c (sig_mask): Fix by reordering. * stream.c (get_string): Fix by renaming optional argument and using declaration instead of assignment. * struct.c (lookup_static_slot_desc): Fix by turning mutated variable into block local. (umethod_args_fun): Fix by reordering. (get_special_slot): Fix by new scope via braces. * sysif.c (usleep_wrap): Fix by new scope via braces. (setrlimit_wrap): Fix by new scope via braces. * time.c (time_string_meth, time_parse_meth): Fix by reordering. * tree.c (tr_do_delete_spec): Fix by new scope via braces. * unwind.h (uw_block_beg): New macro which doesn't define RESULTVAR but expects it to refers to an existing one. (uw_block_begin): Replace do while (0) with enum trick so that we have a declaration that requires a semicolon, rather than a statement, allowing declarations to follow. (uw_match_env_begin): Now opens a scope and features the same enum trick as in uw_block_begin. This fixes a declaration-follows-statement issue in the v_output function in match.c. (uw_match_env_end): Closes scope opened by uw_match_env_begin. * unwind.c (revive_cont): Fix by introducing variable, and using new uw_block_beg macro. * vm.c (vm_execute_closure): Fix using combination of local variable and reordering.
* Makefile: way to clean only C sources.Kaz Kylheku2021-12-291-1/+3
| | | | | | | * Makefile (clean-c): New target, complementary to clean-tlo, to only clean the C object files, executables and related materials, without touching the .tlo files. (clean): Depend on clean-c; body entirely moved into clean-c.
* help: fix preprocessor directive in macro call.Kaz Kylheku2021-12-291-3/+10
| | | | | | | * txr.c (IF_HAVE_FORK_STUFF): New macro, conditionally defined. (help): Remove #if in the middle of a lit() macro call in favor of IF_HAVE_FORK_STUFF.
* doc: spurious reference to car in search tree section.Kaz Kylheku2021-12-281-1/+0
| | | | | * txr.1: Remove spurious car place syntax from syntax section of key, left and right functions.
* Version 273.txr-273Kaz Kylheku2021-12-286-915/+1002
| | | | | | | | | | | | * RELNOTES: Updated. * configure (txr_ver): Bumped version. * stdlib/ver.tl (lib-version): Bumped. * txr.1: Bumped version and date. * txr.vim, tl.vim: Regenerated.
* doc: document *struct-clause-expander*.Kaz Kylheku2021-12-272-0/+31
| | | | | | | * txr.1: New section about special variable *struct-clause-expander*. * stdlib/doc-syms.tl: Updated.
* doc: stray reference to *place-macro*.Kaz Kylheku2021-12-271-1/+1
| | | | | * txr.1: In description of *match-macro* fix stray copy-paste referring to *place-macro*.
* match: allow bound variables with regex modifier.Kaz Kylheku2021-12-273-1/+37
| | | | | | | | | * stdlib/match.tl (expand-quasi-match): Add regex cases with bound variable. * tests/011/patmatch.tl: Test cases for this. * txr.1: Documented.
* match: bad compile-error call in quasi matcher.Kaz Kylheku2021-12-271-1/+1
| | | | | * stdlib/match.tl (expand-quasi-match): Fix too few arguments to compile-error for format args.
* doc: problems in qualisiteral pattern section.Kaz Kylheku2021-12-271-4/+2
| | | | | | | | * txr.1: Fix wrong word and number agreement: the sentence is about boudn variables. Fix bungled description of bound variable substitution; this should be a .meIP to head its own section, not in line meta-typesetting; plus the syntax must refer to a {P} and show the backticks.
* txr: do not ignore regex in positive match.Kaz Kylheku2021-12-273-44/+40
| | | | | | | | | | | | | | | | | * match.c (h_var): Refactor the logic here a bit. Without regard for whether the variable has a value, we dispatch the regex, fixed field and function cases. These handle the binding against the existing value. Then before all other cases, we check for the existing value and convert that to a literal text match. The effect of this is that now the regular expression is processed even if the variable has a value. * tests/010/span-var.txr: Last two test cases hardened a bit so they cannot fall through to a successful exit, if they invoke the wrong case. This is not related to this change. New test cases for regex span. * txr.1: Updated documentation and compatibility notes.
* txr: function span variable must match existing value.Kaz Kylheku2021-12-273-22/+278
| | | | | | | | | | | | | | | | | | | | * match.c (h_var_compat): New function; verbatim copy of existing h_var prior to this commit. (h_var): If a variable has an existing binding, but is a function spanning match, do not substitute it with text. Handle it with the ordinary case, in which we now use dest_bind instead of cons. (v_var): Similarly, here, we must also use dest_bind, rather than always freshly binding the variable. (match_compat_fixup): For 272 compatibility, substitute h_var_compat for h_var in the horizontal directive table. * tests/010/span-var.txr: New test cases. * txr.1: Documentation updated and also improved overall. The behavior when a variable has an existing value is clarified for the regex and fixed field case. Also update and condense compat notes for 272.
* txr: allow variable to span vertical function.Kaz Kylheku2021-12-265-7/+95
| | | | | | | | | | | | | | | * match.c (v_var_compat, v_var): New static functions. (match_files): No longer recognize v_var specially; it is now handled via vertical table. (dir_tables_init): Register a vertical sys:var directive also via v_var function. (match_compat_fixup): New function. * txr.c (compat): Call match_compat_fixup. * tests/010/span-var.txr: New file. * txr.1: Documented.
* new feature: :mass-delegate struct clause macro.Kaz Kylheku2021-12-234-0/+213
| | | | | | | | | | | | | | | With :mass-delegate, it is possible to generate delegation methods in bulk. All of the methods of a struct type can be mirrored by delegates in another struct type just by writing a single :mass-delegate clause. * stdlib/struct.tlk (:mass-delegate): New struct clause macro. * tests/012/oop.tl: New tests. * txr.1: Documented. * stdlib/doc-syms.tl: Updated.
* eval: fix optional parameter bug from 2014.Kaz Kylheku2021-12-232-4/+17
| | | | | | | | | | | | | | | | | | | | | | | | | | | | This bug affects optional parameters which either have no default expression, or one that is nil. For instance x in (lambda (: (x nil))) or (lambda (: x)). When such a parameter is given the : symbol as an argument, it is not being bound, as if it weren't there. ((lambda (: x) x) :) -> ;; error: unbound variable x This issue is not a regression; it was introduced in the commit which introduced the colon convention to optionals, as well as init expressions and presence-indicating variables, commit 68c084269581f32f0a7b859446ae2efb6c6a26c0 made in February 2014. This might be the first instance of an interpreter bug being found that is not present in the compiler. * eval.c (bind_args): The idea here was that when the argument to an optional the colon keyword symbol, and the optional's initform is nil, we can skip the overhead of calling eval to get that initform's value. Unfortunately, the skip was extended over the code which binds the parameter. Only the eval can be skipped! * tests/012/lambda.tl: New test cases to cover this.
* new feature: defstruct clause macros.Kaz Kylheku2021-12-225-18/+313
| | | | | | | | | | | | | | | | | | | | | | * lisplib.c (struct_set_entries): Trigger autoload on new symbols define-struct-clause and *struct-clause-expander*. * stdlib/struct.tl (*struct-clause-expander*): New variable. (defstruct): expand-slot local function now returns list of expanded slots, not a single slot; every case in the tree-case is converted to return a list. The syntax of a slot clause is first expanded through *struct-clause-expander hash; if that works then the resulting list is further scanned for expansions. (define-struct-clause): New macro. (:delegate): New struct clause defined with define-struct-clause. Provides single-slot delegation. * tests/012/oop.tl: Tests for :delegate. * txr.1: Documented define-struct-clause and :delegate. * stdlib/doc-syms.tl: Updated.
* defstruct: refactor with local function.Kaz Kylheku2021-12-221-147/+146
| | | | | | | | * stdlib/struct.tl (defstruct): Move the large tree-case in the loop which calculates the expanded slot syntax into a local function called expand-slot. This anticipates the addition of application-defined slot expanders, which will produce output that has to be recursed upon.
* The pairlis function comes to TXR Lisp.Kaz Kylheku2021-12-226-0/+87
| | | | | | | | | | | | * eval.c (eval_init): Register pairlis intrinsic. * lib.c, lib.h (pairlis): New function. * tests/012/seq.tl: New test cases. * txr.1: Documented. * stdlib/doc-syms.tl: Updated.
* New functions: subq, subql, subqual and subst.Kaz Kylheku2021-12-227-5/+181
| | | | | | | | | | | | | | | * eval.c (eval_init): Register new intrinsics. * lib.c, lib.h (subq, subql, subqual, subst): New functions. * tests/012/seq.tl: New test cases. * stdlib/optimize.tl (subst): Function removed. The new subst drop-in replaces this one. * txr.1: Documented. * stdlib/doc-syms.tl: Updated.
* product/arithmetic each: missing block nil.Kaz Kylheku2021-12-203-63/+91
| | | | | | | | | | | | | | | | | | | * stdlib/arith-each.tl (sys:vars-check): New function, copy and pasted from each-prod.tl. (sys:arith-each): New macro. (sum-each, sum-each*, mul-each, mul-each*): Reworked using sys:arith-each macro. This macro uses logic borrowed from a stripped-down expand-each in the compiler. * stdlib/each-prod.tl (sys:expand-each-prod, sys:expand-arith-each-prod*): Add the block nil around the mapping call, taking care that the initialization forms are evaluated outside of the block, and their values bound to gensyms that then form the function arguments. * txr.1: Document the missing requirements for all the affected macros that there must be an anonymous block around the body, which, if used, determines the return value.
* maprodo: bugfix: spurious return value.Kaz Kylheku2021-12-201-9/+7
| | | | | | | | | | | | | | | There are cases when maprodo returns a non-nil value, even though it is supposed to collect nothing. This is because though it is is collecting nothing, that nothing is sometimes converted to an alternative return type via make_like. * eval.c (prod_common): We allow the collect_fn function pointer to be null, to indicate nothing is to be collected, rather than using a stub. If collect_fn is null, we just call the mapping function without collecting its value, and at the end, we do not involve make_like and just return nil. (collect_nothing): Static function removed. (maprodo): Pass null function pointer instead of collect_nothing.
* less: bug, vectors not supported.Kaz Kylheku2021-12-202-1/+23
| | | | | | | | * lib.c (less_tab_init): Add missing initialization for VEC, with a priority above CONS: all vectors are greater than conses. The BUF priority is bumped to 7. * test/012/less.tl: New file.
* tree: new functions for priority queue operation.Kaz Kylheku2021-12-185-0/+156
| | | | | | | | | | | | | | | | * tree.c (tree_min_node, tree_min, tree_del_min_node, tree_del_min): New functions. (tree_init): tree-min-node, tree-min, tree-del-min-node, tree-del-min: New intrinsics registered. * tree.h (tree_min_node, tree_min, tree_del_min_node, tree_del_min): Declared. * txr.1: Documented. * tests/010/tree.tl: New tests. * stdlib/doc-syms.tl: Updated.
* tree: bugfix wrong tree-count.Kaz Kylheku2021-12-182-2/+14
| | | | | | | | | | | | | When duplicate keys are inserted in the default way with replacement, the tree size must not be incremented. * tree.c (tr_insert): Increment the tr->size and maintain tr->max_size here. In the case of replacing an existing node, do not touch the count. * tests/010/tree.tl: Add test cases covering duplicate insertion and tree-count. (tree_insert_node): Remove unconditional size increment.
* tree: support for duplicate keys.Kaz Kylheku2021-12-179-28/+309
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * tree.c (tr_insert): New argument for allowing duplicate. If it is true, suppresses the case of replacing a node, causing the logic to fall through to traversing right, so the duplicate key effectively looks like it is greater than the existing duplicates, and gets inserted as the rightmost duplicate. (tr_do_delete_specific, tr_delete_specific): New static functions. (tree_insert_node): New parameter, passed to tr_insert. (tree_insert): New parameter, passed to tree_insert_node. (tree_delete_specific_node): New function. (tree): New parameter to allow duplicate keys in the elements sequence. (tree_construct): Pass t to tree to allow duplicate elements. (tree_init): Update registrations of tree, tree-insert and tree-insert-node. Register tree-delete-specific-node function. * tree.h (tree, tree_insert_node, tree_insert): Declarations updated. (tree_delete_specific_node): Declared. * lib.c (seq): Pass t argument to tree_insert, allowing duplicates. * parser.c (circ_backpatch): Likewise. * parser.y (tree): Pass t to new argument of tree, so duplicates are preserved in the element list of the #T literal. * y.tab.c.shipped: Updated. * tests/010/tree.tl: Test cases for duplicate keys. * txr.1: Documented. * stdlib/doc-syms.tl: Updated.
* tree-count: new function.Kaz Kylheku2021-12-175-2/+33
| | | | | | | | | | | | | * tree.c (tree_count): New function. (tree_init): tree-count intrinsic registered. * tree.h (tree_count): Declared. * lib.c (length): Support search tree argument via tree_count. * tests/010/tree.tl: Test cases for tree-count, indirectly via len. * txr.1: Documented.
* iter-reset: gc problem.Kaz Kylheku2021-12-171-0/+3
| | | | | | | | | | | | | * lib.c (iter_reset): When we reinitialize the iterator, it can allocate a new secondary object, e.g. using hash_begin, which is stored into the iterator. This is potentially a wrong-way assignment in terms of GC generations and so we must call mut(iter) to indicate that the object has been suspiciously mutated. We only do this if the iterator has a mark function. If it doesn't have one, then it isn't wrapping a heap object, and so doesn't have this issue. (seq_reset): This has the same issue, and the fix is the same. Since ths function is obsolescent, we don't bother doing the si->ops->mark check; we optimize for code size instead.
* iter-begin: gc problem.Kaz Kylheku2021-12-171-4/+8
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Issue 1: the seq_iter_init_with_info function potentially allocates an object via hash_begin or tree_begin and installs it into the iterator. The problem is that under iter_begin, the iterator is a heaped object; this extra allocation can trigger gc which pushes the iterator into the mature generation; yet the assignment in seq_iter_init_with_info is just a plain assignment without using the set macro. Issue 2: when gc is triggered in the above situations, it crashes due to the struct seq_iter being incompletely initialized. The mark function tries to dereference the si->ops pointer. Alas, this is initialized in the wrong order inside seq_iter_init_with_info. Concretely, tree_begin is called first, and then the it->ops = &si_tree_ops assignment is performed, which means that if the garbage collector runs under tree_begin, it sees a null it->ops pointer. However, this issue cannot just be fixed here by rearranging the code because that leaves Issue 1 unsolved. Also, this initialization order is not an issue for stack-allocated struct seq_iters. The fix for Issue 1 and Issue 2 is to reorder things in iter_begin. Initialize the iterator structure first, and then create the iterator cobj. Now, of course, that goes against the usual correct protocol for object initialization. If we just do this re-ordering naively, we have Issue 3: the familiar problem that the cobj() call triggers gc, and the iterator object (e.g. from tree_iter) that has been stored into the seq_iter structure is not visible ot the GC, and is reclaimed. * lib.c (iter_begin): reorder the calls so that seq_iter_init_with_info is called first, and then the cobj to create from it the heap-allocated iterator, taking care of Issue 1 and Issue 2. To avoid Issue 3, after initializing the structure, we pull out the vulnerable iterator object into a local variable, and pass it to gc_hint(), to ensure that the variable is spilled into the stack, thereby protecting it from reclamation. (seq_begin): This function has exactly the same issue, fixed in the same way.
* compiler: fix broken (compile '(lambda ...)).Kaz Kylheku2021-12-141-15/+17
| | | | | | | | | | * stdlib/compiler.tl (compile): The symbol-function function returns true for lambda and that's where we are handling lambda expressions. However, the (set (symbol-function ...) ...) then fails: that requires a function name that designates a mutable function location. Let's restructure the code with match-case, and handle the lambda pattern separately via compile-toplevel.
* compiler: small end/jend issue in late-peephole.Kaz Kylheku2021-12-111-1/+1
| | | | | | | | | * stdlib/optimize.tl (basic-blocks late-peephole): In one pattern, an instruction that is recognized as (jend ...) is inadvertently rewritten to (end ...). Since this is the last optimization stage, currently, and end and jend are synonyms for the same opcode, it doesn't matter. But it could turn into a bug; let's fix it.
* compiler: tweak in basic block debug print.Kaz Kylheku2021-12-111-1/+1
| | | | | | * stdlib/optimize (basic-block print): Print the label of the next block, rather than the block itself. This reduces the verbosity during debugging.
* compiler: register-compacting optimization.Kaz Kylheku2021-12-102-0/+63
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This work addresses the following issues, which cause compiled functions to use more stack space than necessary. Firstly, the compiler doesn't allocate registers tightly. Every closure's registers can start at t2, but this isn't done. Secondly, data flow optimizations eliminate registers, leaving gaps in the register allocation. Code ends up strange: you may see register t63 used in a function where the next highest register below that is t39: evidence that a large number of temporary variables got mapped to registers and eliminated. In this change, an optimization is introduced, active at *opt-level* 6 which compacts the t registers for every closure: every closure's registers are renumbered starting from t2. Then, each closure' generating close instruction is also updated to indicate the accurate number of registers ensuring no space is wasted on the stack when the closure is prepared for execution. * stdlib/compiler.tl (compiler optimize): At optimization level 6, insert a call to basic-blocks compact-tregs just before the instruction are pulled out and put through the late peephole pass. * stdlib/optimize.tl (basic-block): New slot, closer. This is pronounced "clozer", as in one who closes. For any basic block that is the head of a closure (the entry point ito the closure code), this slot is set to point to the previous block: the one which ends in the close instruction which creates this closure: the closer. This is important because the close instruction can use t registers for arguments, and those registers belong to the closure. Those argument registers must be included in the renaming. (basic-blocks): New slots closures and cl-hash. The former lists the closure head basic blocks; all the basic blocks which are the entry blocks of a closure. The cl-hash associates each head block with a list of all the blocks (including the head block). (basic-blocks identify-closures): New method. This scans the list of blocks, identifying the closure heads, and associating them with their closers, to establish the bb.closure list. Then for each closure head in the list, the graph is searched to find all the blocks of a closure, and these lists are put into the bb.cl-hash. (basic-block fill-treg-compacting-map): This method scans a basic block, ferreting out all of it t registers, and adds renaming entries for them into a hash that is passed in. If the block is the head of a closure, then the close instruction of the block's closer is also scanned for t registers: but only the arguments, not the destination register. (basic-block apply-treg-compacting-map): This method renames the t register of a block using the renaming map. It follows the registers in the same way as fill-treg-compacting-map, and consquently also goes into the close instruction to rename the argument registers, as necessary. When tweaking the close instruction, it also updates the instruction's number-of-tregs field with the newly calculated number, which comes from the map size. (basic-blocks compact-tregs): This method ties it together, using the above methods to identify the basic blocks belonging to closures, build register renaming maps for them, and hen apply the renaming.
* define-accessor: fix broken arg handling.Kaz Kylheku2021-12-102-1/+13
| | | | | | | | | | | I discovered this off chance by searching for occurrences of (let ,(zip ...) ...) or (let (,*(zip ...)) ...) in the code base, noticing an incorrect one. * stdlib/place.tl (sys:register-simple-accessor): Remove spurious list around ,(zip temps args). * tests/012/defset.tl: Test cases for define-accessor added.
* each-match macro family: missing anon block.Kaz Kylheku2021-12-083-4/+22
| | | | | | | | | | | | | | | | | * txr.1: Adding the missing requirement that each-match and the other macros in that family must have an implicit anonymous block around the body forms. This is a requirements bug, effectively: the programmer expects these operators to be consistent with the each operator, as part of the same family. * match.tl (each-match-expander): Implement the requirement. Since we are using mapping functions, we must use temporary variables: the evaluation of the expressions which produce the sequence argument values to the mapping functions must be outside of the anonymous block. The block must surround only the function call. * tests/011/patmatch.tl: Add small test case covering this.
* case macros: bug in singleton key optimization.Kaz Kylheku2021-12-082-1/+33
| | | | | | | | | | | | * eval.c (me_case): Reduce (key) to key only if key is an atom. Otherwise we reduce ((a b c)), which is a single list-valued key to (a b c), which looks like three keys. This was introduced on Oct 25, 2017 in commit b72c9309c8d8f1af320dce616a69412510531b48, making it a regression. * tests/012/case.tl: New file. The last test case fails without this bugfix. The others pass either way.
* rot, nrot: new functions.Kaz Kylheku2021-12-076-0/+239
| | | | | | | | | | | | | | * eval.c (eval_init): nrot, rot intrinsics registered. * lib.c (nrot, rot): New functions. * lib.h (nrot, rot): Declared. * tests/012/seq.tl: New test cases. * txr.1: Documented. * stdlib/doc-syms.tl: Updated.
* ret, aret: take one argument, as documented.Kaz Kylheku2021-12-072-6/+6
| | | | | | | | | | | | | | | | * stdlib/op.tl (ret, aret): Simplify implementation, without progn or @rest, or interpolation of multiple args. We use identity* to allow the resulting function to allow and ignore multiple arguments. * txr.1: Strangely, an an edit in commit 99131c676, on Sep 26, 2014, reverted the more accurate equivalence (ret x) <--> (op identity (progn @rest x)) back to the original documentation (ret x) <--> (op identity x) which matched an older implementation. Anyway, that's moot now; the documentation is updated to give the new equivalence via identity*.
* quips: gift shop exit theme.Kaz Kylheku2021-12-061-0/+1
| | | | * stdlib/quips.tl (%quips%): New one.
* tuples*: new function.Kaz Kylheku2021-12-046-0/+170
| | | | | | | | | | | | | | | * eval.c (eval_init): Register tuples* intrinsic. * lib.c (tuples_star_func): New static function. (tuples_star): New function. * lib.h (tuples_star): Declared. * tests/012/seq.tl: New test cases. * txr.1: Documented. * stdlib/doc-syms.tl: Updated.
* tuples: change to abstract iteration.Kaz Kylheku2021-12-021-10/+16
| | | | | | | | | | | | | | | * lib.c (make_like): In the COBJ case, recognize an iterator object. Pull out the underlying object and recurse on it. This is needed in tuples_func, where make_like will now be called on the abstract iterator, rather than the actual sequence object. (tuples_func): The incoming object is now an iterator, and not a sequence; we need to handle it with iter_more, iter_item and iter_step. (tuples): Instead of nullify, begin iteration with iter_begin, and use iter_more to test for empty. In non-empty case, put propagate the iterator thorugh the lazy cons car field, rather than the sequence.
* tuples: add test cases.Kaz Kylheku2021-12-021-1/+48
| | | | * tests/012/seq.tl: Numerous test cases for tuples.