| Commit message (Collapse) | Author | Age | Files | Lines |
... | |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* 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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* 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.
|
|
|
|
|
|
|
|
|
|
|
| |
* 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.
|
|
|
|
|
|
| |
* tests/018/clean.tl: New file.
* tests/018/clean.expected: New file.
|
|
|
|
|
|
|
|
|
|
|
|
| |
* 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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* 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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
| |
* 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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
| |
* tests/012/sort.tl: The larger input tests are
testing only vectors, thus covering neither
quicksort nor array binary merge. Cases
added.
|
|
|
|
|
|
|
|
| |
* 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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
| |
* 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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
| |
* tests/010/range.tl: New file.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* 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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
| |
* 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/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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* 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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* 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.
|
|
|
|
|
| |
* tests/018/crypt.tl: Exit with successful termination status
on Android or Cygwin.
|
|
|
|
|
|
|
|
|
|
|
|
| |
* 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").
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
| |
* 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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* 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.
|
|
|
|
| |
* tets/012/oop-dsc.tl: New file.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* 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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* 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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* 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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
| |
* tests/012/lambda.tl: Add the test case which reproduces
the compiler failure that was fixed several
commits ago.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* 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.
|