summaryrefslogtreecommitdiffstats
path: root/tests
Commit message (Collapse)AuthorAgeFilesLines
...
* New cached sorting functions.Kaz Kylheku2023-06-281-2/+23
| | | | | | | | | | | | | | | | | | These functions are useful when sorting a sequence using an expensive keyfun. * autoload.c (csort_set_entries, csort_instantiate): New static functions. (autlod_init): Register autoloading of csort module via new functions. * stdlib/csort.tl: New file. * tests/012/sort.tl: csort functions included in tests. * txr.1: Documented. * stdlib/doc-syms.tl: Updated.
* New function: hash-map.Kaz Kylheku2023-06-281-0/+3
| | | | | | | | | | | | | | | | | | | | hash-map converts a function mapping over a sequence into a hash table. * hash.[ch] (hash_map): New function. * tests/010/hash.tl: Test case. * genman.txr: The hash-map identifier introduces a hash collision. We have to deal with that somehow now. (colli): We put the conflicting entries into a new hash called colli which maps them to an increment value. (hash-title): Increment the hash code h by the amount indicated in colli, if the title is found there. * txr.1: Documented. * stdlib/doc-syms.tl: Updated.
* equal: bug: broken equality substitution.Kaz Kylheku2023-06-281-0/+8
| | | | | | | | | | | | | * lib.c (equal): Several cases which react to the type of the left argument have a default path which wrongly short-circuits to an early return. All these cases must break through to the logic at the end of the function which tests the right side for a possible equality substitution. * tests/012/struct.tl: One breaking test cases added. equal was found to return nil for two structures that have equal lists as their equality substitute.
* hash: support existing mutation+iteration semantics.Kaz Kylheku2023-06-201-0/+33
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The original chained hashing scheme makes certain guarantees in situation when a hash table that is being iterated is also undergoing insertions or deletions. The original scheme meets these requirements simply, by putting a freeze against hash table growth while there are outstanding iterations. Chained hashing gracefully handles load factors above 1. Load factors above 1 are not possible under open addressing (and we don't even want to approach 1) but we would like to preserve the requirements. The requirements are: 1. If an iterator has already visited an item, it will not see that item again, regardless of insertions which cause the table to be reorganized. 2. It is not specified/required that an iterator will visit newly inserted items. It may visit some of those items, but not others. 3. If an iterator has not yet visited an item, and that item is deleted, it will not see that item, regardless of any insertions that reorganize the table. In this commit, we implement a "table stack" scheme. 1. When a table is resized due to insertions, and it is being iterated (h->usecount > 0), in that situation it will push the existing small table onto a stack, the h->tblstack (table stack). 2. Iterators take a hash table's current table and its size, and work with that snapshot of the table. If the original hash table grows, existing iterators work with the original table as it existed just before the reorganization. So after that they do not see any new insertions. 3. Whenever the delete operation (hash_remove) finds the item and removes it from the current table, it also walks the table stack, searches for the item in every table in the stack and nulls it out. This search is oblivious to nil; it's a blind search that goes around the table starting at the first probe position, looking for the identical cons cell to take out. This algorithm ensures that iterators will not see a deleted item, unless they already visited it before the deletion, of course. * hash.h (struct hash_iter): New members table, and mask. * hash.c (struct hash): New member, tblstack. (hash_grow): We drop the vec argument and recreate it locally (not essential to this commit). If we find that the usecount is positive, we push the existing table onto the table stack. Otherwise, we take the opportunity to obliterate the table stack. (hash_insert): Drop the restriction that hash_grow is only called when the use count is zero. Adjust calls to hash_grow to drop the vec argument. (hash_remove): When an item is found and deleted, and the table is in use by iterators, walk the table stack and delete it from each previous table. Otherwise, if the table is not in use by iterators, obliterate the table stack. (hash_mark): Exit early also if there is a table stack, and mark that stack. (do_make_hash, make_similar_hash, copy_hash): Initialize table stack in new hash. (hash_iter_mark): Mark the iterator's table. This is likely not necessary since we also mark the hash table, which should have a pointer to that same table. That wouldn't be defensive programming, though. (hash_iter_init, us_hash_iter_init): Initialize table and mask. (hash_iter_next_impl, hash_iter_peek): These functions have to walk the table snapshot taken by the iterator, using the captured mask, and not the current table. (has_reset): If the target table's use count drops to zero, obliterate its table stack. We add a missing setcheck here; this operation potentially stores a different hash into an existing iterator. It's not being done safely with regard to generational GC. * tests/010/hash.tl: New tests.
* New macro: match-cond.Kaz Kylheku2023-06-121-0/+14
| | | | | | | | | | | | | * stdlib/match.tl (match-cond): New macro. * autoload.c (match_set_entries): match-cond triggers autoload of match module. * tests/011/patmatch.tl: Tests. * txr.1: Documented. * stdlib/doc.tl: Updated.
* New functions keep-keys-if, separate-keys.Kaz Kylheku2023-06-071-0/+15
| | | | | | | | | | | * lib.[ch] (keep_keys_if, separate_keys): New functions. * eval.c (eval_init): keep-keys-if, separate-keys intrinsics registered. * txr.1: Documented. * stdlib/doc-syms.tl: Updated.
* clean-file: tests.Kaz Kylheku2023-06-052-0/+110
| | | | | | * tests/018/clean.tl: New file. * tests/018/clean.expected: New file.
* New functions load-args-recurse and load-args-processKaz Kylheku2023-06-051-0/+72
| | | | | | | | | | | | * autoload.c (load_args_set_entries, load_args_instantiate): New static functions. (autoload_init): Register new auto-loaded module "load-args". * stdlib/load-args.tl: New file. * txr.1: Documented. * stdlib/doc-syms.tl: Updated.
* load: now passes args via *load-args*Kaz Kylheku2023-05-313-0/+16
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | We can give additional arguments to load, which become arguments of the script, which it can retrieve via the *load-args* special variable. * eval.c (load_args_s): New symbol variable. (loadv): New function, taking over the implementation of load. This takes variadic arguments. Loadv binds the *load-args* variable from the list of variadic arguments. (load): Reduced to wrapper around loadv. (rt_load_for): Each clause in load for can now have arguments after the target name. If that file needs to be loaded, then the arguments are passed. (me_load_for): The macro expander for the load-for macro needs to allow for the load-arg expressions and generate code which passes them to sys:rt-load-for. They all get evaluated. (eval-init): Initialize load_args_s and register the *load-args* variable. Update registration of intrinsic function load to use loadv. * tests/019/load-ret.tl, * tests/019/load-ret/module.tl, * tests/019/load-ret/module2.tl: New files. * txr.1: Documented.
* expander: support param macros in nested macro param lists.Kaz Kylheku2023-05-271-0/+9
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Parameter list macros work in inside macro parameter lists, like they do in function parameter lists. However, they ony work at the top level. Macro parameter lists are nested; they may contain nested parameter lists that match corresponding shapes in the argument list. This patch extends parameter list macros to work in nested macro parameter lists. * eval.c (expand_opt_params_rec, expand_params_rec): These two functions must be extended to take a body argument, and to return not just an expanded parameter list but a parameter list accompanied by a body. We do that by making them return a cons cell, whose car is the expanded parameter list and the cdr is the possibly transformed body. Additionally, these functions now call expand_param_macro on nested macro parameter lists. (expand_params): This function becomes slightly simpler as a result of the above changes. Because expand_params_rec already returns a cons cell holding a parameter list and body, we just return that as-is. * tests/011/keyparams.tl: Added some tests of this, vie the standard :key parameter list macro. A macro is tested which has a nested (:key ...) parameter list in a required parameter position as well as in an optional position. * txr.1: Documented.
* label/flet: bug: empty case wallops symbol macros.Kaz Kylheku2023-05-241-0/+5
| | | | | | | | | | | | | | * eval.c (make_var_shadowing_env): We cannot return the original env in the empty variable case, but earnestly make a new one. This function is used by the expander when walking the lbind/fbind special from emitted by labels/flet. That form clobbers the environment via make_fun_shadowing_env, which calls make_var_shadowing_env and then destructively moves the variable bindings to the function binding slot of the environment. The manifestation is that when we have (symacrolet ((x 1)) (labels () x)), the x fails to expand; it has been wrongly moved to the function bindings area of the macro environment.
* lib: fix issue uncovered by recent vm CALL insn change.Kaz Kylheku2023-05-241-2/+25
| | | | | | | | | | | | | | | | | | | | | | | | | | | | The functions funcall1 through funcall4, when invoking a VM function, are not defending against the case when there are more arguments than the function can take. As a result, some :mass-delegate tests in tests/012/oop.tl are failing. They expect an :error result, but the calls are succeeding in spite of passing too many parameters via the delegate interface. The tests/012/lambda.tl suite should catch this, but it has unfortunate weaknesses. * lib.c (funcall1, funcall2, funcall3, funcall4): When dispatching the general VM case via vm_execute_closure, check that if the closure has fewer fixed parameters than arguments we are passing, it must be variadic, or else there is an error. * tests/012/lambda.tl (call-lambda-fixed): New function. Unlike call-lambda, which uses the apply dot syntax, this switches on the argument list shape and dispatches direct calls. These compile to the CALL instruction cases with four arguments or less which will exercise funcall, funcall1, ... funcall4. Also, adding some missing test cases that probe behavior with excess arguments.
* awk: bug: fix ->> appending redirection operator.Kaz Kylheku2023-05-231-0/+42
| | | | | | | * stdlib/awk.tl (awk-state ensure-stream): Fix missing handling for the :apf kind symbol used by appending. * tests/015/awk-redir.tl: New file.
* New special operator: progvKaz Kylheku2023-05-151-0/+29
| | | | | | | | | | | | | | | | | | | | | | Adding a progv operator, similar to the Common Lisp one. * eval.c (progv_s): New symbol variable. (op_progv): New static function. (do_expand): Recognize and traverse the progv form. (rt_progv): New static function: run-time support for compiled progv. (eval_init): Initialize progv_s, and register the the op_progv operator interpreting function. * stdlib/compilert (compiler compile): Handle progv operator ... (compiler comp-progv): ... via this new method. * tests/019/progv.tl: New file. * txr.1: Documented. * stdlib/doc-syms.tl: Updated.
* bug: symbol-value place always global.Kaz Kylheku2023-05-141-0/+24
| | | | | | | | | | | | | | | | | | | | | | | | | | | We have a problem. If v is a dynamic variable, then the form (let (v) (set (symbol-value 'v) 3)) is not behaving correctly; it's updating the top-level value of v not the rebound one. * eval.c (set_symbol_value): New static function. (eval_init): Register sys:set-symbol-value intrinsic. The top-vb variable, though no longer referenced by the symbol-value place, because existing compiled code depends on it. * stdlib/place.tl (symbol-value): Rewrite the place logic to use symbol-value to access the variable, and set-symbol-value to update it, instead of referencing sys:top-vb. (sys:get-vb): This function has to stay, because it provides run-time support for code compiled with the buggy version of the place. * tests/019/symbol-value.tl: New file.
* sort: missing vector coverage in tests.Kaz Kylheku2023-05-031-4/+18
| | | | | | | * tests/012/sort.tl: The larger input tests are testing only vectors, thus covering neither quicksort nor array binary merge. Cases added.
* sort: move tests into tests/012.Kaz Kylheku2023-05-021-0/+0
| | | | | | | | * tests/010/sort.tl: File moved to tests/012. The reason is that the tests 010 run with the --gc-debug torture tests. That test case runs way too long under that test because of the testing of many permutations and whatnot.
* sort: support stable sorting via ssort and snsort.Kaz Kylheku2023-05-021-0/+22
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | For array-like objecgts, these objects use an array-based merge sort, using an auxiliary array equal in size to the original array. To provide the auxiliary array, a new kind of very simple vector-like object is introduced into the gc module: protected array. This looks like a raw dynamic C array of val type, returned as a val *. Under the hood, there is a heap object there, which makes the array traversable by the garbage collector. The whole point of this exercise is to make the new mergesort function safe even if the caller-supplied functions misbehave in such a way that the auxiliary array holds the only references to heap objects. * gc.c (struct prot_array): New struct, (prot_array_cls): New static variable. (gc_late_init): Register COBJ class, retaining in prot_array_cls. (prot_array_mark, prot_array_free): New static functions. (prot_array_ops): New static structure. (prot_array_alloc, prot_array_free): New functions. * gc.h (prot_array_alloc, prot_array_free): Declared. * lib.c (mergesort, ssort_vec): New static function. (snsort, ssort): New functions. * lib.h (snsort, ssort): Declared. * tests/010/sort.tl: Cover ssort. * txr.1: Documented. * stdlib/doc-syms.tl: Updated.
* sort: larger test.Kaz Kylheku2023-05-011-0/+8
| | | | | | | | * tests/010/sort.tl: Add some test cases of larger list. The exhaustive permutation tests are good but only go up to a relatively short size, where the median-of-three doesn't even kick in. We also cover choosing an alternative less function.
* sort: replace Lomuto partitioning with HoareKaz Kylheku2023-05-011-0/+15
| | | | | | | | | | | | | | | | | | I'm seeing numbers aobut the same performance on a sorted vector of integers, and 21% faster on vector of N random integers in the range [0, N). Also, this original algorithm handles well the case of an array consisting of a repeated value. The code we are replacing degrates to quadratic time. * lib.c (med_of_three, middle_pivot): We don't use the return value, so don't calculate and return one. (quicksort): Revise to Hoare: scanning from both ends of the array, exchanging elements. * tests/010/sort.tl: New file. We test sort with lists and vectors from length zero to eight, all permutations.
* hash: new function, hash-props.Kaz Kylheku2023-05-011-0/+7
| | | | | | | | | | | | | | | | We don't have a function in the hash table module which can create a populated hash table in one step without requiring the caller to create auxiliary lists. This new function fills that gap, albeit with some limitations. * hash.c (hash_props): New function. (hash_init): Register hash-props intrinsic. * tests/010/hash.tl: New tests. * txr.1: Documented. * stdlib/doc-syms.tl: Updated.
* match: ^#S() and ^#H(()) patterns must workKaz Kylheku2023-04-291-0/+6
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Quasiquote patterns not containing unquotes are not working, because the parser transforms them into quoted objects. For instance ^#S(time) becomes the form (quote #S(time)) and not the form (sys:qquote (sys:struct-lit time)). The pattern matching compiler doesn't treat quote specially, only sys:qquote. * parser.y (unquotes_occur): Function removed. (vector, hash, struct, tree, json_vals, json_pairs): Remove use of unquotes_occur. Thus vector, hash, struct, tree and JSON syntax occurring within a backquote will be turned into a special literal whether or not it contains unquotes. * lib.c (obj_print_impl): Do not print the form (sys:hash-lit) as #Hnil, but #H(). * stdlib/match.tl (transform-qquote): Add a case which will handle ^#H(), as if it were ^H(()). Bugfix in the ^H(() ...) case. The use of @(coll) means it fails to match the empty syntax when no key/value pairs are specified, whereas @(all) respects vacuous truth. * test/011/patmatch.tl: A few tests. * y.tab.shipped, y.tab.h.shipped: Updated.
* range/range*: tests.Kaz Kylheku2023-03-271-0/+103
| | | | * tests/010/range.tl: New file.
* New function: arithp.Kaz Kylheku2023-03-262-0/+9
| | | | | | | | | | | | | | | | | | | * lib.h (arithp): Declared. (plus_s): Existing symbol declared. * arith.c (arithp): New function. * struct.h (special_slot): New enum member plus_m. * struct.c (special_sym): Register plus_s together as the [plus_m] entry of the array. * tests/016/arith.tl * tests/016/ud-arith.tl: Tests for arithp. * txr.1: Documented. * stdlib/doc-syms.tl: Updated.
* match: support @nil in predicates.Kaz Kylheku2023-03-231-0/+8
| | | | | | | | | | | | | | | | | For instance @(<= 10 @nil 20) is a pattern which matches a number between 10 and 20, without binding a variable. * stdlib/match.tl (compile-predicate-match): Looks like this code was already halfway expressing the intent that the avar could be nil, because arg-var takes the value of avar if that is non-nil, otherwise a gensym is substituted. What was missing was that the gensym that replaces nil must also be substituted into the predicate. * tests/011/patmatch.tl: New tests. * txr.1: Document that the variable embedded in a predicate may be null.
* printer: [] shouldn't print as [. nil].Kaz Kylheku2023-03-231-1/+7
| | | | | | | | | | * lib.c (obj_print_impl): In the case when dwim has no args, and the logic short circuits to a closing brace, bypassing the loop, we should only use the dot notation if the terminating atom is other than nil. * tests/012/readprint.tl: Tests added.
* tests: squelch unused variable warnings.Kaz Kylheku2023-03-236-25/+29
| | | | | | | | | | | | | | | | | | * tests/011/patmatch.tl, * tests/019/pct-fun.tl: Disable unused warnings around file self-compilation. * tests/011/tree-bind.tl: Fix one unused variable instance using interned symbol. * tests/011/compile.tl: Disable unused warnings around all file compilation. * tests/012/lambda.tl: Use the parameter of one trivial lambda. * tests/common.tl: Disable unused warnings around compiled tests.
* lib: address remaining unused variable warnings.Kaz Kylheku2023-03-222-6/+10
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * stdlib/arith-each.tl (sys-arith-each): Remove :form param. * stdlib/awk.tl (awk-state :fini): Suppress unused warning in dohash form by using an uninterned symbol for this variable. This is a useful technique worth documenting. (awk-expander): Remove unused varaible in a predicate pattern. (awk-code-move-check): Lose the unused awc and aws-sym. (awk-mac-let): Don't pass the unused parameters to awk-code-move-check. * stdlib/conv.tl (conv-expand): Remove unused gensym. * stdlib/debugger.tl (fcall-frame loc, fcall-frame print-trace, expand-frame print-trace): Mark unused parameters ignored. * stdlib/defset.tl (defset-expander-simple): Remove unused parameter. (defset): Drop argument from defset-expander-simple call, and also fix unused warning in tree-case form. * stdlib/doc-lookup.tl (detached-run): Remove unused variable from a pattern matching predicate. It's not in the rightmost position so we have to revers the comparison. I will enhance the pattern matcher to support @nil in a predicate. (toplevel): Ignore a parameter of the not-implemented version of the open-url function. * stdlib/doloop.tl (expand-dooloop): Replace unused variable in a tree binding pattern with the t symbol. * stdlib/each-prod.tl (expand-each-prod*): Remove unused let variable. * stdlib/except.tl (expand-handle): Put else variable in tree bind pattern to use. * stdlib/getopts.tl (opt-desc (basic-type-p, cumul-type-p)): Replace unused catch-all variable in tree bind pattern with t symbol. (opt-processor parse-opts): Remove unused args argument. The object holds the args, prepared at construction time. (getopts, option-base getopts): Don't pass args to parse-opts. (define-option-struct): Replace unused treee pattern variable with t. * stdlib/ifa.tl (if-to-cond): Put catch-all else variable to use. * stdlib/keyparams.tl (param-expander): Mark unused parameter ignored. Replace unused variables in tree-case with t. * stdlib/match.tl (compile-struct-match, compile-predicate-match, compile-require-match, compile-as-match, compile-with-match, compile-or-match, compile-and-match, compile-not-match, compile-hash-match, compile-scan-match, compile-exprs-match): Address unused variables in mac-param-bind and tree-bind patterns. (match-case): Likewise, and also remove unused let variables. (while-match-case, while-true-match-case): Remove unused :env parameter. (expand-lambda-match): Remove unused let variable. (defun-match): Remove unused variable in tree-bind. (define-param-expander): Mark menv parameter ignored. Unused variables in tree-bind. (defmatch): Replace lambda variable with a gensym. (loosen, pat-len): Remove unused parameter. (sme, end): Fix calls to loosen and pat-len. (non-triv-pat-p): Mark parameter ignored in the temporary version of this function. (expand-quasi-match): Address unused variables in patterns, and remove unused gensyms. * stdlib/op.tl (op-rec-p): Unused variable in tree-case. (op-alpha-rename): Remove f parameter. (op-ignerr): Mark catch handler parameter ignored. (op-expand): Remove argument from calls to op-alpha-rename. * stdlib/path.test (if-windows, if-native-windows): The compiler complains here about the unused variable due to constant folding. We use the use function to indicate that the variable is not ignored, but used. * stdlib/pic.tl (expand-pic-num): Remove unused let variable. (pic): Remove unused :env parameter. * stdlib/place.tl (macroexpand-1-place): Ignore unused env parameter. (pset): Ignore some tree-bind variables. Not replacing them with t because their names help code readability. Lots of tricky code in place.tl. (shift): Replace unused variable with t in tree-case. (vecref, chr-str, ref, sub): Deal with unused expander parameters. (gethash): Deal with unused place parameter. (dwim): Remove unused env parameter, and deal with unused place parameters. (get-fun-getter-setter): Unused variables in tree-bind. (read-once, define-modify-macro): Remove unused gensyms. (placelet-1): Mark ignored a parameter of an update expander lambda. * stdlib/pmac.tl (macroexpand-params): Fix unused catch-all in tree-case. * stdlib/struct.tl (prune-missing-inits): Mark tree-bind unused variable ignored. (defstruct): Unused tree-case variable. (qref): Unused tree-case catch-all variables. (rslot): Unused parameter removed. (:delegate): Unused tree-case variables. * stdlib/tagbody.tl (tagbody): Drop unused :env param. Mark ignored the threaded-2 let variable, which cannot be removed because its init-form performs a needed side effect. * stdlib/trace.tl (trace-leave): Remove unused param. (trace): Don't pass argument to unused param of trace-leave. (untrace): Use gensym in dohash to suppress unused variable warning. * stdlib/type.tl (typecase-expander): Unused variable in tree-case. * stdlib/with-resources.tl (with-resources): Likewise. * stdlib/yield.tl (hlet-expand): Remove two unused locals. * tests/012/lambda.tl: Fix test cases that break the tests due to unused variable warnings. * tests/016/arith.tl: Add test case for each-prod*. At first I thought a bug was found in it but it turned out that the init-forms variable that was removed was really superfluous.
* Allow t symbol in macro parameter lists.Kaz Kylheku2023-03-211-0/+20
| | | | | | | | | | | | | | | | | * eval.c (expand_params_rec, bind_macro_params): Handle t specially everywhere a parameter can occur. Expansion allows the syntax through without extending the environment with a t variable; binding walks over the structure without binding a variable. * stdlib/compiler.tl (expand-bind-mac-params): Likewise, handle occurrences of t, suppressing the generation of and assignment to variables, while ensuring that initializing expressions are evaluated. * tests/011/tree-bind.tl: New file. * txr.1: Documented.
* android, cygwin: do not try to test crypt.Kaz Kylheku2022-12-301-0/+3
| | | | | * tests/018/crypt.tl: Exit with successful termination status on Android or Cygwin.
* crypt: fix for platforms that lack crypt_r.Kaz Kylheku2022-12-301-1/+1
| | | | | | | | | | | | * sysif.c (crypt_wrap): Don't call free(cd) on platforms where we don't have crypt_r and have not defined the cd variable. * test/018/crypt.tl: Move the (crypt "a" "b") test case to be GNU/Linux-only. On Solaris, it yields a valid-looking hash instead of failing. That hash will not validate the password though; i.e. (crypt "a" (crypt "a" "b")) is not equal to (crypt "a" "b").
* awk: new feature, res variable.Kaz Kylheku2022-12-301-0/+8
| | | | | | | | | | | | | | | | The res variable captures the specific value of the condition expression, making it available to the action. * autoload.c (awk_set_entries): Intern the res symbol * stdlib/awk.tl (awk): Instead of generating the condition-action into a simple when, we use whenlet to also bind the res variable. * tests/015/awk-res.tl: New file. * txr.1: Documented. * stdlib/doc-syms.tl: Updated.
* read-once: support globals properly.Kaz Kylheku2022-11-101-9/+13
| | | | | | | | | | | | | | | | | | | | | | | | When a global variable v is wrapped with (read-once v), multiple accesses to the place still generate multiple accesses of the global through getv or getlx instructions. The reason is that the alet and slet macros optimize away a temporary bound to the value of a variable regardless of whether the variable is lexical. Let's fix that. * stdlib/place.tl (slet, alet): Replace the bindable test with lexical-var-p, in the given environment. A binding to a variable is only alias-like if the variable is lexical, otherwise we need a real temporary. * tests/012/struct.tl (get-current-menv): New macro. (menv): New global variable. Fix a number of tests which use expand, whose expansion has changed because the expressions refer to free variables. We introduce an environment parameter which binds all the variables, so that the optimized expansion is produced, as before. * txr.1: Updated documentation. slet gets examples.
* New feature: struct preludes.Kaz Kylheku2022-11-032-0/+18
| | | | | | | | | | | | | | | | | | | | | | | | | | | A struct prelude definition associates one or more future defstruct (by struct name) with clauses which are implicitly inserted into the defstruct. It is purely a macro-time construct, customizing the expansion behavior of defstruct. * stdlib/struct.tl (*struct-prelude, *struct-prelude-alists*): New special variables holding hash tables. (defstruct): Before processing slot-specs, augment it with the contents of the prelude definitions associated with this struct name. (define-struct-prelude): New macro. * autoload.c (struct_set_entries): define-struct-prelude is interned and triggers autoload of struct module. * tests/012/oop-prelude.tl: New file. * tests/012/oop-prelude.expected: Likewise. * txr.1: Documented. * stdlib/doc-syms.tl: Updated.
* crypt: remove dubious validator.Kaz Kylheku2022-10-311-0/+18
| | | | | | | | | | | | | | | | | | | | | | | | The validate_salt function was introduced in commit c3a0ceb2cea1a9d43f2baf5a2e63d0d712c8df19, February 2020. I cannot reproduce the internal crash in crypt which it alleges, and I neglected to mention the bad inputs in the commit or add tests. I'm not able to reproduce the alleged behavior in spite of trying all sorts of bad inputs; and looking at the crypt source in glibc, I don't see any obvious problem. And so, on this Halowe'en, we exorcise the ghost that has been haunting the crypt. * sysif.c (salt_char_p, validate_salt): Static functions removed. (crypt_wrap): Don't call validate_salt, and so cwsalt need not be tested for null. * tests/018/crypt.tl: New file. * txr.1: Mention that crypt_r is used if available, which avoids static storage.
* cat-str/join/join-with: allow nested sequencesKaz Kylheku2022-10-251-0/+13
| | | | | | | | | | | | | | | | | | | | | | | The measure/allocate/catenate functions which underlie the cat-str implementation are streamlined, simplifying the code. At the same time, they handle nested sequences of string/character items. * lib.c (struct cat_str): New member, seen_one. This flips from 0 to 1 after the first item has been seen in the cat_str_measure pass or cat_str_append pass. Each item other than the first is preceded by a separator. (cat_str_measure, cat_str_append): The more_p argument is dropped. We account for the separator with the help of the new seen_one flag, which allows us to easily recurse over items that are sequences. (cat_str_alloc): Reset the seen_one flag in preparation for the cat_str_append pass. (cat_str, vscat, scat2, scat3, join_with): Simplified. * tests/015/split.tl: New tests. * txr.1: Redocumented.
* defstruct: new :inherit clause.Kaz Kylheku2022-10-171-0/+15
| | | | | | | | | | | | | | | The :inherit clause allows custom struct clauses to inject inherited bases. * stdlib/struct.tl (defstruct): Recognize :inherit clause, adding symbol arguments to extra list of supers that get appended to the list coming from defstruct's seconda rgument. (define-struct-clause): Disallow :inherit clause name. * tests/012/oop-dsc.tl: New tests. * txr.1: Documented.
* structs: optional init-exprs now useful in :delegateKaz Kylheku2022-10-111-2/+10
| | | | | | | | | | | | * stdlib/struct.tl (:delegate): Handle the two-element form of the optional parameter, which specifies the usual initializing expression for the default value. This is just passed through as-is to the generated method. Diagnose if the three-element form occurs. * tests/012/oop.tl: Some new tests. * txr.1: Documented.
* Syntax: allow separator commas in numeric tokens.Kaz Kylheku2022-10-051-0/+27
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * parser.l (remove_char): New static function. (DIGSEP, XDIGSEP, NUMSEP, FLOSEP, XNUMSEP, ONUMSEP, BNUMSEP, ONUM, BNUM): New named lex patterns. (FLODOT): Use DIGSEP instead of DIG. (ONUM): Use ODIG instead of [0-7]. (BNUM): Use BDIG instead of [0-1]. (grammar): New rule for producing NUMBER from decimal token with commas based on BNUMSEP instead of BNUM. This is a copy and paste so that the BNUM rule doesn't deal with the comma removal, not to slow it down. For the octal, binary and hex, we just switch to BNUMSEP, ONUMSEP and XNUMSEP, so they all go through one case. Floating point numbers are also handled with a copy pasted case using FLOSEP. * tests/012/syntax.tl: New test cases. * txr.1: Documented. * genvim.txr (alpha-noe, digsep, hexsep, octsep, binsep): New variables. (txr_pnum, txr_xnum, txr_onum, txr_bnum, txr_num): Integrate separating commas. Some bugs fixed in txr_num, some simplifications, better txr_badnum pattern. * lex.yy.c.shipped: Updated.
* define-struct-clause: add tests.Kaz Kylheku2022-10-051-0/+65
| | | | * tets/012/oop-dsc.tl: New file.
* oop: allow multiple :init, :fini, etc.Kaz Kylheku2022-10-042-0/+28
| | | | | | | | | | | | | | | | | | | | | | The motivation is that struct clause macros defined using define-struct-clause may want to introduce their own initializers and finalizers for the specific stuff they add to the struct. The uniqueness restrictions on these initializing and finalizing clauses makes it impossible to use two clause macros which both want to inject a definition of the same initializer or finalizer type. * stdlib/struct.tl (defstruct): Don't enforce that there be at most one clause in the category of :init, :postinit, :fini or :postini. Multiple are allowed. They all execute left-to-right except for :fini. * tests/012/fini.tl: New tests. * tests/012/fini.expected: Updated. * txr.1: Documented.
* New: %fun% mechanism for current function name.Kaz Kylheku2022-10-032-0/+59
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * eval.c (pct_fun_s): New symbol variable, holding the usr:%fun% symbol. (fun_macro_env): New static function. (do_expand): For defun and defmacro, use fun_macro_env to establish an environment binding the %fun% symbol macro, and expand everything in that environment. (eval_init): Intern the %fun% symbol, initializing pct_fun_s, and also register a global symbol macro in that name so that we can freely use %fun% everywhere without worrying that the code will blow up. E.g. a logging macro can use it to get the function name, but still be useful in a top-level form outside of a named function. * stdlib/struct.tl (sys:meth-lambda): New macro. (defstruct, defmeth): Use sys:meth-lambda as a replacement for lambda to set up the %fun% symbol macro. In the :init case which doesn't use a lambda, an open-coded symacrolet does the job. * tests/019/pct-fun.tl: New file. * tests/019/pct-fun.expected: Likewise. * txr.1: Documented. * stdlib/doc-syms.tl: Updated.
* New method: str-addr.Kaz Kylheku2022-10-031-0/+68
| | | | | | | | | | | | | | | | | | | | | * socket.c (sock_set_entries): Intern str-addr symbol. There is no autoload on this because the struct types of which this is a method don't exist if the socket module has not been loaded. * stdlib/socket.tl ((sockaddr-in str-addr), (sockaddr-in6 str-addr), (sockaddr-un str-addr)): New methods. * tests/014/str-addr.tl: New file. This provides coverage not just for the str-addr method, but the hitherto untested address to text functions. This is why the bug was found, that was addressed in the previous commit. The test case which produces "8000::1" was actually producing "800:1". * txr.1: Documented. * stdlib/doc-syms.tl: Updated.
* New sockaddr-str function.Kaz Kylheku2022-10-021-0/+49
| | | | | | | | | | | | | | | | This function "intelligently" constructs an address object of the right type from a string. * socket.c (sock_set_entries): Autoload socket.tl on sockaddr-str function being accessed. * stdlib/socket.tl (sockaddr-str): New function. * tests/014/sockaddr-str.tl: New file. * txr.1: Documented. * stdlib.doc-syms.tl: Updated.
* New :postfini feature in defstruct.Kaz Kylheku2022-09-272-1/+43
| | | | | | | | | | | | | | | | | | | | | | | | The :postfini clause registers a finalizer that runs in the ordinary order: after previously registered ones. This has the effect of allowing a derived structure to run clean-up actions after those of inherited structures. Either order can be useful because the dependencies between base and derived can go in either direction. It's a huge mistake in C++ that it supports only derived-first destructor invocation order. * stdlib/struct.tl (defstruct): Recognize and translate :postfini clause. It's exactly like :fini but omits the t parameter in the finalize call, registering in the natural order. * tests/012/fini.tl (derived): Add :postfini handler. * tests/012/fini.expected: Updated to reflect the messages coming from the postfini handler, which are happening in the correct order. * txr.1: Documented.
* seq-iter: bugfix: floating-point ranges.Kaz Kylheku2022-09-151-0/+23
| | | | | | | | | | | | | | | | | | | | | | * lib.c (seq_iter_get_range_bignum): Static function renamed to seq_iter_get_range_number because it in fact generalizes to numbers. (seq_iter_peek_range_bignum): Renamed to seq_iter_peek_range_number. (seq_iter_get_rev_range_bignum): Renamed to seq_iter_get_rev_range_number. (seq_iter_peek_rev_range_bignum): Renamed to seq_iter_peek_rev_range_number. (si_range_bignum_ops): Renamed to si_range_number_ops. (si_rev_range_bignum_ops): Renamed to si_rev_range_number_ops. (seq_iter_init_with_info): Handle ranges where the from value is floating-point. Also, if the from-value is bignum that fits into cnum range, we now try to handle that as a cnum range. * tests/012/iter.tl: New tests.
* compiler: bug: bad basic-block merge across end insn.Kaz Kylheku2022-09-151-0/+6
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The bad situation reproduced as a miscompilation of some prof forms at *opt-level* 5 or above. The basic idea is that there is a situation like this prof t2 ... profiled code here producing value in t8 mov t2 t8 end t2 end t2 The code block produces a value in t8, which is copied into t2, and executes the end instruction. This instruction does not fall through to the next one but passes control back to the prof instruction. The prof instruction then stores the result value, which came from t2, back into the t2 register and resumes the program at the end t2. The first bad thing that happens is that the end instructions get merged together into one basic block. The optimizer then treats them without regard for the prof instruction, as if they were a linear sequence. It looks like the register move mov t2 t8 is wasteful and so it eliminates it, rewriting the end instruction to: end t8 end t8 Of course, the second instruction is now wrong because prof is still producing the result in t2. To fix this without changing the instruction set, I'm introducing another pseudo-op that represents end, called xend. This is similar to jend, except that jend is regarded as an unconditional branch whereas xend isn't. The special thing about xend is that a basic block in which it occcurs is marked as non-joinable. It will not be joined with the following basic block. * stdlib/asm.tl (xend): New alias opcode for end. * stdlib/compiler.tl (comp-prof): Use xend to end prof fragment, rather than plain end. * stdlib/optimize.tl (basic-block): New slot, nojoin. If true, block cannot be joined with next one. (basic-blocks jump-ops): Add xend to list of jump ops, so that a basic block will terminate on xend. (basic-blocks link-graph): Set the nojoin flag on a basic block which contains (and thus ends with) xend. (basic-blocks local-liveness): Add xend to the case in def-ref that handles end. (basic-blocks (peephole, join-blocks)): Refuse to join blocks marked nojoin. * tests/019/comp-bugs.tl: New file with miscompiled test case that was returning 42 instead of (42 0 0 0) as a result of the wrong register's value being returned.
* compiler: bug: scoping of lambda optionals.Kaz Kylheku2022-09-151-0/+5
| | | | | | | | | | | | | | | | | | | | | | The scoping is not behind handled correctly for optional variables. The init-forms are being evaluated in a scope in which all the variables are already visible, instead of sequentially. Thus, for instance, variable rebinding doesn't work, as in (lambda (: (x x)) ...). When the argument is missing, x ends up with the value : because the expression refers to the new x, rather than the outer x. * stdlib/compiler.tl (compiler comp-lambda-impl): Perform the compilation of the init-forms earlier. Use the same new trick that is used for let*: the target for the code fragment is a locaton obtained from get-loc, which is then attached to a variable afterward. The spec-sub helper is extended with a loc parameter to help with this case. * tests/012/lambda.tl: New test case that fails without this fix.
* compiler: test for recent bugfix.Kaz Kylheku2022-09-141-0/+2
| | | | | | * tests/012/lambda.tl: Add the test case which reproduces the compiler failure that was fixed several commits ago.
* syntax: read and print [. x] and [. @x].Kaz Kylheku2022-09-081-0/+7
| | | | | | | | | | | | | | | | | | | | | | | * lib.c (obj_print_impl): Handle (dwim . atom) syntax by printing [. atom]. Note that (dwim . @var) and (dwim . @(expr)) already print as [. @var] and [. @(expr)]; this is not new. But none of these forms are supported by reading without the accompanying change to the parser. * parser.y (dwim): Handle the [. expr] and [ . expr] syntax, so that forms like [. a] and [. @a] have print-read consistency. The motivation is to be able to [. @args] in pattern matching to match a DWIM forms; I tried that and was surprised to have it blow up in my face. * tests/012/readprint.tl: New test file. Future printer/parser changes will be tested here. Historically, changes to the syntax have not been consistently unit-tested. * y.tab.c.shipped: Regenerated.