summaryrefslogtreecommitdiffstats
path: root/eval.c
Commit message (Collapse)AuthorAgeFilesLines
* buf: use C types in buf and buf_strm structures.Kaz Kylheku2025-05-301-1/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Using Lisp types for lengths, indices and buffer sizes has been awkward due to all the conversions. The code in buf.c and other code elsewhere that touches buffers, overall improves when we revise this decision. Mostly there are fewer conversion from Lisp to C which require a type check and self symbol for error diagnsotis, like c_unum(len, self). In a few places, there are conversions in the other direction that were not needed before, like unum(b->len). These are simpler and faster. * lib.h (struct buf): Members len and size change from val to ucnum (pointer-sized unsigned integer). * gc.c (mark_obj): No need to do anything with BUF any more; it has no Lisp object references. * buf.c (BUR_BORROWED): New preprocessor symbol. Because the allocation size can no longer be nil to indicate that the buffer is borrowed (the buffer object doesn't own the memory) we use this value instead: the highest value of the ucnum type. (buf_check_alloc_size): len parameter changes from cnum to ucnum. Defends against the BUF_BORROWED value. (buf_check_index): Returns ucnum rather than cnum. (err_oflow): NORETURN attribute added to prevent some spurious compiler warnings. (prepare_pattern): Drop c_unum conversion of len. (make_buf): Some locals change from cnum to ucnum. We lose an unnecessary conversion. (init_borrowed_buf): Take len as ucnum rather than val. Use BUF_BORROWED value for allocated size to indicate borrowed status. (make_borrowed_buf): Take len as ucnum. (make_duplicate_buf, make_owned_buf): Take len as ucnum, and take a self argument. Check for the size being BUF_BORROWED and reject. (make_ubuf): Parameter renamed. Lose a conversion from ucnum to val. (copy_buf): Check for allocated size being BUF_BORROWED to distinguish the two cases, rather than it being nil or not. (buf_shrink): Simplifies: loses a C to Lisp integer conversion, and no longer needs the local variable self. (buf_trim): Reject borrowed buffers by noticing the BUF_BORROWED value. (buf_do_set_len): len param becomes ucnum. Two Lisp-to-C integer conversiond disappear; one C-to-Lisp moves elsewhere in the code. (buf_set_length): Use buf_check_len to check and convert incoming len to ucnum. This is an improvement over the previous approach of letting buf_do_set_len to just rely on c_num conversions and their generic diagnostics. (buf_free): Check for borrowed buffer by comparing allocated size to BUF_BORROWED constant. (length_buf): ucnum to Lisp conversion now required here. (buf_alloc_size): Check for alloc_size being BUF_BORROWED and convert that to a nil return value. When returning an integer size, we need a conversion to a Lisp integer. (sub_buf): Use self symbol rather than lit("sub") when obtaining buffer handle. Use buf_check_len to validate the length and convert to C type. (replace_buf): Some cnum local variables become ucnum. We need a very careful comparison of w and l because w remains signed while l is unsigned. (buf_list): Substantially rewritten. We don't calculate the length of the sequence upfront, but extend the buffer as we add the elements to it. (buf_move_bytes): size parameter changes from cnum to ucnum. Lisp arithmetic replaced with C arithmetic; conversions eliminated. (buf_put_buf): Conversion eliminated in call to buf_move_bytes. (buf_put_bytes): Function reduced to wrapper for but_move_bytes, since it is almost identical. The only difference is that it performs memcpy rather than memmove which is not worth a separate function. (buf_put_i8, buf_put_u8, buf_put_char, buf_put_uchar, buf_get_i8, buf_get_u8): Simplified with C arithmetic and fewer conversions; cnum use replaced with ucnum. (buf_get_bytes): size parameter goes from cnum to ucnum. Overflow check for p + size addition added. (buf_print): Two conversions removed. (buf_str_sep): Conversion removed. (struct buf_strm): pos member changes from val to ucnum. (buf_strm_mark): Do not mark p->pos, no longer a Lisp object. (buf_strm_put_byte_callback): Lisp arithmetic removed, but a unum conversion is needed now in calling buf_put_uchar. That could be eliminated by not using the public interface. (buf_strm_get_byte_callback): Eliminate buf_check_index to validate the stream position; we simply check it against b->len. Becomes simple one liner. (buf_strm_get_char): Local variable index renamd to pos. Two conversions from and to Lisp eliminated, leaving no conversions. (buf_strm_unget_byte): Local variable p renamed to pos and changes from cnum to ucnum. Two conversions eliminated leaving no conversions. (buf_strm_fill_buf): Conversions eliminated. Check for the allocated size being BUF_BORROWED, in which case we fall back on using the length. Lisp arithmetic eliminated. (buf_strm_seek): Offset calculation done with C arithmetic and bounds checks. (buf_strm_truncate): Check incoming len with buf_check_len and convert to ucnum. Lisp arithmetic and conversions eliminated; buf_do_set_len used instead of public interface buf_set_length. (buf_strm_get_error): Use C comparison rather than ge function, and convert to t or nil result. (buf_strm_get_error_str): Bug: do not call errno_to_string since buffers don't talk to an operating system API that uses errno. The only error condition is eof. Thus, return either "eof" or "no error". (make_buf_stream): Initialize pos to 0 rather than Lisp zero. (swap32, buf_str, str_buf, buf_int, buf_uint, int_buf, uint_buf): Conversions eliminated; int_buf and uint_buf use C multiplication by 8. We know this doesn't overflow because the MPI bignums restrict the number of bits to something countable by a word. (buf_compress, buf_decompress, str_compress, str_decompress): Conversions eliminated. (buf_ash, buf_fash, buf_and, buf_test, buf_or, buf_xor, buf_not, buf_trunc, buf_bitset, buf_bit, buf_zero_p, buf_count_ones, binary_width, buf_xor_pattern): Make necessary adjustments, adding and/or elimiating conversions. * buf.h (make_borrowed_buf, init_borrowed_buf, make_owned_buf, make_duplicate_buf, buf_put_bytes): Declarations updated. * lib.c (equal, less): Conversions eliminated in BUF cases. * eval.c (map_common): Add self argument to make_owned_buf call. * chksum.c (chksum_ensure_buf): len param changes from cnum to ucnum. Conversions eliminated and use of lt() switches to C less-than operator. (sha1_stream, sha1_buf, sha1, sha1_hash, sha1_end, sha256_stream, sha256_buf, sha256, sha256_hash, sha256_end, md5_stream, md5_buf, md5, md5_hash, md5_end): Adjustments: conversions eliminated. (crc32_buf): Conversion eliminated. * genchksum.txr: Changes to chksum.c actually made here. * ffi.c (ffi_buf_in, ffi_buf_get, ffi_buf_d_in, ffi_buf_d_get, buf_carray, put_carray, fill_carray, put_obj, get_obj): Simplified with removal of conversions. (fill_obj): Necessary adjustments, leaving same number of conversions. * hash.c (equal_hash): Remove conversion from BUF case. * rand.c (make_random_state): Remove conversion of seed to Lisp integer. (random_buf): Pass self to make_owned_buf. * strudel.c (strudel_unget_byte, strudel_fill_buf): Coversions removed, streamlining code. * stream.c (iobuf_get, iobuf_put): We cannot overload the len field with serving as a linked list since it's no longer a pointer. We instead use the struct any union member, which has a next pointer for this purpose. Because "t.next" overlaps with "b.size", and we must not clobber the size field, we save "b.size" by copying it into "b.len". When pulling buffers from the iobuf_free_list, we restore b.size from b.len. For good measure, We add a bug_unless assertion that the size is the expected one. I ran into a test case failure while working on this due to the size being clobbered to zero, and subsequent I/O with that zero-sized buffer being interpreted as EOF.
* expander: handle format string in quasi.Kaz Kylheku2025-05-191-1/+5
| | | | | | | | * eval.c (expand_quasi): Quasiliteral sys:var items now have a format string, which we have to propagate to the expansion. * tests/012/quasi.tl: New tests.
* quasistrings: support format notation.Kaz Kylheku2025-05-181-18/+65
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This patch adds support to quasiliterals to have the inserted items formatted via a format conversion specifier, for example @~3,3a:abc is @abc modified by ~3,3a format conversion. When the inserted value is a list, the conversion is distributed over the elements individually. Otherwise it applies to the entire item. * eval.c (fmt_tostring, fmt_cat): Take additional format string argument. If it isn't nil, then do the string conversion via the fmt1 function rather than tostring. (do_format_field): Take format string argument, and pass down to fmt_cat. (format_field); Take format string argument and pass down to do_format_field. (fmt_simple, fmt_flex): Pass nil format string argument to fmt_tostring. (fmt_simple_fmstr, fmt_flex_fmstr): New static functions, like fmt_simple and fmt_flex but with format string arg. Used as run-time support for compiler-generated quasilit code for cases when format conversion specifier is present. (subst_vars): Extract the new format string frome each variable item. Pass it down to fmt_tostring, format_field and fmt_cat. (eval_init): Register sys:fmt-simple-fmstr and sys:flex-fmstr intrinsics. * eval.h (format_field): Declaration updated. * lib.c (out_quasi_str_sym): Take format string argument. If it is present, output it after the @, followed by a colon, to reproduce the read notation. (out_quasi_str): Pass down the format string, taken from the fourth element of a sys:var item of the quasiliteral. For simple symbolic items, pass down nil. * match.c (tx_subst_vars): Pass nil as new argument of format_field. The output variables of the TXR Pattern language do not exhibit this feature. * parser.l (FMT): New pattern for matching the format string part. (grammar): The rule which recognizes @ in quasiliterals optionally scans the format notation, and turns it into a string attached to the token's semantic value, which is now of type val (see parser.y remarks). * parser.y (tokens): The '@' token's %type changed from lineno to val so it can carry the format string. (q_var): If format string is present in the @ symbol, then include it as the fourth element of the sys:var form. This rule handles braced items. (meta): We can no longer get the line number from the @ item, so we get it from n_expr. (quasi_item): Similar to q_var change here. This handles @ followed by unbraced items: symbols and other expressions. * stdlib/compiler.tl (expand-quasi-mods): Take format string argument. When the format string is present, then generate code which uses the new alternative run-time support functions, and passes them the format string as an argument. (expand-quasi-args): Extend the sys:var match to extract the format string if it is present. Pass it down to expand-quasi-mods. * stdlib/match.tl (expand-quasi-match): Add an error case diagnosing the situation when the program tries to use a format-conversion-endowed item in a quasilit pattern. * stream.[ch] (fmt1): New function. * tests/012/quasi.tl: New tests. * txr.1: Documented. * lex.yy.c.shipped, y.tab.c.shipped: Regenerated.
* compiler: improvements in reporting form in diagnostics.Kaz Kylheku2025-05-091-5/+19
| | | | | | | | | | | | | | | | | | | | * eval.c (ctx_name): Do not report just the car of the form. If the form starts with three symbols, list those; if two, list those. * stdlib/compiler.tl (expand-defun): Set the defun form as the macro ancestor of the lambda, rather than propagating source location info. Then diagnostics that previously refer to a lambda will correctly refer to the defun and thank to the above change in eval.c, include its name. * stdlib/pmac.t (define-param-expander): A similar change here. We make the define-param-expander form the macro ancestor of the lambda, so that diagnostics agains tthe lambda will show that form.
* flet/labels: generate macro ancestor form,Kaz Kylheku2025-05-091-0/+4
| | | | | | | | | * eval.c (me_flet_labels): Create a synthetic macro ancestor form which is (labels <name>) or (flet <name>) so the function name, location and type of binding can be traced from the lambda expression. This will be useful to the :trace parameter macro that is coming.
* args: type check uses of dargs in places.Kaz Kylheku2025-05-071-3/+3
| | | | | | | | | | | | | | The DARG object type (dynamic args) is used in a few places. It has no safe accessors that do type checks and is directly accessed for efficiency. We need some modicum of safety when is is planted into the environment of functions, because those are mutable. * eval.c (do_args_apf, do_args_ipf, do_callf): type check the dargs object from the function to be DARG before accessing it. * struct.c (method_args_fun, umethod_args_fun): Likewise.
* New function: progf.Kaz Kylheku2025-05-021-0/+23
| | | | | | | | | * eval.c (do_progf, progf): New static functions. (eva_init): Register progf intrinsic. * tests/012/callable.tl: New test. * txr.1: Documented.
* callf, juxt: rewrite.Kaz Kylheku2025-05-021-4/+27
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | * lib.[ch] (do_juxt, juxtv): Functions removed. * eval.c (do_callf): New static function. Implements callf without consing up an argument list with juxt which is then applied to the function. It's all done with a loop which builds args on the stack. (callf): Rewritten to use do_callf. We have to convert the function list to dynamic args, but that is more compact than all the consing done by the removed juxt implementation. (juxt): New static function: implemented trivially using callf and list_f. (eval_init): Change registration from removed juxtv to juxt. Going forward, I won't be using the v suffix on functions. That should only be used when two versions of a function exist: one which takes vargs, and one which takes C variable arguments or something else like a list. Example: format is a variadic C function with a ... in its argument list. formatv takes a varg and is the main implementation. vformat takes a va_list. Leading v is the standard C convention, like vsprintf. trailing v is the TXR convention for a function that takes vargs, but only if it is an alternative to one which doesn't.
* expander: noexpand mechanism.Kaz Kylheku2025-04-191-1/+10
| | | | | | | | | | | | | * eval.c (noexpand_s): New symbol variable, holding sys:noexpand symbol. (do_expand): When a (sys:noexpand X) form is seen, then produce the expansion X without recursing into it; in other words, sys:noexpand is like quote, but against expansion. (noexpand): Static function. (eval_init): Initialize noexpand_s. Register noexpand as intrinsic function. * txr.1: Document noexpand function.
* Rebind *expand-hook* in load and compile-file.Kaz Kylheku2025-04-171-0/+1
| | | | | | | | | | | | * eval.c (loadv): Rebind *expand-hook* to its current value, like we do with *package*. * match.c (v_load): Likewise. * stdlib/compiler.tl (compile-file-conditionally): Likewise. * txr.1: Documented.
* special-operator-p: don't report error entries as t.Kaz Kylheku2025-04-141-1/+15
| | | | | | | | | | | * eval.c (special_operator_p): Do not return t for certain symbols that are wired to error-throwing functions in the table, whose purpose it is to detect certain unexpanded syntax that is handled internally by the expander. * txr.1: Documentation udpated in several places to clarify that certain operators are not special operators. Also expander-let is reclassified from Macro to Ooerator.
* expander-let: rewrite in C.Kaz Kylheku2025-04-141-1/+35
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The expander-let mechanism wants to be more tightly integrated into the expander than a macro. The reason is that the macro makes an explicit call to the expander. But the expansion it returns will be processed again by the expander. In the tightly integrated expander-let, we can avoid this; the expander can assume that the function which processes expander-let completely processes it and consequently can be tail called. All in all, since the expander is written in C, a utility which is this close to the heart of the expander should be implemented together with it in C. * eval.c (expander_let_s): New symbol variable. (expand_expander_let): New function. (do_expand): Tail call expand_expander_let when encountering a form headed by the expander-let symbol. (eval_init): Initialize expander_let_s variable with interned symbol. Also wire it into the special op table as an error entry, similarly to macrolet and a few others. * autoload.c (expander_let_set_entries, expander_let_instantiate): Static functions removed. (autoload_init): Autoload registration for expander-let module removed. * stdlib/expander-let.tl: File removed. Also, it should be noted that the the expander-let macro in this file has a a tiny bug: it refers to a sys:dv-bind symbol which should have been sys:dvbind. That means it is evaluating the (sys:dvbind ...) forms, which means it binds special variables twice: once in that evaluation, and then again in progv.
* expand-hook: implement in macroexpand-1.Kaz Kylheku2025-04-081-8/+35
| | | | | | | | | | | | | | | | | | | When expanding a form with macroexpand-1 or macroexpand, and an expand hook is in effect, we must call the hook. Otherwise macrology that relies on macroexpand or macroexpand-1 might not work with expander-driven syntax. I'm running into not being able to, for instance, use the swap macro on a pair of infix expressions because of this. macroexpand-1 must behave like the real macro expander. eval.c (do_macroexpand_1): After looking up whether the form is a macro, pass it through the hook if it is defined. If the hook transforms the code, then iterate on this. We pass the form through the expand hook even if it is not a macro call, and classify it based on whether is a function call, dwim brackets form or other, careful not to pass down special operators.
* expand-hook: process DWIM brackets forms.Kaz Kylheku2025-04-081-5/+15
| | | | | | | | | | | It turns out we need this for infix. * eval.c (do_expand): Call the expand hook for forms headed by the dwim operator, passing that operator symbol as the type indicator. * txr.1: Document this and also that the expand hook doesn't receive symbol macros.
* expand-hook: don't process symbol macros.Kaz Kylheku2025-04-081-10/+0
| | | | | | | | | | There isn't an obvious use for calling the expander hook for symbolic forms that are macros. (Especially while not calling it for symbolic forms that are not macros.) * eval.c (do_expand): Do not call the expand hook for symbol macro forms.
* expander: expand arguments after hook processing.Kaz Kylheku2025-04-021-14/+16
| | | | | | | | | | | | * eval.c (do_expand): Do not expand the arguments of a function call prior to checking for and dispatching the expand hook. The expand hook may rewrite the entire form and the arguments, so that those expansions are then thrown away. Not only is it wasteful to calculate them but possibly wrong. A form that is rewritten by a hook may have strange syntax, such that the hook itself will get confused if it is unleashed recursively on the constituent fragments of the syntax.
* expand-hook-combine: bugfix.Kaz Kylheku2025-04-011-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | | Here we fix bugs in expand-hook-combine, imrprove the tests and make different recommendations in the manual about hook order. * eval.c (expand_hook_combine_fun): Fix incorrect tests which cause the next function to be ignored. * tests/011/exphook.tl: (pico-style-expand-hook): Needs tweak to evaluate constantp using standard expansion (without pico-style), so that pico-style can nest with ifx in either order. (pico-style): Now when we call expand-hook-combine we give the new hook first, and the existing one next. This behavior makes more sense as a default go-to strategy because it gives priority to the innermost hook-based macro, closest to the code. (infix-expand-hook, ifx): Add test cases which test nesting of hook-based macros. * txr.1: Opposite recommendation made about chaining of expand hooks: new first, fall back on old. Example adjusted.
* constantp: muffle all expander warnings.Kaz Kylheku2025-04-011-2/+13
| | | | | | | | | | | | | | This fixes nuisance diagnostics from constantp, such as when invalid forms are given. An example is (constantp '(1)). * eval.c (no_ub_warn_expand): New name for previous no_warn_expand function. (no_warn_expand): Rewritten to muffle all warnings, and call no_ub_warn_expand. The constantp function continues to call no_warn_expand. (eval_init): Retarget expand intrinsic to no_ub_warn_expand, to preserve its documented behavior. The only function which currently uses no_warn_expand is constantp.
* New function: expand-hook-combine.Kaz Kylheku2025-04-011-0/+25
| | | | | | | | | | | | | This function provides a functional combinator that takes the responsibility of combining expand hooks. * eval.c (expand_hook_combine_fun, expand_hook_combine): New static functions. (eval_init): Register expand-hook-combine intrinsic. * tests/011/exphook.tl: New file. * txr.1: Documented.
* New feature: *expand-hook*.Kaz Kylheku2025-03-311-1/+44
| | | | | | | | | | | | | | * eval.c (expand_hook_s): New symbol variable. (do_expand): Check for expand hook in several places and call it: symbol macros, macros, functions, and forms that not confirmed function calls. (eval_init): Initialize new symbol, and register the *expand-hook* special variable. * eval.h (expand_hook_s): Declared. (expand_hook): New macro. * txr.1: Documented.
* New function keep: generalized keepqual.Kaz Kylheku2025-03-281-0/+1
| | | | | | | | | | | * eval.c (eval_init): Register keep intrinsic. * lib.[ch] (keep): New function. * stdlib/compiler.tl (compiler comp-fun-form): Transform two argument keep to keepqual. * txr.1: Documented.
* New function: remove.Kaz Kylheku2025-03-271-0/+1
| | | | | | | | | | | | | | | We need a remove function that doesn't have an equality suffix, analogous to member, pos, count. * eval.c (eval_init): Register remove intrinsic. * lib.[ch] (remov): New function. Named this way to avoid clashing with the ISO C remove function in <stdlib.h>. * tests/012/seq.tl: New tests. * txr.1: Documented.
* case synonyms for more readable case macros.Kaz Kylheku2025-03-241-3/+9
| | | | | | | | | | | | | | | | There is a general trend in TXR Lisp to use a nice name for the variant of a function which uses equal equality. With the case macros, we have to use casequal, ecasequal, ecasequal or ecasequal*. Let's introduce synonyms for these: case, case*, ecase and ecase*. * eval.c (case_s, case_star_s): New symbol variables. (me_case): Check for case_star_s also to determine whether we have a "star" macro. (eval_init): Initialize symbol variables, and register case, case*, ecase and ecase* intrinsics. * txr.1: Documented.
* New macro: letrec.Kaz Kylheku2025-03-211-0/+44
| | | | | | | | | * eval.c (me_letrec): New function. (eval_init): Register letrec intrinsic macro. * tests/012/let.tl: New file. * txr.1: Documented, and also referenced from mlet.
* New function: iterp.Kaz Kylheku2025-03-071-0/+1
| | | | | | | | | | | | | | | | | * eval.c (eval_init): Register iterp intrinsic. * lib.[ch] (iterp): New function. * tests/012/iter.tl: New tests. * txr.1: Document iterp. Update documentation for iter-more, iter-item and iter-step to more precisely identify which objects are valid arguments in terms of iterp and additional conditions, and that other objects throw a type-error exception. Fix wrong references to iter-more under documentation for iter-item. Removed obsolete text specifying that iter-step uses car on list-like sequences, a dubious behavior removed in the previous commit.
* Copyright year bump 2025.Kaz Kylheku2025-01-011-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * 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, lex.yy.c.shipped, lib.c, lib.h, linenoise/linenoise.c, linenoise/linenoise.h, match.c, match.h, parser.c, parser.h, parser.l, parser.y, protsym.c, 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/comp-opts.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 bumped to 2025.
* lib: fix g++ warning in map_common.Kaz Kylheku2024-12-111-1/+1
| | | | * eval.c (map_common): use the all_zero_init macro, defined
* mapcar: introduce map as a synonym.Kaz Kylheku2024-08-141-1/+6
| | | | | | | * eval.c (eval_init): Bind new map symbol to the same function as mapcar. * txr.1: Documented.
* keep-if, remove-if, keep-keys-if: mapfun argument.Kaz Kylheku2024-07-301-3/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | We introduce a mapfun argument to these functions so that they can additionally transform the accumulated values. The keep-keys-if function is now implemented through the same helper function as keep-if but with the mapfun argument defaulting to a copy of the keyfun argument. * eval.c (eval_init): Update registrations of remove-if, keep-if and keep-keys-if to new arities of C functions. * lib.c (rem_if_impl): Implement new optional mapfun parameter. (remove_if, keep_if): Add mapfun parameter. (keep_keys_if): Implement via rem_if_impl, and add mapfun argument. We do the defaulting of keyfun here, so that we can then use that argument's value to default mapfun. * lib.h (remove_if, keep_if, keep_keys_if): Declarations updated. * tests/012/seq.tl: Couple of test cases exercising mapfun argument of keep-if and remove-if. * txr.1: Documented.
* lib: get rid of internal rewindable iter nonsense.Kaz Kylheku2024-07-251-1/+1
| | | | | | | | | | | | | | | | | | | | Iterator rewinding is only used by the three functions isec, isecp and diff, which can easily just re-initialize the iterator. * lib.c (seq_iter_rewind): Static function removed. (seq_iter_init_with_info): Remove support_rewind argument, and adjust all code referencing it on the assumption that it's zero. (seq_iter_init_with_rewind): Static function removed. (seq_iter_init, iter_begin, iter_reset, nullify, find, rfind): Drop last argument from seq_iter_init_with_info. (diff, isec, iescp): Use seq_iter_init rather than seq_iter_init_with_rewind. Instead of seq_iter_rewind, just reinitialize the iterator. * lib.h (seq_iter_init_with_info): Declaration updated. * eval.c (tprint): Drop last argument from seq_iter_init_with_info.
* zip: more permissive implementation.Kaz Kylheku2024-07-241-9/+11
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | zip and transpose should allow non-character data when the leftmost column is a string, falling back on making lists, like seq_build. We can't use seq_build as-is because of the special semantics of transpose/zip with regard to strings. We introduce a "strcat" variant of seq_build for this purpose. * lib.c (seq_build_strcat_add): New static function. (sb_strcat_ops): New static structure like sb_str_ops, but with seq_build_strcat_add as the add operation, which allows string arguments to be appended to the string rather than switching to a list. (seq_build_strcat_init): New function. * lib.h (seq_build_strcat_init): Declared. * eval.c (zip_strcat): New static function; uses seq_build_strcat_init. (zipv): Only recognize strings specially; all else goes through the existing default case. Strings use zip_strcat. * tests/012/seq.tl: New test case. * txr.1: Describe special semantics of zip/tranpose; previously only documented in one example. Clarify that the rows are only sequences of the same kind as the leftmost column if possible, otherwise lists. Remove text which says that it's an error for the other columns to contain non-string, non-character objects if the leftmost column is a string.
* New function: seq-like.Kaz Kylheku2024-07-231-2/+3
| | | | | | | | | | | | * eval.c (zip_fun): Renamed to seq_like. (zipv): Follow rename of zip_fun. (eval_init): Register seq-like intrinsic. * tests/seq.tl: Some tests for make-like and seq-like, revealing a difference: make-like needs to be rewritten to use seq_build. * txr.1: Documented.
* New functions: find-maxes and find-mins.Kaz Kylheku2024-07-161-0/+2
| | | | | | | | | | | * eval.c (eval_init): New intrinsic functions find-maxes and find-mins. * lib.[ch] (find_maxes, find_mins): New function. * tests/012/seq.tl: New tests. * txr.1: Documented.
* New funtion related to where function.Kaz Kylheku2024-07-111-0/+4
| | | | | | | | | | | | | | * eval.c (eval_init): register intrinsics wheref, whereq, whereql and wherequal. * lib.c (wheref_fun): New static function. (wheref, whereq, whereql, wherequal): New functions. * lib.h (wheref, whereq, whereql, wherequal): Declared. * tests/012/seq.tl: New tests. * txr.1: Documented.
* New functions: cshuffle and cnshuffle.Kaz Kylheku2024-07-011-0/+2
| | | | | | | | | | | | | | | | | | | These functions find random cyclic permutations. * eval.c (eval_init): Register cshuffle and cnshuffle intrinsics. * lib.c (nshuffle_impl): New static function, formed out of nshuffle. (nhuffle): Now wrapper around nshuffle_impl. (shuffle): Also wraps nshuffle_impl rather than nshuffle. (cnshuffle, cshuffle): New funtions. * lib.h (cnshuffle, cshuffle): Declared. * txr.1: Documented new functions. Also added warning about limitations on permutation reachability in relation to PRNG state size.
* combi: fix permi and rpermi; impl combi, rcombi; test.Kaz Kylheku2024-06-241-0/+2
| | | | | | | | | | | | | | | | | | | | | | | | | * combi.c (permi_get, permi_peek): Fix algorithm. (permi_mark): New static function. (permi_ops): Reference permi_mark for mark operation. (permi): Initialize it->ul.next to nao as required by new get/peek algorithm. (rpermi_get, rpermi_peek): Fix algorithm. (rpermi_mark): New static function. (rpermi_ops): Reference permi_mark for mark operation. (rpermi): Initialize it->ul.next to nao as required by new get/peek algorithm. (combi_get, combi_peek, combi_mark, combi_clone): New static functions. (combi_ops): New static structure. (combi): New function. (rcombi_get, rcombi_peek, rcombi_mark, rcombi_clone): New static functions. (rcombi_ops): New static structure. (rcombi): New function. * combi.h (combi, rcombi): Declared. * tests/015/comb.tl: New tests.
* New rpermi: iterator version of rpermKaz Kylheku2024-06-191-0/+1
| | | | | | | | | | | * combi.c (rpermi_get, rpermi_peek, rpermi_clone): New static functions. (rpermi_ops): New static structure. (rpermi): New function. * combi.h (rpermi): Declared. * eval.c (eval_init): Register rpermi intrinsic.
* New function: copy-iter.Kaz Kylheku2024-06-151-0/+1
| | | | | | * eval.c (eval_init): Register copy-iter intrinsic. * lib.[ch] (copy_iter): New function.
* New permi: iterator version of perm.Kaz Kylheku2024-06-151-0/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | * eval.c (eval_init): Register permi intrinsic. * combi.c (permi_get, permi_peek, permi_clone): New static functions. (permi_ops): New static structure. (permi_iter): New static function. (permi): New function. * combi.h (permi): Declared. * lib.h (struct seq_iter_ops): New function pointer, clone. (seq_iter_ops_init, seq_iter_ops_init_nomark): Initialize new member. (seq_iter_ops_init_clone): New macro. (seq_iter_cls): Existing external name declared. (seq_iter_cobj_ops, seq_iter_mark_op): Previously internal names declared external. * lib.c (seq_iter_mark_op, seq_iter_cobj_ops): Static variables become extern. (seq_iter_clone): New static function. (seq_iter_init_with_info): Use seq_iter_clone instead of assuming we can trivially clone an iterator state bitwise.
* bugfix: one missing case of fmt_cat separator defaulting.Kaz Kylheku2024-05-271-1/+1
| | | | | | | | | | In a recent commit, the defaulting of the separator in quasiliteral variable formatting was moved down into the fmt_cat routine. One stray case remains in subst_vars. * eval.c (subst_vars): A call to fmt_cat is specifying a separator value consisting of a single space. This is wrong, preventing fmt_cat from defaulting it in different ways according to type.
* quasiliterals: buffers in hex, separation for strings and buffers.Kaz Kylheku2024-05-271-2/+6
| | | | | | In this commit, output variables in the TXR Pattern language and in TXR Lisp quasiliterals now support separator strings for values that are strings and buffers. Values which are buffers appear
* quasilit: move separator defaulting to fmt_cat.Kaz Kylheku2024-05-031-4/+5
| | | | | | | | | | | | | | | | | | | | | The motivation here is an upcoming change in which we will support the separator modifier for buffers and strings. Currently, it does nothing. If we write `@{a ":"}`, and a is a buffer or string, the separator is ignored. We don't fix that in this commit, but we fix the problem that some higher level formatting functions are defaulting the separator to " " (single space) and passing it down. We want to control the defaulting based on the type of the object in one place. * eval.c (fmt_cat): Do not assume here that sep has been defaulted; do the defaulting to space here. (format_field, fmt_flex): Initialize the separator to nil, not space. If no separator occurs among the modifiers, it gets passed down as nil through to fmt_cat. (fmt_simple): Don't default the sep argument to space; pass it through to do_format_field which will pass it down to fmt_cat.
* buf: pprint produces hex, not raw bytes.Kaz Kylheku2024-05-031-5/+14
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The pprint semantics of buffers is that the raw bytes are dumped into the stream. This is poor. It was hastily designed based on analogy with strings, which pprint by just sending their contents to the stream; but for strings this is justified because they represent text. We also fix the semantics of buffer values being rendered by quasiliteral notation. Currently, the are treated as sequences, and so they explode into individual decimal integers. * buf.c (buf_pprint): Print the bytes as pairs of lower-case hex digits, with no line breaks. In 294 compatibility or lower, put out bytes as before. * eval.c (fmt_cat): When not in 294 compatibility mode, treat a buffer object via tostringp, which will render it to hexadecimal via buf_pprintf. In compatibility mode, treat it as before, which is as a sequence: the individual values of the buffer are converted to text, thus decimal values in the range 0 to 255, catenated using the given separator. * tests/012/readprint.tl: New tests. * txr.1: Documented. Also expanding on what pretty printing means in TXR.
* New function: iter-cat.Kaz Kylheku2024-04-161-0/+1
| | | | | | | | | | | | | | | | * eval.c (eval_init): Register iter-cat intrinsic. * lib.h (struct seq_iter): New union member dargs. (iter_catv): Declared. * lib.c (seq_iter_get_cat, seq_iter_peek_cat): New static functions. (si_cat_ops): New static structure. (iter_catv): New function. * tests/012/iter.tl: New tests. * txr.1: Documented.
* New function: lcons-force.Kaz Kylheku2024-04-041-0/+1
| | | | | | | | * lib.[ch] (lcons_force): New function. * eval.c (eval_init): Register lcons-force intrinsic. * txr.1: Documented.
* New function: rangeref.Kaz Kylheku2024-03-071-0/+1
| | | | | | | | | | | | | | | | | | | | | Because ranges can be iterated like sequences, and are identified as vector-like, they have to support indexing. However, ranges already have semantics as a function: with a sequence argument, they slice it. Let's put the semantics into a function called rangeref, so it can be coherently documented. * eval.c (eval_init): Register rangeref intrinsic. * lib.c (generic_funcall): Range as a function works in terms of rangeref. (ref): Handle RNG case via rangeref. (rangeref): New function. * lib.h (rangeref): Declared. * tests/012/seq.tl: New tests.
* mapcar: avoid alloca proportional to number of args.Kaz Kylheku2024-03-011-2/+16
| | | | | | | | | | | | | | | * eval.c (MAP_ALLOCA_LIMIT): New preprocessor symbol. (map_common): If the number of args is greater than MAP_ALLOCA_LIMIT, then allocate the array of seq_iter_t structures from chk_malloc rather than alloca. In case an exception might be thrown during the execution of this function, we bind that memory to a buf object. If we return normally, we call the new function buf_free to release it. Otherwise we rely on the garbage collector. * buf.[ch] (buf_free): New function. * tests/012/seq.tl: Test case which hits this behavior.
* zip: make more generic.Kaz Kylheku2024-03-011-7/+54
| | | | | | | | | | | | | | | | * lib.c (do_pa_12_1_v, pa_12_1_v): Static functions removed. (transposev, transpose): Functions removed. * lib.c (transposev, transpose): Declarations removed. * eval.c (join_f): New global variable. (zip_fun, zipv, transpose): New static functions. (eval_init): gc-protect join_f, and initialize it. Registration of zip intrinsic goes to zipv rather than transposev. sys:fmt-join and join registered with help of global join_f rather than local. * tests/012/seq.tl: New zip test cases.
* mapcar, mappend: switch to seq_build.Kaz Kylheku2024-02-271-6/+9
| | | | | | | | | | | | | | * lib.c (mapcar): Implement with seq_iter and seq_build, rather than relying on mapcar_listout and make_like. (mappend): Replace list_collect_decl and make_like with seq_build. * eval.c (map_common): Replace list_collect_decl and make_like with seq_build. The collect_fn is now a pointer to either seq_add or seq_pend rather than list_collect or list_collect_append. (mapcarv, mappendv): Pass seq_add and seq_pend to map_common, rather than list_collect and list_collect_append.
* New function: cons-count.Kaz Kylheku2024-02-091-0/+1
| | | | | | | | | | | | | * eval.c (eval_init): Register cons-count intrinsic. * lib.c (cons_count_rec): New static function. (cons_count): New function. * lib.h (cons_count): Declared. * tests/012/cons.tl: New tests. * txr.1: Documented.