summaryrefslogtreecommitdiffstats
Commit message (Collapse)AuthorAgeFilesLines
...
* parser: recover stream data buffered by lexer.Kaz Kylheku2025-05-238-180/+509
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | After parsing out of a stream, we attach a shadow stream which temporarily patches the operations to make it appear that bytes that were taken into the lexer have been pushed back. This lets us call an ordinary input operation after a parsing operation to read the data immediately following the parsed-out construct. (Almost: there is still the issue of the parser consuming one token of lookahead in some situations.) * stream.h (struct strm_base): New member shadow_obj. This is a context pointer used by the shadow stream operations. (generic_fill_buf): Declare previously internal function. * stream.c (strm_base_init): Initialize shadow_obj to null. (generic_fill_buf): Function changed to external linkage. Also, reloads the ops pointer from the stream on each loop iteration. This is because it can change; part of the buffer may be filled by shadow_get_byte, which can detach the shadow operations, so then the rest of the buffer is filled by something else like stdio_get_byte. (generic_get_line): Reload ops in in the loop, like in gneric_fill_buf, for the same reason. * parser.l: Include <stddef.h> for ptrdiff_t. (scanner_has_buffered_bytes, scanner_get_buffered_bytes): New functions. * parser.c (SHADOW_TAB_SIZE): New preprocessor symbol. (shadow_tab): New static array. (struct shadow_context, struct shadow_ungetch): New struct types. (lisp_parse_impl): After calling parse, call parse_shadow_stream_attach to attach the shadow stream context and operations onto the stream. (shadow_detach, shadow_destroy_op, shadow_mark_op, shadow_put_string, shadow_put_char, shadow_put_byte, shadow_get_char_callback, shadow_get_char, shadow_unget_char_callback, shadow_unget_char, shadow_get_byte, shadow_unget_byte, shadow_put_buf, shadow_close, shadow_flush, shadow_seek, shadow_truncate): New static functions. (shadow_ops_template): New static structure. (customize_shad_ops): New static function. (parser_shadow_stream_attach): New function. (parser_free_all): New function. * parser.h (scanner_has_buffered_bytes, scanner_get_buffered_bytes, parser_shadow_stream_attach, parser_free_all): Declared. * txr.c (free_all): Call parser_free_all. * tests/018/streams.tl: New test cases. * lex.yy.c.shipped: Regenerated.
* streams: fix uninitialized last_op in stdio streams.Kaz Kylheku2025-05-231-6/+0
| | | | | | | | * stream.c (tail_strategy, make_stdio_stream_common): A recent change introduced this problem. Initialization of h->last_op must no longer be compile-time conditional on CONFIG_STDIO_STRICT, because it is used in non-strict mode also.
* streams: move utf8 decoder into strm_base.Kaz Kylheku2025-05-2314-30/+59
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This refactoring is required become some upcoming hack work is going to depend on the assumption that every stream object has a utf8_decoder_t. * utf8.h (utf8_decoder_initializer): New macro, used when initializing strm_base. * stream.h: Some of the content is now hidden unless the preprocessor symbol STREAM_IMPL is defined. This is motivated by the fact that stream.h now depends on utf8.h. When STREAM_IMPL is not defined, the bits that depend on utf8.h are disabled and we don't have to touch files which include "stream.h" which don't refer to those bits. (struct strm_base): New member ud, of type ut8_decoder_t. * stream.c: include "utf8.h" before "stream.h" and ensure STREAM_IMPL is defined. (strm_base_init): Initialize ud member of struct strm_buf using utf8_decoder_initializer. (struct stdio_handle, struct byte_input, struct string_out): Remove member ud. (stdio_switch, stdio_seek, stdio_get_char, stdio_get_byte, stdio_unget_byte, stdio_fill_buf, tail_strategy, byte_in_get_char string_out_byte_flush): Refer to new ud member in base. (make_stdio_stream_common, make_string_byte_input_stream, make_string_output_stream): No need to call utf8_decoder_init since strm_base_init takes care of it. * buf.c, gzio.c, hash.c, lib.c, parser.c, regex.c, socket.c, struct.c, strudel.c, syslog.c, tree.c: Move #include "utf8.h" above "stream.h", or in some cases add it. Define STREAM_IMPL before #include "stream.h".
* streams: get-char for string byte input streams.Kaz Kylheku2025-05-223-6/+109
| | | | | | | | | | | | | | | | | | | | | | | String byte input streams extended to provide characer input (get-char), and any mixture of unget-byte and unget-char. Also fill-buf is supported. * stream.c (struct byte_input): New ut8_decoder_t member ud. (struct byte_input_ungetch): New struct type. (byte_in_get_char_callback, byte_in_get_char, byte_in_unget_char_callback, byte_in_unget_char): New functions. (byte_in_ops): Wire in byte_in_get_char, byte_in_unget_char and byte_in_unget_byte. Also generic_fill_buf. (make_string_byte_input_stream): Initialize the UTF-8 decoder. * tests/018/streams.tl: New tests. * txr.1: Documented.
* streams: improve pushback semantics of stdio streams.Kaz Kylheku2025-05-225-28/+169
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * utf8.[ch] (utf8_getc, utf8_ungetc): New functions which allow the push-back buffer of the decoder to be accessed. We can use the decoder's push-back buffer to implement a stream's byte push-back, so that the behavior is then consistent: invalid bytes pushed back by the decoder are treated uniformly with bytes pushed back using unget-char. * stream.c (stdio_switch): Bugfix: reset the UTF8 decoder when changing direction. Without this, it is possible that pushed back bytes in the decoder's buffer will be read, even though write operations moved the position. Thus stdio_switch is now defined as a function regardless of whether CONFIG_STDIO_STRICT is in effect. (stdio_get_byte): If there are pushed back characters present, throw an error. Otherwise, try to get a byte from the UTF8 buffer's pushback first via utf8_getc. If that produces something, just return it. Otherwise fall back on reading from the stdio stream. (stdio_unget_byte): If there are pushed back characters present, throw an error. Otherwise push back the character using utf8_ungetc. If that reports no space, throw an error. (stdio_fill_buf): Take bytes from the push-back buffer int he UTF8 decoder first, then fread the rest from the stdio stream, if necessary.
* utf8: use unsigned int in decoder.Kaz Kylheku2025-05-221-2/+2
| | | | | | | | * utf8.h (utf8_decoder_t): Declare the flags member as well as the buffer indices head, tail and back as unsigned. Bitmask fields holding flags should be unsigned. Regarding the indices, we perform % 8 reductions on them in the decoder, which optimizes much better for unsigned types.
* vim: syntax highlighting for format strings in quasiliteral.Kaz Kylheku2025-05-191-1/+2
| | | | | * genvim.txr (fmt): New variable. (txr_quat): Match optional fmt after at.
* expander: handle format string in quasi.Kaz Kylheku2025-05-192-1/+11
| | | | | | | | * 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.
* parser: compounds not attributed with format string.Kaz Kylheku2025-05-192-2/+2
| | | | | | | | | * parser.y (quasi_item): In the @ n_expr case, we must generate the sys:var expression if the @ is carrying a format string, regardless of whether n_expr is an integer or symbol. * y.tab.c.shipped: Regenerated.
* doc: break up remove-if section.Kaz Kylheku2025-05-191-25/+34
| | | | | | | * txr.1: The remove and keep functions are missing from their section heading. Adding them in makes the heading overstuffed, so breaking it up. The separate function and the two lazy functions remove-if* and keep-if* go into their own sections.
* quasistrings: support format notation.Kaz Kylheku2025-05-1814-5111/+5550
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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: fix unidiomatic if/cond combination.Kaz Kylheku2025-05-171-13/+12
| | | | | | | * stdlib/compiler.tl (expand-quasi-mods): Fix unidiomatic if form which continues with a cond fallback. All I'm doing here is flattening (if a b (cond (c d) ...)) to (cond (a b) (c d) ...).
* math: consolidate some error reporting.Kaz Kylheku2025-05-161-35/+47
| | | | | | | | | | * arith.c (arg_type_error_1, arg_type_arror_2, arg_type_error_3): New static functions. (exptmod, isqrt, square, gcd, divides, logand, logior, logxor, logxor_old, logtest, lognot, logtrunc, ash, bit, bitset, logcount, width, poly, rpoly): Use one of these three functions to replace an ad-hoc throw.
* infix: add missing ~ complement operator.Kaz Kylheku2025-05-163-2/+8
| | | | | | | | | * stdlib/infix.tl (toplevel): New ~ operator, prefix at level 35, tied to lognot function. * tests/012/infix.tl: New tests. * txr.1: Documented.
* math: hook buf support into bit ops.Kaz Kylheku2025-05-162-12/+127
| | | | | | | | | | * arith.c (zerop, logand, logior, logxor, logtest, lognot, logtrunc, ash, bit, bitset, logcount, width): Add support for buffer arguments via the new bit manipulation functions provided by the buffer module. * txr.1: Documented.
* buf: buf-trunc: wrong self string.Kaz Kylheku2025-05-161-1/+1
| | | | | * buf.c (buf_trunc): Fix self string from buf-not to buf-trunc.
* arith: logtrunc: issues with short-circuiting to zero.Kaz Kylheku2025-05-161-6/+8
| | | | | | | | | * arith.c (logtrunc): Firstly, the correct condition for trivially returning zero is bits <= 0, not bits < 0. Secondly, we don't want to do this upfront. In the case we have a struct with user-defined arithmetic, the method must be called. It might return a different kind of zero.
* buf: bug: empty fill pattern.Kaz Kylheku2025-05-163-2/+15
| | | | | | | | | | * buf.c (prepare_pattern): Do not return a zero length pattern for an empty buffer. Callers don't deal with this properly. Return a one byte pattern that is zero. * test/012/buf.tl: Test case added. * txr.1: Documented.
* doc: buffers: section on arithmetic conventions.Kaz Kylheku2025-05-161-0/+22
| | | | * txr.1: Add Arithmetic Conventions of Buffer section.
* buf: make-buf and buf-set-length take pattern.Kaz Kylheku2025-05-163-56/+181
| | | | | | | | | | | | | The init-val parameter of make-buf and buf-set-length is generalized to a possibly multi-byte fill pattern. * buf.c (make_buf, buf_do_set_len): Change init-val parameter to init-pat, and implement. We optimize the to memset when it's a one-byte pattern. * tests/012/buf.tl: New tests. * txr.1: Documented.
* buf: move pattern preparation to function.Kaz Kylheku2025-05-161-45/+59
| | | | | | | * buf.c (prepare_pattern): New static function. (buf_xor_pattern): Use prepare_pattern to classify the pat parameter and prepare the pattern.
* parser: distinguish lambda dot token.Kaz Kylheku2025-05-153-7/+11
| | | | | | | | | | * parser.y (yybadtoken): Map the LAMBDOT token code to the name "lambda dot" to distinguish it from CONSDOT in error situations. * txr.1: Change the Consing Dot section to Lambda Dot. * y.tab.c.shipped: Regenerated.
* syntax: allow for multiline qref chaining.Kaz Kylheku2025-05-156-4805/+4891
| | | | | | | | | | | | | | | | | | | | | | | | Introducing a relaxation in the obj.slot.(method arg) syntax. There can be whitespace to the right of the dot, for splitting across multiple lines, as: obj. slot. (method arg) * parser.l (OREFDOT): Allow optional whitespace to the right of .? * parser.y (n_expr): Add a n_expr LAMBDOT n_expr phrase, with same semantic rule as n_expr '.' n_expr. We cannot add optional whitespace after . in the lexer because that is ambiguous with LAMBDOT. * tests/012/syntax.tl: New tewt cases. * txr.1: Documented. * lex.yy.c.shipped, y.tab.c.shipped: Regenerated.
* ffi: take advantage of string_utf8_from_buf.Kaz Kylheku2025-05-151-4/+2
| | | | | | * ffi.c (ffi_char_array_get, ffi_zchar_array_get): Use newly added string_utf8_from_buf rather than utf8_dup_from_buf followed by string_own.
* New string compression/decompression functions.Kaz Kylheku2025-05-155-1/+134
| | | | | | | | | | | | * buf.c (str_compress, str_decompress): New functions. (buf_init): str-compress, str-decompress intrinsics registered. * lib.[ch] (string_utf8_from_buf): New function. * tests/012/buf.tl: New tests. * txr.1: Documented.
* hmac: use buf-xor-pattern function.Kaz Kylheku2025-05-111-11/+9
| | | | | * stdlib/hmac.tl (hmac-impl): Eliminate xor loop by using buf-xor-pattern.
* New function: buf-xor-pattern.Kaz Kylheku2025-05-116-1/+170
| | | | | | | | | | | | | | * buf.c (buf_xor_pattern): New function. (buf_init): Register buf-xor-pattern intrinsic. * buf.h (buf_xor_pattern): Declared. * lib.[ch] (unsup_obj): Change function to external linkage and declare in header. * tests/012/buf.tl: New tests. * txr.1: Documented.
* match: make @(require) work over args in lambda-match.Kaz Kylheku2025-05-101-32/+40
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The issue is that in a lambda-match, when we wrap @(require) around an argument match, it becomes a single pattern which matches the variadic arguments as a list. As a result, the function also becomes variadic, and a list is consed up for the match. A nested list is worth a thousand words: Before this change: 1> (expand '(lambda-match (@(require (@a @b) (= 5 (+ a b))) (cons a b)))) (lambda (. #:rest0014) (let (#:result0015) (or (let* (a b) (let ((#:g0017 (list* #:rest0014))) (if (consp #:g0017) (let ((#:g0018 (car #:g0017)) (#:g0019 (cdr #:g0017))) (sys:setq a #:g0018) (if (consp #:g0019) (let ((#:g0020 (car #:g0019)) (#:g0021 (cdr #:g0019))) (sys:setq b #:g0020) (if (equal #:g0021 '()) (if (and (= 5 (+ a b))) (progn (sys:setq #:result0015 (cons a b)) t)))))))))) #:result0015)) After this change: 1> (expand '(lambda-match (@(require (@a @b) (= 5 (+ a b))) (cons a b)))) (lambda (#:arg-00015 #:arg-10016) (let (#:result0017) (or (let* (b a) (sys:setq b #:arg-10016) (sys:setq a #:arg-00015) (if (and (= 5 (+ a b))) (progn (sys:setq #:result0017 (cons a b)) t)))) #:result0017)) @(require (@a @b)) now leads to a two-argument function. The guard condition is applied to the a and b variables extracted from the arguments rather than a list. * stdlib/match.tl (when-exprs-match): Macro removed. (struct lambda-clause): New slot, require-conds. (parse-lambda-match-clause): Recognize @(require ...) syntax, destructure it and recurse into the argument pattern it contains. Because the incoming syntax includes the clause body, for the recursive call we synthesize syntax consisting of the pattern extracted from the @(require), coupled with the clause body. When the recursive call gives us a lambda-clause structure, we then add the require guard expressions to it. So in essence the behavior is that we parse the (@(require argpat cond ...) body) as if it were (argpat body), and decorate the object with the extracted conditions. (expand-lambda-match): This now takes an env argument due to the fact that when-exprs-match was removed. when-exprs-match relied on its :env parameter to get the environment, needed for compile-match. Now expand-lambda-match directly calls compile-match, doing all the work that when-exprs-match helper was doing. Integrating that into expand-lambda-match allows us to add logic to detect that the lambda-clause structure has require conditions, and add the code as a guard to the compiled match using add-guards-post. (lambda-match, defun-match, :match): Pass environment argument to expand-lambda-match.
* trace: need autoload on sys:*trace-level*.Kaz Kylheku2025-05-091-0/+5
| | | | | | | | * autoload.c (trace_set_entries): Add sys:*trace-level* symbol as autoload trigger. Compiled code which uses the :trace parameter macro references this variable (and some other internal trace symbols, but that one first).
* compiler: improvements in reporting form in diagnostics.Kaz Kylheku2025-05-093-13/+27
| | | | | | | | | | | | | | | | | | | | * 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.
* buf-count-ones: optimize for common cases.Kaz Kylheku2025-05-091-14/+31
| | | | | | | * buf.c (buf_count_ones): Short-circuit loop iteration if word or byte is zero. If the word/byte is a power of two (1 bit set) or if it has all bits set, then skip the bit trick.
* trace: new parameter macro :trace for simple static tracingKaz Kylheku2025-05-093-1/+76
| | | | | | | | | | | | Just add :trace to the head of the parameter list, and the function is traced. No dynamic turning on and off though. * autoload.c (trace_set_entries): Trigger autoload on :trace keyword. * stdlib/trace.tl (:trace): New parameter list expander. * txr.1: Documented.
* 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.
* dig: don't stop at form that has source location.Kaz Kylheku2025-05-091-2/+1
| | | | | | | | | | * stdlib/error.tl (sys:dig): Do not stop tracing the macro ancestry of a form upon finding source location info. This can be counterproductive because there are situations in which intermediate forms receive the info via rlcp or rlcp_tree. We would like to get to the form that actually exists in that file at that line number.
* autoload: load error module for sys:dig.Kaz Kylheku2025-05-091-1/+1
| | | | | | * autoload.c (error_set_entries): Add dig to system package names that trigger autoload of stdlib/error.
* quips; Unicode quip.Kaz Kylheku2025-05-081-0/+1
| | | | * stdlib/quips.tl (%quips%): New one about grapheme clusters.
* match: new macros in the "each" family.Kaz Kylheku2025-05-084-1/+250
| | | | | | | | | | | | | | | | | * autoload.c (match_set_entries): Trigger autoload on new symbols in function namespace: each-match-case, collect-match-cases, append-match-cases, keep-match-cases, each-match-case-product, collect-match-case-products, append-match-case-products, keep-match-case-products. * stdlib/match.tl (each-match-case, collect-match-cases, append-match-cases, keep-match-cases, each-match-case-product, collect-match-case-products, append-match-case-products, keep-match-case-products): New macros. * tests/011/patmatch.tl: New tests. * txr.1: Documented.
* args: type check uses of dargs in places.Kaz Kylheku2025-05-072-5/+5
| | | | | | | | | | | | | | 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.
* infix: expose and document finish-infix.Kaz Kylheku2025-05-072-1/+47
| | | | | | | * autoload.c (infix_set_entries): intern finish-infix in the usr package, and trigger autoload on it. * txr.1: Documented existence and purpose of finish-infix.
* infix: bug: non-infix expressions conflated with infix.Kaz Kylheku2025-05-073-15/+29
| | | | | | | | | | | | | | | | | | | The problem is that (parse-infix '(x < y < z)) and (parse-infix '(x < (< y z)) produce exactly the same parse and will be treated the same way. But we would like (< y z) to be left alone. The fix is to annotate all compound terms such that finish-infix will not recurse into them. * stdlib/infix.tl (parse-infix): When an operand is seen that is a compound expression X it is turned into @X, in other words (sys:expr X). (finish-infix): Recognize (sys:expr X) and convert it into X without recursing into it. * tests/012/infix.tl: Update a number of test cases. * txr.1: Documented.
* buf: int-buf: unsigned multiplication overflow.Kaz Kylheku2025-05-071-2/+1
| | | | | | | * buf.c (int_buf): Do not multiply the buffer length by 8 as a built-in unsigned integer. Use the mul function instead on the original Lisp integer length. sign-extend handles bignum values for the bit width.
* mpi: remove signed_bin stuff we don't use.Kaz Kylheku2025-05-072-42/+0
| | | | | | | | | * mpi/mpi.c (mp_read_signed_bin, mp_signed_bin_size, mp_to_signed_bin): Functions removed. * mpi/mpi.h (mp_read_signed_bin, mp_signed_bin_size, mp_to_signed_bin): Declarations removed. (mp_read_raw, mp_raw_size, mp_toraw): Macros removed.
* arith: logtrunc, lognot, bit, sign-extend: handle bits <= 0.Kaz Kylheku2025-05-072-22/+29
| | | | | | | | | | | | | | | This fixes an exception in (int-buf #b''). * arith.c (comp_trunc, lognot): Do not throw on negative bits, just return zero. (bit): Return nil if bit is negative rather than throwing. (sign_extend): Fix instance of bad indentation. Renumber goto labels. Otherwise, nothing needs to be done here since bit is where it was blowing up on a zero or negative bits value. * txr.1: Document that logtrunc, lognot, sign-extend and bit handle nonpositive bit widths, and negative bit positions.
* mpi: allow conversion of zero-sized buffer.Kaz Kylheku2025-05-071-1/+1
| | | | | | | | | This causes assertions in uint-buf and int-buf on an empty buffer argument. * mpi.c (mp_read_unsigned_bin): Remove len > 0 assertion, because the code works fine for len == 0, returning the zero mp_int produced by mp_zero.
* New function: buf-binary-width.Kaz Kylheku2025-05-074-0/+164
| | | | | | | | | | | * buf.c (buf_binary_width): New function. (buf_init): Register buf-binary-width intrinsic. * buf.h (buf_binary_width): Declared. * tests/012/buf.tl: New tests. * txr.1: Documented.
* New function: buf-count-ones.Kaz Kylheku2025-05-064-0/+201
| | | | | | | | | | | * buf.c (buf_count_ones): New function. (buf_init): Register buf-count-ones intrinsic. * buf.h (buf_count_ones): Declared. * tests/012/buf.h: New tests. * txr.1: Documented.
* buf: buf_ash: fix buffer overrrun.Kaz Kylheku2025-05-061-1/+1
| | | | | * buf.c (buf_ash): Loop must be clamped the smaller length of the result, cnlen.
* buf: remove array size checks from bit ops.Kaz Kylheku2025-05-061-15/+1
| | | | | | | | | | | | | | | | The length of a buffer is capped by the range of cnum, which is a subrange of ucnum. A buffer can never be so big that it can't be iterated by a for (i = 0; i < len; i++) loop, where i and len are of type ucnum. * buf.c (buf_ash): In this function, we potentially create a longer buffer than the input, and so here it makes sense to check for the new length being out of the range of cnum; i.e. beyond INT_PTR_MAX. We keep the check but change the threshold. (buf_and, buf_test, buf_or, buf_xor, buf_not): Remove checks on existing length.
* New function: buf-test.Kaz Kylheku2025-05-064-3/+77
| | | | | | | | | | | * buf.c (buf_test): New function. (buf_init): Register buf-test intrinsic. * buf.h (buf_test): Declared. * tests/012/buf.tl: New tests. * txr.1: Documented.
* New function: buf-zero-p.Kaz Kylheku2025-05-064-0/+59
| | | | | | | | | | | * buf.c (buf_zero_p): New function. (buf_init): Register buf-zero-p intrinsic. * buf.h (buf_zero_p): Declared. * tests/012/buf.tl: New tests. * txr.1: Documented.