| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* RELNOTES: Updated.
* configure (txr_ver): Bumped version.
* stdlib/ver.tl (lib-version): Bumped.
* txr.1: Bumped version and date.
* txr.vim, tl.vim: Regenerated.
* protsym.c: Regenerated.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
| |
* txr.1: *define-struct-prelude* should of course be
define-struct-prelude.
* stdlib/doc-syms.tl: Updated.
|
|
|
|
| |
* stdlib/quips.tl (%quips%): New one about personality.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
When an invalid call expression is constant folded, such
as (call 'abs 1 2), runaway recursion occurs. This is
because due to the wrong number of arguments being passed
to abs, the safe-const-reduce function returns the
expression unmodified. The comp-apply-call method then
passes it to compile, wrongly assuming a reduction had
taken place, and so everything repeats.
* stdlib/compiler.tl (comp-apply-call): Detect when
safe-const-reduce has hit a fixed point by returning
the input form. In that case, we don't call the compiler
top-level entry point, but the comp-fun-form method
directly; the wrong function call will be compiled without
constant folding and throw an error at run-time.
|
|
|
|
|
|
|
|
| |
* stdlib/constfun.tl (%const-foldable-syms%): Removing
the following functions, which cannot be constant folded
because maybe are relied upon to produce fresh objects:
cons, sub-list, conses, ldiff, uniq, tostring, tostringp,
join, join-with.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* stdlib/compiler.tl (comp-catch): Under an optimization level
of at least 1, if no symbols are being caught, or if the
try expression is a safe constant expression, then just
compile the try expression. Furthermore, if there is only one
exception symbol being caught, and a catch clause is for a
subtype of that symbol, we eliminate the run-time
exception-subtype-p test. This will always be true if the catch
macros are being used, because the list of symbols is derived
from the clauses. Lastly, if there is only one exception symbol
being caught, any clause which doesn't match that symbol is
now eliminated as dead code. That shouldn't happen unless
the sys:catch operator is used directly.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* RELNOTES: Updated.
* configure (txr_ver): Bumped version.
* stdlib/ver.tl (lib-version): Bumped.
* txr.1: Bumped version and date. Also mention that separator
commas in integer tokens are new in 283 and have a different
interpretation in older versions.
* txr.vim, tl.vim: Regenerated.
* protsym.c: Regenerated.
|
|
|
|
|
|
|
|
|
|
|
| |
* stdlib/struct.tl (macroexpand-struct-clause): New function.
* autoload.c (struct_set_entries): Autoload struct module
on macroexpand-struct-clause.
* txr.1: Documented.
* stdlib/doc-syms.tl: Updated.
|
|
|
|
|
|
|
|
|
|
|
| |
* stdlib/match.tl (macroexpand-match): New function.
* autoload.c (match_set_entries): Autoload match
module on macroexpand-match.
* txr.1: Documented.
* stdlib/doc-syms.tl: Updated.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* stdlib/place.tl (sys:pl-expand): Function renamed to
macroexpand-place; env parameter becomes optional.
(macroexpand-1-place): New function.
(place-form-p, call-update-expander, call-clobber-expander,
call-delete-expander): Follow rename.
* autoload.c (place_set_entries): Register symbols
macroexpand-place and macroexpand-1-place for autoload.
* txr.1: Documented.
* stdlib/doc-syms.tl: Updated.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* stdlib/pmac.tl (macroexpand-params): New function,
implemented using newly exposed sys:expand-param-macro.
* autoload.c (pmac_set_entries): Trigger pmac.tl autload
on macroexpand-params symbol.
* eval.c (eval_init): Register existing expand_param_macro
function as sys:expand-param-macro.
* txr.1: Documented.
* stdlib/doc-syms.tl: Updated.
|
|
|
|
|
|
|
|
|
|
|
|
| |
* 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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* stream.c (standard_k, print_json_format_s):
New symbol variables.
(stream_init): New variables initialized.
* stream.h (enum json_fmt): New enum.
(standard_k, print_json_format_s): Declared.
* lib.c (out_json_rec): Take enum json_fmt param,
and pass it recursively. Printing for vector and
dictionaries reacts to argument value.
(out_json, put_json): Examine value of special
var *print-json-format* and calculate enum json_fmt
value from this. Pass to out_json_rec.
* txr.1: Documented.
* stdlib/doc-syms.tl: Updated.
|
|
|
|
|
|
|
|
|
|
|
| |
* stream.c (inc_indent_abs): New function.
(stream_init): inc-init-abs intrinsic registered.
* stream.h (inc_indent_abs): Declared.
* txr.1: Documented.
* stdlib/doc-syms.tl: Updated.
|
|
|
|
| |
* stdlib/quips.tl (%quips%): New entry.
|
|
|
|
|
|
|
|
| |
* stdlib/struct.tl (defstruct): Don't generate a separate finalizer
registration for each :fini or :postfini; roll them into a single
lambda in the correct order. Their object argument turns into a
let block around each piece of code to bind that argument, like
had been done for :init and :postinit.
|
|
|
|
|
|
|
|
| |
* stdlib/struct.tl (defstruct): When an :init, :fini,
:postinit or :postfini has an empty body, do not push
it onto its corresponding list. Then later we don't
have to check for empty items when generating the code;
we know only non-empty items are on the lists.
|
|
|
|
|
|
|
| |
* stdlib/struct.tl (define-struct-clause): Disallow
the :postfini keyword as clause name.
* txr.1: Documented.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
| |
* stdlib/socket.c (sys:in6addr-condensed-text): The
regular expression used in calculating zr is incorrect;
the zero in it can match the trailing zero of
a nonzero quad, when the intent is only to match
zero quads. Hack: we represent zero quads by the
character Z and use that for the matching and removal
of the longest range of zero quads. Then we filter
the Z back to 0.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
| |
* RELNOTES: Updated.
* configure (txr_ver): Bumped version.
* stdlib/ver.tl (lib-version): Bumped.
* txr.1: Bumped version and date.
* txr.vim, tl.vim: Regenerated.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* stdlib/compiler.tl (env rename-var): Method removed.
(compiler comp-let): Instead of initially creating
a let* variable as a gensym, and then renaming it
after compiling the init expression, we now just
obtain the location not bound to a variable, use the
location when compiling the init form, and bind
the location to a variable right after. This is
cleaner since the only thing we are mutating now is
the environment, and we are not wastefully allocating
a gensym. The real motivation is that this is building
up to a bugfix in compiling optional variables in
lambda: stay tuned!
|
|
|
|
|
|
|
|
|
|
|
|
| |
* stdlib/compiler.tl (env get-loc): New method for
allocating v-reg, split out of extend-var and
extend-var*. Now there is a check for the v-cntr
overflow.
(env (extend-var, extend-var*)): Taken an optional
loc parameter, so the caller can optionally allocate
a v-reg location using get-loc, and then specify
that location when creating a variable. If the
argument is omitted, use get-loc.
|
|
|
|
|
|
|
|
|
| |
* stdlib/compiler.tl (env (extend-var, extend-var*)):
Return the variable binding rather than the alist
containing it.
(compiler (comp-catch, comp-let, comp-tree-case)):
Drop use of cdar on return value of extend-var
to ferret out the binding from the alist.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* stdlib/optimize (basic-blocks ling-graph): I'm reverting
an old design decision here. The decision is this:
the basic block of a close instruction points to the
first basic block of the closure as its next block,
but that next block does not point back: it doesn't list
the close instruction's basic block among the rlinks.
The idea was that the close instruction doesn't jump
to that block, and so it shouldn't be linked to it.
However, the next link was set purely so that the graph
is connected. Unfortunately, the inconsistency in the
graph structure which this causes is a problem in the
elim-dead-code method. A situation arises when that
first basic block after the close is removed. Because
pit has an empty rlinks list, the block remains listed
as the next block of the close block, even though it is
removed from the master list of blocks.
(basic-blocks check-bypass-empty): Fix one forgotten detail
in this function: the block being deleted must be removed
from the rlinks list of the next block.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* RELNOTES: Updated.
* configure (txr_ver): Bumped version.
* stdlib/ver.tl (lib-version): Bumped.
* txr.1: Bumped version and date.
* txr.vim, tl.vim: Regenerated.
* protsym.c: Regenerated.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* lib.c (lazy_stream_s): New symbol variable.
(lazy_streams_binding): New static variable.
(lazy_stream_register): New static function
(lazy_stream_cons): If the stream is associated with
a lazy cons, register it with lazy_stream_register.
(obj_init): gc-protect lazy_streams_binding variable.
Intern the sys:*lazy-streams* symbol.
* lib.h (lazy_streams_s): Declared.
* eval.c (eval_init): Register sys:*lazy-streams*
special variable.
* stdlib/getput.tl (close-lazy-streams): New macro.
* autoload.c (getput_set_entries): Trigger autload on
close-lazy-streams symbol.
* txr.1: Documented.
* stdlib/doc-syms.tl: Updated.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* eval.c (eval_init): search-all intrinsic registered.
* lib.c (search_common): New Boolean argument all,
indicating whether all positions are to be returned.
We must handle this in the two places where empty
key and sequence are handled, and also in the main loop.
A trick is used: the found variable is now bound by
list_collect_decl, but not used for collecting unless
all is true.
(search, rsearch, contains): Pass 0 for all argument
of search_common.
(search_all): New function.
* lib.h (search_all): Declared.
* tests/012/seq.tl: New tests.
* txr.1: Documented.
* stdlib/doc-syms.tl: Regenerated.
|
|
|
|
|
|
|
|
|
|
| |
* RELNOTES: Updated.
* configure (txr_ver): Bumped version.
* stdlib/ver.tl (lib-version): Bumped.
* txr.1: Bumped version and date.
|
|
|
|
|
|
|
|
|
|
|
|
| |
* RELNOTES: Updated.
* configure (txr_ver): Bumped version.
* stdlib/ver.tl (lib-version): Bumped.
* txr.1: Bumped version and date.
* txr.vim, tl.vim: Regenerated.
|
|
|
|
|
|
|
| |
* stdlib/path-test.tl (safe-abs-path): If (uname) doesn't
report Linux, then define this function in a way that it
always returns true. We do this by making the name an alias
for the tf function.
|
|
|
|
|
|
| |
* stdlib/path-test.tl (path-components-safe): Reject symlinks
that have a link count not equal to one. This looks
suspiciously like a hard link attack.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Attacks are possible via /proc/<pid>/fd/<n> involving
a deleted file, whereby the link target changes from
"/path/to/file" to "/path/to/file (deleted)", which
can be perpetrated by a different user, not related
to process <pid>, who has access to perform
unlink("/path/to/file").
* stdlib/path-test.tl (safe-abs-path): Perform the
pattern check regardless of effective user ID.
* tests/018/path-safe.tl: Test cases adjusted.
|
|
|
|
|
| |
* stdlib/path-test (path-components-safe): Remove empty
components from split path.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
In a Linux system, it's possible for an unprivileged
user to create a root symlink pointing to any directory,
simply by changing to that directory and running a setuid
executable like "su". That executable will get a process
whose /proc/<pid> directory is root owned, and contains
a symlink named cwd pointing to the current directory.
Other symlinks under /proc look exploitable in this way.
* stdlib/path-test.tl (safe-abs-path): New function.
Here is where we are going to check for unsafe paths.
We use some pattern matching to recognize various unsafe
symlinks under /proc.
(path-components-safe): Simplify code around recognition
of absolute paths. When an absolute path is read from
a symlink, remove the first empty component. Pass every
absolute path through safe-abs-path to check for known
unsafe paths.
* tests/018/path-safe.tl: New tests.
|
|
|
|
|
|
|
|
| |
* stdlib/copy-file.tl (path-simplify, path-split, path-volume,
rel-path, path-equal): Remove from here.
* stdlib/path-test.tl: (path-simplify, path-split, path-volume,
rel-path, path-equal): Move to here.
|
|
|
|
|
|
|
|
| |
* stdlib/socket.tl (in6addr-str): Remove one of
the two repetitions of a string substitution
intended to be done once. The substitution is
idempotent and therefore a second application
of it is redundant regardless of intent.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* txr.c (sysroot_init): Use regsub to look for "\\"
substring instead of regex.
* stdlib/getopts.tl (opt-parsed convert-type):
regsub for "0x" substring rather than #/0x/ regex.
* stdlib/pic.tl (pic-join-oipt): regsub for
"~" substring rather than #/\~/ regex.
* stdlib/socket.tl (in6addr-str): regsub for "::"
substring instead of #/::/ regex in two places.
The double regsub there looks like a mistake; will
address in another commit.
|
|
|
|
|
|
|
|
| |
* stdlib/path-test.tl (path-components-safe): Simplify code;
forget trying to do anything on Windows: just return true.
* txr.1: Document that path-components-safe is useless
on Windows.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* autoload.c (path_test_set_entries): Autoload on
path-components-safe symbol.
* stdlib/path-test.tl (if-windows, if-native-windows):
New system macros.
(path-safe-sticky-dir): New system function.
(path-components-safe): New function.
* tests/018/path-safe.tl: New file.'
* txr.1: Documented.
* stdlib/doc-syms.tl: Updated.
|