summaryrefslogtreecommitdiffstats
path: root/eval.c
Commit message (Collapse)AuthorAgeFilesLines
* 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.
* New function: cons-find.Kaz Kylheku2024-02-091-12/+1
| | | | | | | | | | | | | | | | | * eval.c (cons_find): Static function removed; a new one is implemented in lib.c. (eval_init): Register cons-find intrinsic. * lib.c (cons_find_rec): New static function. (cons_find): New function. * lib.h (cons_find): Declared. * tests/012/cons.tl: New file. * txr.1: Documented cons-find together with tree-find. Document that tree-find's test-fun argument is optional, defaulting to equal.
* New function: hist-sort-by.Kaz Kylheku2024-02-021-0/+1
| | | | | | | | | | | | | * 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.
* We need a length-< special method.Kaz Kylheku2024-01-191-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.