summaryrefslogtreecommitdiffstats
path: root/stdlib
Commit message (Collapse)AuthorAgeFilesLines
...
* infix: phony infix for prefix funtion call expressions too.Kaz Kylheku2025-04-221-1/+7
| | | | | | | | | | | | | | * stdlib/infix.tl (infix-expand-hook): In addition to the phony infix rule which swaps a function from second to first place, and then transforms the arguments, if possible, we add a case which is essentially like the above, but with the leading argument before the function being absent: the expression begins with a function and has two or more arguments. If those arguments transform as infix, we take the result as one argument. Otherwise if no transformation takes place, we return the original expression. * txr.1: Documented.
* infix: support function power operators.Kaz Kylheku2025-04-211-2/+11
| | | | | | | | | | | | | | | | | | | | * infix.tl (ifx-oper): New slot, power. When we detect a prefix operator that is followed by a power symbol and operand, we clone the operator and store the operand here. (parse-infix): If the operator has the power slot, the add-local function, add an extra node for the exponentiation operation over the function result. When about to add a prefix operator to the operator stack, we check whether it is a function, and whether it is followed by ** and an operand. If so, we clone the operator and store the operand into the power slot then remoe those two arguments from the rest of the input; effectively, we recognize this as a phrase structure. (detect-infix): We need a couple of rules here to detect infix expressions which use function power operators. * txr.1: Document function power operators as well as the new auto-detection rules.
* infix: autodetection takes lexical functions into account.Kaz Kylheku2025-04-211-7/+10
| | | | | | | | | | * stdlib/infix.tl (funp): New macro. (detect-infix): Take environment argument and test with funp rather than fboundp. (infix-expand-hook): Pass environment to detect-infix. Also use funp in the phony infix argument test. * txr.1: Documented.
* infix: revise auto-detection algorithm.Kaz Kylheku2025-04-211-12/+20
| | | | | | | | | | | | | | | * stdlib/infix.tl (detect-infix): Redesign. New algorithm looks only at the first two or three elements. Arguments that are not operators are only considered operands if they don't have function bindings. This is important because sometimes the logic is applied to the arguments in a DWIM bracket form, like [apply / args], which we don't want to treat as (/ apply args). * tests/012/infix.tl: New test. * txr.1: Redocumented.
* infix: phony infix: try arguments as infix.Kaz Kylheku2025-04-211-1/+4
| | | | | | | | | | | | * stdlib/infix.tl (infix-expand-hook): In the phony infix logic that swaps the first two arguments, we also try the remaining arguments as a stand-alone expression, passing that through the hook. If the hook recognizes and transforms them as infix, we keep the result as one argument. Otherwise, we just take the original arguments. I already committed some test cases for this which are failing. * txr.1: Documented.
* op: reduce and mitigate multiple expansion.Kaz Kylheku2025-04-191-4/+6
| | | | | | | | | * stdlib/op.tl (sys:op-expand): Bind *expand-hook* to nil in several places so that the unavoidable multiple expansions we perform do not re-invoke hooks. Finally, when we interpolate the calculated lambda-interior into the output templates, we mark it noexpand since the material already underwent several expansions.
* 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.
* New: HMAC functions.Kaz Kylheku2025-04-161-0/+61
| | | | | | | | | | | | * autoload.c (hmac_set_entries, hmac_instantiate): New static functions. (autoload_init): Register autoload of hmac module. * stdlib/hmac.tl: New file. * tests/013/chksum.tl: New tests. * txr.1: Documented.
* expander-let: rewrite in C.Kaz Kylheku2025-04-141-44/+0
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* infix: revise auto-detection and parsing.Kaz Kylheku2025-04-091-9/+28
| | | | | | | | | | | | | | * stdlib/infix.tl (parse-infix): Change how we treat fn (arg ...) and elem [arg ...] forms. These now translate to (fn (arg ...)) and [elem (arg ...)] rather than (fn arg ...) and [elem arg ...]. (detect-infix): detect certain op [arg ...] forms as infix. (infix-expand-hook): Revise detection logic to handle bracket expression forms, and parenthesized single terms. The latter are needed to reduce [elem (atom)] to [elem atom]. * tests/012/infix.tl: Fix up some tests. * txr.1: Documented.
* infix: new operators, revise precedence.Kaz Kylheku2025-04-081-6/+69
| | | | | | | | | | | | | | | | * autoload.c (infix_set_entries): Intern new symbols ||, &&, !, !=, &=, |=, &&=, ||=, >>=, <<=, ~=, %=, *=, %=, <<, >>, &, |, ~, % and //. * stdlib/infix.tl: revise precedence of calculating assignment operators. Add shifts, bitwise operators, modulo, C-like synonyms for some operators, numerous new calculating assignments. (sys:mod-set, sys:and-set, sys:or-set, sys:logand-set, sys:logxor-set, sys:logior-set, sys:ash-set, sys:asr-set, sys:asr): New macros to provide the implementation of operation combinations that will only be available via infix.
* New macros: mul and div.Kaz Kylheku2025-04-081-0/+8
| | | | | | | | | * autoload.c (place_set_entries): Add mul and div symbols as autoload triggers. * stdlib/place.tl (mul, div): New macros. * txr.1: Documented.
* place: move set-mask, get-mask out of defset.Kaz Kylheku2025-04-072-8/+8
| | | | | | | | | | * autoload.c (place_set_entries, defset_set_entries): Move the set-mask and clear-mask symbols from def_set_entries to place_set_entries. * stdlib/defset.tl (set-mask, clear-mask): Functions removed from here. * stdlib/place.tl (set-mask, clear-mask): Functions moved here.
* infix: remove unnecessary rewrite ruleKaz Kylheku2025-04-061-2/+0
| | | | | | | * stdlib/infix.tl (parse-infix): We don't need to recognize consecutive [...][...], because the rule which reduces any element followed by [...] does the job.
* infix: revise auto-detection.Kaz Kylheku2025-04-051-17/+20
| | | | | | | | | | | * stdlib/infix.tl (parse-infix): Drop usr: package prefix; autoload.c interns this symbol in the usr package. (detect-infix): New function, whose single responsibility is determining whether the argument expression should be treated via parse-infix. (infix-expand-hook): Simplified by using detect-infix function.
* infix: whitespace fix.Kaz Kylheku2025-04-051-1/+1
| | | | | * stdlib/infix.tl (infix-error): Remove trailing whitespace.
* infix: define = operator mapping to identityKaz Kylheku2025-04-051-0/+2
| | | | | | | | * stdlib/infix.tl (toplevel): New prefix operator = at 0 precedence. This is useful for specifying an infix formula that is not being autodetected by ifx nicely. For instance an expression containing only array references can be obtained as (= a[i][j]).
* infix: dynamic precedence algorithmKaz Kylheku2025-04-041-3/+8
| | | | | | | | | | | | | | | | | | | | | We implement a dynamic precedence algorithm whereby when an infix operator is immediately followed by a clump of one or more consecutive prefix operators, the infix operator's precedence is lowered to one less than the lowest one of the prefix operators. This creates nice handling for situations like (sqrt x + y - sqrt z + w) whose visual symmetry parses into (- (sqrt (+ x y)) (sqrt (+ z w))) rather than subordinating the second sqrt to the first one. * stdlib/infix.tl (parse-infix): Before processing an infix operator, calculate the prefix of the rest of the input that consists of nothing but consecutive prefix operators, and if it is nonempty, then use it to adjust the effective precedence used for the infix operator. This algorithm must only ever lower the precedence, never raise it.
* infix: assignment must be right associativeKaz Kylheku2025-04-041-1/+1
| | | | | | * stdlib/infix.tl (toplevel): The := operator must be assoc :right so a := b := c becomes (set a (set b c)) and not (set (set a b) c).
* infix: adjust operator expected diagnostic.Kaz Kylheku2025-04-041-1/+1
| | | | | | | | | * stdlib/infix.tl (parse-infix): The operator expected diagnostic can occur not just before an an operand, but before an prefix operator. For instance "a cos b". An operator is expected between a and cos. We don't want to say "before operand cos" because cos is an operator.
* Initial implementation of infix expressions.Kaz Kylheku2025-04-031-0/+174
| | | | | | | | | | | | | | | | The infix module provides a macro called ifx. Forms (evaluated expressions) enclosed inside ifx at any nesting level, which are not special operator or macro forms, are subject to automatic detection of an infix notation, which is transformed into regular Lisp. The notation is based on Lisp atoms; no read syntax is introduced. Infix may be freely mixed with ordinary Lisp. * autoload.c (infix_set_entries, infix_instantiate): New static functions. (autoload_init): Register new infix module for autoload. * stdlib/infix.tl: New file.
* match: new pattern matching macro, match-tuple-case.Kaz Kylheku2025-04-011-0/+3
| | | | | | | | | | | | | * autolod.c (match_set_entries): Autoload match module on match-tuple-case. * match.tl (match-tuple-case): New macro. * tests/011/patmatch.tl: New tests. The macro is trivial; if lambda-match works, the macro works. * 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.
* compiler: reduce some equal-based sequence functions.Kaz Kylheku2025-03-281-0/+5
| | | | | | | | | | | | | | | * stdlib/compiler.tl (compiler comp-fun-form): Recognize two-argument forms of remove, count, pos, member and subst. When these don't specify test, key or map functions, they are equivalent to remqual, countqual, posqual, memqual and subqual. These functions are a bit faster because they have no arguments to default and some of their C implementations call the equal function either directly or via a pointer, rather than via going via funcall. The exceptions are posqual and subqual which actually call pos; but even for these it is still slightly advantageous to convert to to the fixed arity function, because funcall2 doesn't have to default the optional arguments with colon_k.
* place: fix bad indentation.Kaz Kylheku2025-03-111-4/+4
| | | | | | * stdlib/place.tl (sys:placelet-1): Fix a misindented call-update-expander function call. Also indent its arguments in function style.
* Expose brace expansion bexp function.Kaz Kylheku2025-03-091-2/+2
| | | | | | | | | | | | | | | | | * autoload.c (glob_set_entries): Remove autoload on sys:brace-expand. Add usr:exp. * stdlib/glob.tl (brace-expand): Renamed to usr:bexp. (glob*): Call bexp rather than brace-expand. * tests/018/glob.tl: Rename references to sys:brace expand to bexp. * txr.1: Add section describing the bexp function. Move brace expansion documentation from glob* to this new section, adjusting the wording a little bit, mainly to avoid referring to "patterns". Point glob* documentation to bexp, which also in turn references glob*.
* glob*: add string and integer ranges to brace expansion.Kaz Kylheku2025-03-081-11/+45
| | | | | | | | | | | | | | | | * stdlb/glob.tl (bexp-parse): Recognize .. as a token. (bexp-parse-brace): If a brace expansion doesn't contain commas, then check whether it contains .. and that its elements are all strings. In that case it is a possible range expansion and we thus transform it to a (- ...) node, subject to more validation in bexp-expand. (bexp-expand): Add casees to handle range expansion, taking care that invalid forms translate to verbatim syntax. * tests/018/glob.tl: New tests. * txr.1: Documented.
* Version 299.txr-299Kaz Kylheku2025-02-161-1/+1
| | | | | | | | | | | | * RELNOTES: Updated. * configure (txr_ver): Bumped version. * stdlib/ver.tl (lib-version): Bumped. * txr.1: Bumped version and date. * txr.vim, tl.vim: Regenerated.
* awk: add CSV support.Kaz Kylheku2025-01-301-0/+8
| | | | | | | | | | | * stdlib/awk (awk-state upd-rec-to-f): Handle a new case of fs being the keyword symbol :csv, producing a field-splitting lambda that calls get-csv. * tests/015/awk-basic.tl: Several new test cases for this CSV feature. * txr.1: Documented.
* awk: use prepared lambdas for field separation.Kaz Kylheku2025-01-281-64/+79
| | | | | | | | | | | | | | | | | | | | | | | | | | | | Handle field separations with lambdas, similarly to record separation. The idea is that we replace the rec-to-f method, which contains a cond statement checking the variables for which field separation discipline applies, with a lambda which is updated whenever any of those ariables change. * awk.tl (awk-state): New instance slot, rec-to-f. (awk-state :postinit): Call new upd-rec-to-f method so that rec-to-f is populated with the default field separating lambda. (awk-state rec-to-f): Method removed. (awk-state upd-rec-to-f): New method, based on rec-to-f. This doesn't perform the field separation, but returns a lambda which will perform it. (awk-state loop): We must call upd-rec-to-f whenever we change par-mode, because it influences field separation. (awk-mac-let): Replace the symbol macros fs, ft, fw and kfs with new implementations that use the reactive slot mechanism provided by rslot. Whenever the awk macro assigns any of these, the upd-rec-to-f method will be called. * tests/015/awk-basic.tl: New file. These basic tests of field separation pass before and after this change. * tests/common.tl (otest, motest): New macros.
* get-csv: rewrite in C.Kaz Kylheku2025-01-211-74/+0
| | | | | | | | | | | | | | * autload.c (csv_set_entries, csv_instantiate): Functions removed. (autoload_init): Autoload registration for stdlib/csv removed. * stdlib/csv.tl: File removed. * stream.c (get_csv): New function. (stream_init): Register get-csv intrinsic. * stream.h (get_csv): Declared.
* get-csv: use symbols for states.Kaz Kylheku2025-01-211-45/+44
| | | | | | * csv.tl (get-csv): Since there are only three states, there is no jump table optimization. We might as well use keyword symbols for the states rather than integers.
* get-csv: simplify implementation by CR-LF folding.Kaz Kylheku2025-01-211-30/+7
| | | | | | | | | * stdlib/csv.tl (get-csv): Pre-process the input by a small state machine that maps CR-LF sequences to LF. Then we don't have to recognize #\return anywhere in the state machine and can delete the cr and qcr states, as well as all the code recognizing #\return and branching to those states.
* New function: get-csv.Kaz Kylheku2025-01-211-0/+98
| | | | | | | | | | | | | * autloload.c (csv_set_entries, csv_instantiate): New static funtions. (autoload_init): Register autoload of stdlib/csv module via new functions. * stdlib/csv.tl: New file. * tests/010/csv.tl: Likewise. * txr.1: Documented.
* New macros for enumerated constants.Kaz Kylheku2025-01-201-0/+46
| | | | | | | | | | | | | * autoload.c (enum_set_entries, enum_instantiate): New static functions. (autoload_init): Register autoload of stdlib/enum module via new functions. * stdlib/enum.tl: New file. * tests/016/enum.tl: Likewise. * txr.1: Documented.
* lflow/lopip: optimize one argument situations via lop1.Kaz Kylheku2025-01-171-21/+25
| | | | | | | | | | | | | | | | | | | | | | | In an opip pipeline, only the first pipeline element can receive multiple arguments. The subsequent elements receive the single return value from the previous element. Therefore if it is a left-inserting pipeline created by lopip, only the first element needs to use lop. The others can use lop1, resulting in an optimization. Furthermore in the flow/lflow macros, even the first function in the pipeline is called with one argument: the result of the input expression. So the case of lflow, every element of the pipe that would translate to lop can go to lop1 instead. * stdlib/opt.tl (sys:opip-expand): Calculate a local variable called opsym-rest which determines which op symbol we use for the recursive call. This is the same as the incoming opsym, except in the case when opsym is lop, in which case we substitute lop1. (sys:lopip1): New macro, like lopip but uses lop1 for the first element also. (lflow): Expand to sys:lopip1 rather than lopip.
* New macro: lop1.Kaz Kylheku2025-01-171-1/+11
| | | | | | | | | | | | | * autoload.c (op_set_entries): Autoload on lop1 symbol. * stldlib/op.tl (sys:op-expand): Add lop1 case. (sys:opip-expand): Add lop1 to the list of operators that are recgonized and specially treated. (lop1): New macro. * tests/012/op.tl: New tests. * txr.1: Documented.
* lop: don't insert args when metas present.Kaz Kylheku2025-01-081-4/+8
| | | | | | | | | | | | | | | | | | | | | The lop macro is inconsistent from op in that it inserts the trailing function arguments on the left even if arguments are explicitly given in the form via @1, @2, ... or @rest. This change makes lop is equivalent to op in all situations when these metas are given. * stdlib/op.tl (compat-225, compat-298): New top-level variables. (op-expand): local variable compat replaced by references to compat-225. If compat-298 is *not* in effect, then metas are checked for first in the cond, preventing the lop transformation from taking place. * tests/012/op.tl: Test cases for lop, combinations of do with lop and a few for op also. * txr.1: Redocumented, added compat notes.
* Copyright year bump 2025.Kaz Kylheku2025-01-0149-49/+49
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * 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.
* match-case: bugfix in conversion to casequal.Kaz Kylheku2024-12-201-2/+0
| | | | | | | | | | | | | * stdlib/match.tl (match-case-to-casequal): the (do inc dfl-cnt) action has a problem: it inserts an implicit extra parameter to the invocation of inc, which crashes the + addition due to that parameter being the matching @nil object. We don't need this entire case because it handles @nil, which also matches the following case for (sys:var ...), since @nil is (sys:var nil). That case ahs the same action of incrementing dfl-cnt. * tests/011/patmatch.tl: Test case added.
* Version 298.txr-298Kaz Kylheku2024-12-171-1/+1
| | | | | | | | | | * RELNOTES: Updated. * configure (txr_ver): Bumped version. * stdlib/ver.tl (lib-version): Bumped. * txr.1: Bumped version and date.
* Version 297.txr-297Kaz Kylheku2024-12-161-1/+1
| | | | | | | | | | | | * RELNOTES: Updated. * configure (txr_ver): Bumped version. * stdlib/ver.tl (lib-version): Bumped. * txr.1: Bumped version and date. * txr.vim, tl.vim: Regenerated.
* quips: jab at Weller.Kaz Kylheku2024-12-081-0/+1
| | | | * stdlib/quips.tl (%quips%): New one.
* quips: new one.Kaz Kylheku2024-09-031-0/+1
| | | | * stdlib/quips.tl (%quips%): New entry.
* Version 296.txr-296Kaz Kylheku2024-08-071-1/+1
| | | | | | | | | | | | | | * RELNOTES: Updated. * configure (txr_ver): Bumped version. * stdlib/ver.tl (lib-version): Bumped. * txr.1: Bumped version and date. * txr.vim, tl.vim: Regenerated. * protsym.c: Regenerated.
* struct: slot warning only for bindable symbols.Kaz Kylheku2024-07-171-1/+2
| | | | | | * stdlib/struct.tl (sys:check-slot): Don't issue the diagnostic "<obj> isn't the name of a struct slot" for slots that are not bindable symbols like obj."abc".
* Version 295.txr-295Kaz Kylheku2024-06-281-1/+1
| | | | | | | | | | | | | | * RELNOTES: Updated. * configure (txr_ver): Bumped version. * stdlib/ver.tl (lib-version): Bumped. * txr.1: Bumped version and date. * txr.vim, tl.vim: Regenerated. * protsym.c: Regenerated.
* match: new @(scan-all) operator.Kaz Kylheku2024-06-281-0/+28
| | | | | | | | | | | | | | | | This is like @(scan) but collects all matches over the suffixes of the list. * autoload.c (match_set_entries): Intern scan-all symbol. * stdlib/match.tl (compile-scan-all-match): New function. (compile-match): Dispatch compile-scan-all-match on scan-all symbol. * tests/011/patmatch.tl: Tests for scanall and also missing tests for scan. * txr.1: Documented.
* match: bad indentation.Kaz Kylheku2024-06-271-4/+4
| | | | | * stdlib/match.tl (compile-scan-match): Fix wrong indentation of let* body.
* quips: remove weak one.Kaz Kylheku2024-06-151-1/+0
| | | | | * stdlib/quips.tl (%quips%): Remove quip about lecithin; it does not wear well.