summaryrefslogtreecommitdiffstats
path: root/eval.c
Commit message (Collapse)AuthorAgeFilesLines
...
* Dubious new functions cxr/cyr.Kaz Kylheku2021-06-211-0/+2
| | | | | | | | | | | | | | * lib.c (cxr, cyr): New functions. * lib.h (cxr, cyr): Declared. * eval.c (eval_init): Intrinsics cxr and cyr registered. * tests/012/cadr.tl: New file. * txr.1: Documented. * share/txr/stdlib/doc-syms.tl: Updated.
* expander: bug: atoms in quasiliteral.Kaz Kylheku2021-06-151-0/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Via macros, atoms can sneak into a quasiliteral which then blow up because they get treated as strings without being converted. Example: (defmacro two () 2) `@(two)xyz` -> ;; error The expansion produces the invalid form, in which the 2 is subsequently treated as a string. (sys:quasi 2 "xyz") On the other hand, symbol macros don't have this problem: (defsymacro two 2) `@{two}xyz` -> "2xyz" The reason is that the (sys:var two) syntax will expand to (sys:var 2), and not 2. The straightforward, consistent fix is to ensure that the first case will also go to (sys:var 2). * eval.c (expand_quasi): If the expanded form is an atom which is not a bindable symbol, wrap it in a sys:var. * tests/012/quasi.tl: Test cases added. Also adding a compilation test for this file, cribbed from patmatch.tl.
* defsymacro: regression: don't expand replacement.Kaz Kylheku2021-06-151-12/+29
| | | | | | | | | | | | | | | | | | | | | | | | | | This is a regression that was introduced in 191. The change in 191 was trying to prevent defsymacro from being expanded immediately by the expander except in 190 compatibility. Unfortunately, this caused the whole defsymacro block not to be entered unless in 190 compatibility, otherwise taking the common exit which returns form_ex, containing the expanded replacement form. * eval.c (do_expand): Split up implementation of defvarl and defsymacro. In the defsymacro block, do not do any expanding on entry. Absent of compatibility mode, we just do some sanity checks and pass the entire form through. In 262 compatibility, we do the expansion to obtain form_ex. Then all the previous compat logic is wrapped in that block. * tests/011/macros-3.tl: Add a test case which confirms that symbol macros are lazily expanded. Weakness in the test suite is how these regressions creep in. * txr.1: Improve defsymacro documentation, spelling out clearly that the unexpanded replacement form is associated with the symbol. Eliminate obsolescent text suggesting that defsymacro is evaluated at macro time.
* errors: avoid premature release of deferred warnings.Kaz Kylheku2021-06-111-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | | We don't want to be unconditionally releasing deferred warnings when error exceptions occur in evaluation or compilation. The reason is that the error might be handled, for instance by a speculative expansion. Then unwanted noise occurs, because deferred warnings have been released prematurely. * eval.c (eval_exception): Do not call uw_release_deferred_warnings here. (error_trace): But do call uw_release_deferred_warnings here, before printing anything else. We want to preserve the behavior that when error information is actually being printed to a stream, any deferred warnings are dumped first because they might pertain to the error. (I may revisit this requirement; perhaps deferred warnings rarely, if ever, pertain to an error). * share/txr/stdlib/error.tl (compile-error): Do not dump deferred warnings unconditionally. Only dump them if we are also printing the error message to stderr. Secondly, do not output the error message at all, unless there is no handler for the error.
* lib: new function, fill-vec.Kaz Kylheku2021-06-081-0/+1
| | | | | | | | | | | | | | * eval.c (eval_init): Register fill-vec intrinsic. * lib.c (fill_vec): New function. * lib.h (fill_vec): Declared. * tests/010/vec.tl: New file. * txr.1: Documented. * share/txr/stdlib/doc-syms.tl: Updated.
* expander: expand must only ignores unbound warnings.Kaz Kylheku2021-06-071-1/+20
| | | | | | | | | | | | | | | | | | | The expand function must not muffle all deferred warnings. That causes the problem that a form like (inc var a.bar) fails to produce a warning due to bar not being the slot of any structure. The expand function must only muffle warnings about undefined functions and variables. * eval.c (muffle_unbound_warning): New static function. (no_warn_expand): Use muffle_unbound_warning as handler, rather than uw_muffle_warning. * tests/012/struct.tl: Fix two test cases here which test the expand function using a form that references a nonexistent slot. These now generate a warning, so we use the slot name b rather than d, which is defined. * txr.1: Documented change to expand.
* bugfix: do not expand defun body with name in scope.Kaz Kylheku2021-06-041-4/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This is a revert of November 2016 commit 606132c336dbeb0dd8bb851a64c97f2c11b76a85. The commit claims that it fixes a bug, but in fact it introduces one. There is no discussion in that commit about what motivated it. The commit which follows that one introduces a naivey-implemented diagnostic for catching unbound functions at macro-expansion time, so the likely motivation for this wrong fix was to suppress false positives from that naive diagnostic for recursive functions. That has long since been replaced by a better approach. Because of the bug, we cannot do this very useful thing: we cannot write an inline version of a funtion as a macro first, and then a real function which just calls that macro: (defmacro foo (arg) ...) (defun foo (arg) (foo arg)) The bug causes the (foo arg) call in this function not to be expanded, due to the shadowing. * eval.c (do_expand): When expanding defun, do not introduce the function's name as a lexical function binding, because it isn't one.
* json: functions put-json and put-jsonl.Kaz Kylheku2021-05-291-0/+2
| | | | | | | | | | | | | | | | | | | | | * eval.c (eval_init): Register put-json and put-jsonl intrinsics. * lib.c (out_json_str): Do not output the U+DC01 to U+DCFF code points by masking them and using put_byte. This is unnecessary; if we just send them as-is to the text stream, the UTF-8 encoder does that for us. (put_json, put_jsonl): New functions. * lib.h (put_json, put_jsonl): Declared. * txr.1: Documented. The bulk of tojson is moved under the descriptions of these new functions, and elsewhere where the document pointed to tojson for more information, it now points to put-json. More detailed description of character treatment is given. * share/txr/stdlib/doc-syms.tl: Updated.
* json: get-json function.Kaz Kylheku2021-05-281-0/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | * eval.c (eval_init): get-json intrinsic registered. * parser.c (prime_parser): Handle prime_json. (lisp_parse_impl): Take enum prime_parser argument directly instead of the interactive flag. (lisp_parse, nread, iread): Pass appropriate prime_parser value instead of the original flag. (get_json): New function. Like nread, but passes prime_json. * parser.h (enum prime_parser): New constant, prime_json. (get_json): Declared. * parser.l (prime_scanner): Handle prime_json. * parser.y (SECRET_ESCAPE_J): New terminal symbol. (spec): New productions around SECRET_ESCAPE_J for parsing JSON. * lex.yy.c.shipped, y.tab.c.shipped, y.tab.h.shipped: Updated. * txr.1: Documented. * share/txr/stdlib/doc-syms.tl: Updated.
* json: tojson function.Kaz Kylheku2021-05-281-0/+1
| | | | | | | | | | | | * eval.c (eval_init): tojson intrinsic registered. * lib.c (tojson): New function. * lib.h (tojson): Declared. * txr.1: Documented. * share/txr/stdlib/doc-syms.tl: Updated.
* eval: bugfix: expand keys in case{q,ql,qual}*Kaz Kylheku2021-05-211-2/+2
| | | | | | | * eval.c (me_case): When we evaluate the keys of a caseq, caseql* or casequal* construct, we must use expand_eval. I ran into this problem trying to use constants defined as symbol macros as keys.
* compiler: better code for global var definitions.Kaz Kylheku2021-05-141-4/+22
| | | | | | | | | | | | | | | | | | | | | | | | * eval.c (rt_defvarl): More accurate self string. (rt_defv): New static function: like rt_defvarl but ensures that the new variable has a binding cell, and returns that cell instead of the hash cell. (op_defvarl): Take advantage of rt_defv to not have to cons up the binding cell. (eval_init): Register sys:rt-defv intrinsic. * parser.c (read_file_common): Compiled files are now version 7, so we must recognize them. We still load version 6 files because rt:defvarl still exists for them. * share/txr/stdlib/compiler.tl (expand-defvarl): Improve the generated code in two ways. Firstly, use the new sys:rt-defv, which returns the binding cell, so that the value can be stored into it with rplacd without having to cons up anything. Secondly, if there is no value expression, don't emit the code to do the assignment. (%tlo-ver%): Bump compiled file version to (7 0). * txr.1: Add note about TXR 260 loading version 7 and 6.
* lib: basic support for trees as sequences.Kaz Kylheku2021-05-091-12/+18
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | As of this commit, binary search trees can be iterated: mapped over with mapcar and such. * arith.c (poly, rpoly): rpoly won't work with trees. They work just with vectors and lists so let's make the error message more accurate. I noticed the self names of these two are swapped; will fix in another commit. * eval.c (tprint): Refactor to use iterator framework for objects other than lists. The tree case falls into this, so trees are supported. * lib.h (enum seq_kind): New enum constant SEQ_TREELIKE. (seq_iter_init_with_info): Declared. * lib.c (seq_info): Map tree object to SEQ_TREELIKE type. (seq_iter_get_tree, seq_iter_peek_tree): New static functions. (seq_iter_rewind): Support rewinding tree iteration. I think we could reuse the existing iterator here, and in the hash case as well. I made a note to look into this. (seq_iter_init_with_info): Internal linkage changed to external, because tprint in eval.c uses this. Handle SEQ_TREELIKE case here, by setting up iterator with the two new static functions. (seq_iter_mark): Handle SEQ_TREELIKE_CASE. Change switch statement to exhaustively list cases. (ldiff): Add SEQ_TREELIKE to various cases. Idea is that we handle it like SEQ_HASH. (nsort, sort, nshuffle, take, take_while, take_until, drop_while, drop_until, update): Add case for SEQ_TREELIKE, routing to error message. (lazy_where_tree_func): New static function. (where, sel, reject): Support trees.
* mapcar*: fix broken.Kaz Kylheku2021-04-291-1/+1
| | | | | | | | | | * eval.c (lazy_mapcar_func): We must capture the return value of iter_step, since we refer to it in the next statement, expecting it to have stepped. This bug causes a behavior as if the original list had an extra nil. * tests/012/lazy.tl: Tests. Poor test coverage is why this sort of thing comes up and bites us.
* macros: lexical-var-p: don't report t for specials.Kaz Kylheku2021-04-281-8/+30
| | | | | | | | | | | | | | | | | | | | The lexical-var-p function wrongly reports true for locally rebound special variables, which are not lexical. * eval.c (special_var_p): Static function moved to avoid forward declaration. (lexical_var_p): Bail if sym satisfies special_var_p. (old_lexical_var_p): New function, copy of old lexical_var_p before this bugfix. (eval_init): Conditionally register lexical-var-p as either lexical_var_p or old_lexical_var_p depending on the compat value. * txr.1: Update documentation for lexical-var-p to clarify that it doesn't report true for specials. Also make note that it doesn't report true for global lexicals, and likewise that lexical-fun-p doesn't report global functions. Added compat note.
* compile/eval: new operator, mac-env-param-bind.Kaz Kylheku2021-04-211-3/+37
| | | | | | | | | | | | | | | | | | | | | | mac-env-param-bind is like mac-param-bind but also allows the value for the :env parameter to be specified. * eval.c (op_mac_env_param_bind_s): New sy mbol variable. (op_mac_env_param_bind): New static function. (do_expand): Handle mac_env_param_bind_s. (eval_init): Initialize symbol variable and register macro. * share/txr/stdlib/compiler.tl (compiler compile): Add case for mac-env-param-bind. (compiler comp-mac-env-param-bind): New method. * share/txr/stdlib/doc-syms.tl: Updated with new hashes for tree-bind and mac-param-bind, and inclusion of mac-env-param-bind. * tests/012/binding.tl: New file. * txr.1: Documented.
* expander: fun: misleading diagnostic.Kaz Kylheku2021-03-281-1/+1
| | | | | * eval.c (do_expand): argument of fun is not in "operator position"; fixed wording.
* compile/eval: more standard formatting for diags.Kaz Kylheku2021-03-271-4/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This patch eliminates parentheses from the error messages, as well as a leading ./ being added to relative paths. The word "warning: " is moved into the error message, so that it does not appear before the location. Example, when doing (compile-file "path/to/foo.tl"). Before patch: warning: (./path/to/foo.tl:37): unbound function foo After: path/to/foo.tl:37: warning: unbound function foo Now when I compile out of Vim, it nicely jumps to errors in Lisp code. * eval.c (eval_exception): Drop parentheses from error location, add colon. (eval_warn): Prepend "warning: " to format string. (eval_defr_warn): Drop parentheses from location, and prepend "warning: " to format string. * parser.c (repl-warning): Drop "warning:" prefix. * share/txr/stdlib/compiler.tl (open-compile-streams): Do not do parent substitution for relative paths if the parent path is the empty string "", to avoid inserting ./ onto relative paths in that case. * share/txr/stdlib/error.tl (sys:loc): Drop parentheses and space from location. (compile-error) Separate location with colon and space. (compile-warning, compile-defr-warning): Likewise and add "warning: " prefix. * unwind.c (uw_rthrow): Drop "warning: " prefix. (uw_warningf): Add "warning: " prefix. (uw_dump_deferred_warnings): Drop "warning: " prefix.
* lib: new functions join, join-with.Kaz Kylheku2021-03-091-1/+6
| | | | | | | | | | | | | | | | | | | | | | | | | That old cat-str function is often a pain, requiring the pieces as a list. We have a sys:fmt-join that is undocumented. That functions is now exposed as usr:join, and documented. Also introducing join-with that takes a separator as the leftmost argument. Thus (op join-with "::") gives us a function that joins pieces with :: in between. * eval.c (eval_init): Regiser fmt_join function under join symbol also. Register join-with. * lib.c (join_with): New function. (fmt_join): Now a wrapper for join_with that passes a nil separator. * lib.h (join_with): Declared. * share/txr/stdlib/optimize.tl (basic-blocks join-blocks): Rename the local function join, which now triggers a warning about a standard function being redefined. * txr.1: Redocumented cat-str, and documented join-with and join.
* expander: improve diagnosis of invalid dotted syntax.Kaz Kylheku2021-02-181-17/+33
| | | | | | | | | | * eval.c (dotted_form_error): Use eval_error instead of throwing direcly, so the error message has location info and consistent formatting. (expand_forms, expand_forms_ss, expand_forms_lisp1): Check for the dotting error one level above, at the cons cell. The cons cell will have line number information attached to it for a better error message.
* compiler: eliminate block from recursive functions.Kaz Kylheku2021-02-121-3/+5
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The block elimination logic doesn't work for self-recursive functions, even if they invoke no block returning, and use only system functions that don't have anything to do with block returns. This is because the recursive call is not recognized, and treated as a call to an unknown function. Let's put in a simple hack. The defun and defmacro operators will use a new secret special operator called sys:blk instead of block to generate the block. The compilation of sys:blk will assume that (sys:blk name ...) is only used in a defun or defmacro by that same name, and include name in the list of OK functions. So that functions created using the interpreter and then dynamically compiled will also benefit, we add this operator to the interpreter. * eval.c (sys_blk_s): New symbol variable. (op_defun): For defun and defmacro, use sys:blk for the block for the block (eval_init): Initialize sys_blk_s with the interned symbol sys:blk. Register the sys:blk operator. * share/txr/stdlib/compiler.tl (compiler compile): Recognize the sys:blk special form and handle via comp-block. (comp-block): If sys:blk is being compiled, then include the block name in the list of functions that do not perform block returns. (If this is false, other checks will fail before use that.) (expand-defun): Use sys:blk for defun and defmacro.
* maprod, maprend: correct self name.Kaz Kylheku2021-01-151-2/+2
| | | | | | * eval.c (maprodv, maprendv): These functions implement maprod and maprend; the v suffix is just in the C code and must not be part of the self name.
* mapcar/maprod: show-stopper bug.Kaz Kylheku2021-01-151-2/+6
| | | | | | | | | | | | | | | | | | | | | | | | Observed wrong result: (mapcar (lambda (. args) (list . args)) '#(1 2 3) '#(4 5 6)) -> #((1 4) nil nil) Correct result: -> #((1 4) (2 5) (3 6)) This is not specific to vector input; it's broken for sequences of all types. Functions affected are mapcar, mapf, mappend, mapdo, maprod, maprend, maprodo. * eval.c (map_common, prod_common): Because we reuse the args structure across iterations, we must reinitialize the fill and list members. These can be modified by the functionw which is called. In particular, the arguments are applied, they may be turned into a list (fill decrements to zero, and a list is produced).
* Copyright year bump 2021.Kaz Kylheku2021-01-141-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * METALICENSE: 2020 copyrights bumped to 2021. Added note about SHA-256 routines from Colin Percival. * LICENSE, LICENSE-CYG, Makefile, alloca.h, args.c, args.h, arith.c, arith.h, buf.c, buf.h, cadr.c, cadr.h, chksum.c, chksum.h, chksums/crc32.c, chksums/crc32.h, combi.c, combi.h, configure, debug.c, debug.h, eval.c, eval.h, ffi.c, ffi.h, filter.c, filter.h, ftw.c, ftw.h, gc.c, gc.h, glob.c, glob.h, hash.c, hash.h, itypes.c, itypes.h, jmp.S, lex.yy.c.shipped, lib.c, lib.h, linenoise/linenoise.c, linenoise/linenoise.h, lisplib.c, lisplib.h, match.c, match.h, parser.c, parser.h, parser.l, parser.y, protsym.c, rand.c, rand.h, regex.c, regex.h, share/txr/stdlib/asm.tl, share/txr/stdlib/awk.tl, share/txr/stdlib/build.tl, share/txr/stdlib/cadr.tl, share/txr/stdlib/compiler.tl, share/txr/stdlib/conv.tl, share/txr/stdlib/copy-file.tl, share/txr/stdlib/debugger.tl, share/txr/stdlib/defset.tl, share/txr/stdlib/doloop.tl, share/txr/stdlib/each-prod.tl, share/txr/stdlib/error.tl, share/txr/stdlib/except.tl, share/txr/stdlib/ffi.tl, share/txr/stdlib/getopts.tl, share/txr/stdlib/getput.tl, share/txr/stdlib/hash.tl, share/txr/stdlib/ifa.tl, share/txr/stdlib/keyparams.tl, share/txr/stdlib/op.tl, share/txr/stdlib/package.tl, share/txr/stdlib/param.tl, share/txr/stdlib/path-test.tl, share/txr/stdlib/place.tl, share/txr/stdlib/pmac.tl, share/txr/stdlib/quips.tl, share/txr/stdlib/save-exe.tl, share/txr/stdlib/socket.tl, share/txr/stdlib/stream-wrap.tl, share/txr/stdlib/struct.tl, share/txr/stdlib/tagbody.tl, share/txr/stdlib/termios.tl, share/txr/stdlib/trace.tl, share/txr/stdlib/txr-case.tl, share/txr/stdlib/type.tl, share/txr/stdlib/vm-param.tl, share/txr/stdlib/with-resources.tl, share/txr/stdlib/with-stream.tl, share/txr/stdlib/yield.tl, signal.c, signal.h, socket.c, socket.h, stream.c, stream.h, struct.c, struct.h, strudel.c, strudel.h, sysif.c, sysif.h, syslog.c, syslog.h, termios.c, termios.h, time.c, time.h, tree.c, tree.h, txr.1, txr.c, txr.h, unwind.c, unwind.h, utf8.c, utf8.h, vm.c, vm.h, vmop.h, win/cleansvg.txr, y.tab.c.shipped: Copyright year bumped to 2021.
* progn, prog1, prog2: now also functions.Kaz Kylheku2021-01-011-0/+19
| | | | | | | | | | | | * eval.c (progn_fun, prog1_fun, prog2_fun): New static functions. (eval_init): Wire progn, prog1 and prog2 function bindings to new functions. * txr.1: Documented. * checkman.txr (check-func): Recognize Macro/function and Operators/functions heading.
* New macro: prog2Kaz Kylheku2021-01-011-1/+14
| | | | | | | | | | | | * eval.c (prog2_s): New symbol variable. (me_prog2): New macro expander function. (eval_init): Initialize prog2_s variable with interned symbol. Register prog2 macro expander. * txr.1: Maintain the documentation for progn and prog1, improving the wording and adding a dialect note . Document prog2.
* eval: use symbol vars for registering if, and or.Kaz Kylheku2021-01-011-3/+3
| | | | | * eval.c (eval_init): Use if_s, or_s, and_s instead of wastefully calling intern.
* shuffle/nshuffle: take optional random state argument.Kaz Kylheku2020-12-291-2/+2
| | | | | | | | | | | | | * eval.c (eval_init): Register shuffle and nshuffle as two-argument functions with optional argument. * lib.c (nshuffle): Take random-state argument, defaulting to value of random_state special variable. (shuffle): Take random-state argument, pass down to nshuffle. * lib.h (shuffle, nshuffle): Declarations updated. * txr.1: Updated.
* txr, eval: eliminate some func_n1 calls.Kaz Kylheku2020-12-101-2/+2
| | | | | | | | | * match.c (do_output_line, do_repeat, v_deffiler): Replace func_n1(cdr) and func_n1(rest) with cdr_f. * eval.c (eval_init): Replace func_n1(car) and func_n1(cdr) with car_f and cdr_f. Should have been done in 2011 when this was done for the registrations of car and cdr.
* mapcar: regression: not not converting to left typeKaz Kylheku2020-10-101-1/+2
| | | | | | * eval.c (map_common): Save the leftmost arg in a local variable, and refer to that in the make_like call. The bug here is that the args get zapped to nil.
* time: move time functions out of lib.c into time.c.Kaz Kylheku2020-10-071-14/+0
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * Makefile (OBJS): Add new time.o. * eval.c (eval_init): Registration of time functions is removed from here; it is done in time_init now, in time.c. * hash.c: Must #include "time.h" now. * lib.c (time_s, time_local_s, time_utc_s, time_string_s, time_parse_s, year_s, month_s, day_s, hour_s, min_s, sec_s, dst_s, gmtoff_s, zone_s): Variable definitions removed. These are now in time.c. Also declared in time.h. (time_sec, time_sec_usec, gmtime_r, localtime_r, string_time, time_string_local, time_string_utc, broken_time_list, tm_to_time_struct, broken_time_struct, time_fields_local, time_fields_utc, time_struct_local, time_struct_utc, time_fields_to_tm, time_struct_to_tm, make_time_impl, make_time, epoch_tm, strptime_wrap, time_parse, setenv, unsetenv, timegm_hack, make_time_utc, time_meth, time_string_meth, time_parse_meth, time_parse_local, time_parse_utc): Functions removed. These are now in time.c. (time_init): Removed, and now in time.c as an external function. * lib.h (time_sec, time_sec_usec, time_string_local, time_string_utc, time_fields_local, time_fields_utc, time_struct_local, time_struct_utc, make_time, make_time_utc, time_parse, time_parse_local, time_parse_utc): Declarations removed. Now in time.h. * rand.c: Must #include "time.h" now. * time.c: New file. * time.h: New file.
* tags: address small issue with tag lookup.Kaz Kylheku2020-09-011-4/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Exuberant Ctags uses the full content of one line as the key to find a tag. A function declaration that is split into multiple lines can have a first line which is identical to the definition, as in: static int add(int a, int b); static int add(int a, int b) { return a + b; } Here, the search key which ctags uses for the add function is "static int add(int a,", taken from the definition. But it's exactly the same as a the first line of the declaration, and that is what Vim jumps to for that tag. A few function declarations in TXR have this issue. * eval.c (expand_params_rec, do_eval): Make the first line of the forward declaration different from the first line of the definition. * match.c (mf_all): Likewise. * struct.c (make_struct_type_compat): Likewise.
* New function: reject.Kaz Kylheku2020-09-011-0/+1
| | | | | | | | | | | * eval.c (eva_init): Register reject intrinsic. * lib.c (appendl): New static function. (reject): New function. * lib.h (reject): Declared. * txr.1: Documented.
* txr: repeat ferrets out Lisp-embedded vars.Kaz Kylheku2020-08-171-1/+1
| | | | | | | | | | | | | | | Gone is the need for :vars to inform @(repeat)/@(rep) about variable references buried in Lisp. * eval.c (expand_with_free_refs): Change to external linkage. * eval.h (expand_with_free_refs): Declared. * parser.y (extract_vars): Handle sys:expr forms, which are embedded Lisp via expand_with_free_refs to uncover their free variables. * txr.1: Redocumented this area.
* Change noreturn to NORETURN.Kaz Kylheku2020-08-071-3/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The noreturn macro is respelled to harmonize with the upper-case INLINE and NOINLINE. * lib.h (noreturn): Rename to NORETURN. * arith.c (not_number, not_integer, invalid_ops, invalid_op): Declaration updated. * arith.c (do_mp_error): Likewise. * eval.c (eval_error, no_bindable_error, dotted_form_error): Likewise. * eval.h (eval_error): Likewise. * lib.c (unsup_obj, callerror, wrongargs): Likewise. * match.c (sem_error): Likewise. * stream.c (unimpl, unimpl_put_string, unimpl_put_char, unimpl_put_byte, unimpl_get_line, unimpl_get_char, unimpl_get_byte, unimpl_unget_char, unimpl_unget_byte, unimpl_put_buf, unimpl_fill_buf, unimpl_seek, unimpl_truncate, unimpl_get_sock_family, unimpl_get_sock_type, unimpl_get_sock_peer, unimpl_set_sock_peer): Likewise. * struct.c (no_such_struct, no_such_slot, no_such_static_slot): Likewise. * unwind.h (jmp_restore, uw_throw, uw_throwf, uw_errorf, uw_errorfv, type_mismatch): Likewise.
* New sspl function.Kaz Kylheku2020-07-221-0/+1
| | | | | | | | | | | * eval (eval_init): Register sspl, an argument-reversed interface to split-str-set. * lib.c (sspl): New function. * lib.h (sspl): Declared. * txr.1: Documented.
* Support weak semantics in symbol packages.Kaz Kylheku2020-07-121-2/+2
| | | | | | | | | | | | | | | | | | | | | A package is weak if it holds weak references to symbols, meaning that if there are no references to a symbol other than its entry in a weak package, it can be removed from the package and reclaimed by the garbage collector. * eval.c (eval_init): Update registrations for make-package and sys:make-anon-package to reflect new optional argument. * lib.c (make_package_common): New argument weak. If it is true then both the hashes will have weak values. (make_package, make_anon_package): New optional argument weak. (obj_init): Add nil argument to calls to make_package. All the standard packages are regular, not weak. * lib.h (make_package, make_anon_package): Declarations updated. * txr.1: Documented.
* listener: new *-1, *-2 ... *-20 macros.Kaz Kylheku2020-07-111-1/+1
| | | | | | | | | | | | * arith.h (minus_s): Declared. * eval.c (reg_symacro): Changing to external linkage. * eval.h (macro_time_s, reg_symacro): Declared. * parser.c (repl): Bind the *-1 to *-20 symbol macros. * txr.1: Documented.
* New function: iterable.Kaz Kylheku2020-07-021-0/+1
| | | | | | | | | | | | * eval.c (eval_init): Register iterable intrinsic. * lib.c (seq_iterable): New static function. (nullify): Use seq_iterable to simplify function. (iterable): New function. * lib.h (iterable): Declared. * txr.1: Documented.
* c_num: now takes self argument.Kaz Kylheku2020-06-291-12/+16
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The c_num and c_unum functions now take a self argument for identifying the calling function. This requires changes in a large number of places. In a few places, additional functions acquire a self argument. The ffi module has the most extensive example of this. Some functions mention their name in a larger string, or have scattered literals giving their name; with the introduction of the self local variable, these are replaced by references to self. In the following changelog, the notation TS stands for "take self argument", meaning that the functions acquires a new "val self" argument. The notation DS means "define self": the functions in question defines a self variable, which they pass down. The notation PS means that the functions pass down an existing self variable to functions that now require it. * args.h (args_count): TS. * arith.c (c_unum, c_num): TS. (toint, exptv): DS. * buf.c (buf_check_len, buf_check_alloc_size, buf_check_index, buf_do_set_len, replace_buf, buf_put_buf, buf_put_i8, buf_put_u8, buf_put_char, buf_put_uchar, buf_get_bytes, buf_get_i8, buf_get_u8, buf_get_cptr, buf_strm_get_byte_callback, buf_strm_unget_byte, buf_swap32, str_buf, buf_int, buf_uint, int_buf, uint_buf): PS. (make_duplicate_buf, buf_shrink, sub_buf, buf_print, buf_pprint): DS. * chskum.c (sha256_stream_impl, sha256_buf, crc32_buf, md5_stream_impl, md5_buf): TS. (chksum_ensure_buf, sha256_stream, sha256, sha256_hash, md5_stream, md5, md5_hash): PS. (crc32_stream): DS. * combi.c (perm_while_fun, perm_gen_fun_common, perm_str_gen_fun, rperm_gen_fun, comb_vec_gen_fun, comb_str_gen_fun, rcomb_vec_gen_fun, rcomb_str_gen_fun): DS. * diff.c (dbg_clear, dbg_set, dbg_restore): DS. * eval.c (do_eval, gather_free_refs, maprodv, maprendv, maprodo, do_args_apf, do_args_ipf): DS. (op_dwim, me_op, map_common): PS. (prod_common): TS. * ffi.c (struct txr_ffi_type): release member TS. (make_ffi_type_pointer): PS and release argument TS. (ffi_varray_dynsize, ffi_array_in, ffi_array_put_common, ffi_array_get_common, ffi_varray_in, ffi_varray_null_term): PS. (ffi_simple_release, ffi_ptr_in_release, ffi_struct_release, ffi_wchar_array_get, ffi_array_release_common, ffi_array_release, ffi_varray_release): TS. (ffi_float_put, double_put, ffi_be_i16_put, ffi_be_u16_put, ffi_le_i16_put, ffi_le_u16_put, ffi_be_i32_put, ffi_be_u32_put, ffi_le_i32_put, ffi_sbit_put, ffi_ubit_put, ffi_buf_d_put, make_ffi_type_array, make_ffi_type_enum, ffi_type_compile, make_ffi_type_desc, ffi_make_call_desc, ffi_call_wrap, ffi_closure_dispatch_save, ffi_put_into, ffi_in, ffi_get, ffi_put, carray_set_length, carray_blank, carray_buf, carray_buf_sync, carray_cptr, carray_refset, carray_sub, carray_replace, carray_uint, carray_int): PS. (carray_vec, carray_list): DS. * filter.c (url_encode, url_decode, base64_stream_enc_impl): DS. * ftw.c (ftw_callback, ftw_wrap): DS. * gc.c (mark_obj, gc_set_delta): DS. * glob.c (glob_wrap): DS. * hash.c (equal_hash, eql_hash, eq_hash, do_make_hash, hash_equal, set_hash_traversal_limit, gen_hash_seed): DS. * itypes.c (c_i8, c_u8, c_i16, c_u16, c_i32, c_u32, c_i64, c_u64, c_short, c_ushort, c_int, c_uint, c_long, c_ulong): PS. * lib.c (seq_iter_rewind): TS and becomes internal. (seq_iter_init_with_info, seq_setpos, replace_str, less, replace_vec, diff, isec, obj_print_impl): PS. (nthcdr, equal, mkstring, mkustring, upcase_str, downcase_str, search_str, sub_str, cat_str, scat2, scat3, fmt_join, split_str_keep, split_str_set, trim_str, int_str, chr_int, chr_str, chr_str_set, vector, vecref, vecref_l, list_vec, copy_vec, sub_vec, cat_vec, lazy_str_put, lazy_str_gt, length_str_ge, length_str_lt, length_str_le, cptr_size_hint, cptr_int, out_lazy_str, out_quasi_str, time_string_local_time, time_string_utc, time_fields_local_time, time_fields_utc, time_struct_local, time_struct_utc, make_time, time_meth, time_parse_meth): DS. (init_str, cat_str_init, cat_str_measure, cat_str_append, vscat, time_fields_to_tm, time_struct_to_tm, make_time_impl): TS. * lib.h (seq_iter_rewind): Declaration removed. (c_num, c_unum, init_str): Declarations updated. * match.c (LOG_MISMATCH, LOG_MATCH): PS. (h_skip, h_coll, do_output_line, do_output, v_skip, v_fuzz, v_collect): DS. * parser.c (parser, circ_backpatch, report_security_problem, hist_save, repl, lino_fileno, lino_getch, lineno_getl, lineno_gets, lineno_open): DS. (parser_set_lineno, lisp_parse_impl): PS. * parser.l (YY_INPUT): PS. * rand.c (make_random_state): PS. * regex.c (print_rec): DS. (search_regex): PS. * signal.c (kill_wrap, raise_wrap, get_sig_handler, getitimer_wrap, setitimer_wrap): DS. * socket.c (addrinfo_in, sockaddr_pack, fd_timeout, to_connect, open_sockfd, sock_mark_connected, sock_timeout): TS. (getaddrinfo_wrap, dgram_set_sock_peer, sock_bind, sock_connect, sock_listen, sock_accept, sock_shutdown, sock_send_timeout, sock_recv_timeout, socketpair_wrap): DS. * stream.c (generic_fill_buf, errno_to_string, stdio_truncate, string_out_put_string, open_fileno, open_command, base_name, dir-name): DS. (unget_byte, put_buf, fill_buf, fill_buf_adjust, get_line_as_buf, formatv, put_byte, test_set_indent_mode, test_neq_set_indent_mode, set_indent_mode, set_indent, inc_indent, set_max_length, set_max_depth, open_subprocess, run ): PS. (fds_subst, fds_swizzle): TS. * struct.c (make_struct_type, super, umethod_args_fun): PS. (method_args_fun): DS. * strudel.c (strudel_put_buf, strudel_fill_buf): DS. * sysif.c (errno_wrap, exit_wrap, usleep_wrap, mkdir_wrap, ensure_dir, makedev_wrap, minor_wrap, major_wrap, mknod_wrap, mkfifo_wrap, wait_wrap, wifexited, wexitstatus, wifsignaled, wtermsig, wcoredump, wifstopped, wstopsig, wifcontinued, dup_wrap, close_wrap, exit_star_wrap, umask_wrap, setuid_wrap, seteuid_wrap, setgid_wrap, setegid_wrap, simulate_setuid_setgid, getpwuid_wrap, fnmatch_wrap, dlopen_wrap): DS. (chmod_wrap, do_chown, flock_pack, do_utimes, poll_wrap, setgroups_wrap, setresuid_wrap, setresgid_wrap, getgrgid_wrap): PS. (c_time): TS. * sysif.h (c_time): Declaration updated. * syslog.c (openlog_wrap, syslog_wrap): DS. * termios.c (termios_pack): TS. (tcgetattr_wrap, tcsetattr_wrap, tcsendbreak_wrap, tcdrain_wrap, tcflush_wrap, tcflow_rap, encode_speeds, decode_speeds): DS. * txr.c (compato, array_dim, gc_delta): DS. * unwind.c (uw_find_frames_by_mask): DS. * vm.c (vm_make_desc): PS. (vm_make_closure, vm_swtch): DS.
* New function: maprodo.Kaz Kylheku2020-06-281-0/+12
| | | | | | | | | | maprodo is like maprod, but doesn't collect or return anything. It's the Cartesian product analog of mapdo. * eval.c (collect_nothing, maprodo): New static functions. (eval_init): Register maprodo intrinsic. * txr.1: Documented.
* New functions: list-seq, ved-seq and str-seq.Kaz Kylheku2020-06-281-0/+3
| | | | | | | | | | | | | | These functions convert any iterable to a list, vector or string. * eval.c (eval_init): Registered list-seq, vec-seq and str-seq intrinsics. * lib.c (list_seq, vec_seq, str_seq): New functions. * lib.h (list_seq, vec_seq, str_seq): Declared. * txr.1: Documented.
* each: fix (each ()) segfault.Kaz Kylheku2020-06-061-4/+5
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The (each ()) form should infinitely loop, and the compiled version does. The interpreter crashes, when that is a top-level form. The reason is that the underlying sys:each-op operator uses an empty list of variable names as an indication to use the bindings from the parent lexical environment. And in that particular case, the let is also empty. The whole thing looks like: (let () (sys:each-op each nil)) If this is a top-level expression, then op_let receives a null environment pointer. Since it has no bindings to add, it doesn't extend the environment chain and passes a null environment pointer down to op_each, which that tries to use, because it's told to reach into it for bindings. Let's use the t symbol for that instead, so then the above would look like: ;; the t and only the t means "access parent env" (let () (sys:each-op each t)) And then, let's also fix it so that t is never used in this case when there are no vars: ;; no t, and so don't access parent env. (let () (sys:each-op each nil)) * eval.c (op_each): Get the bindings from the parent environment if vars is t, rather than when it's null. (me_each): When the symbols are not being inserted into the sys:each-op form, then insert t to indicate that, rather than nil. If the source form specifies an empty list of bindings, then insert nil, not t. * share/txr/stdlib/compiler.tl (expand-each): Get the list of variable names from the parent lexical environment when vars is t, rather than when it's null.
* mapcar/maprod: fix stack overflow regression.Kaz Kylheku2020-06-051-6/+5
| | | | | | | | | | | | The recent refactoring of the mapping functions to use stack-allocated iterators has a bug. args_decl occurs inside a loop. But args_decl uses alloca, which doesn't dispose of the memory when the block scope terminates. * eval.c (map_common, prod_common): Move the declaration of args_fun outside of the loop, so that it is allocated just once. The loop just stuffs fresh sets of values into the arguments.
* mapping: rewrite loop using seq_info and args.Kaz Kylheku2020-06-041-19/+27
| | | | | | | | | | | | | | | * eval.c (map_common): Do not extract the arguments as a list. Do not produce a list of iterator objects. Instead, allocate an array of seq_iter_t objects on the stack using alloca, and use these for walking the input lists in parallel. Do not cons a list of the tuples coming from the lists, but rather store the tuples into a struct args, also on the stack, and invoke the function with that. Now, the only heap memory we allocate is the resulting list being accumulated. In the case of mapdo, no heap allocation takes place. However, if some of the inputs are hashes, then hash iterators get allocated in seq_iter_init. (mapcarv, mappendv, mapdov): Pass self argument to map_common, needed for seq_iter_init.
* mapcar, mappend, mapdo: merge implementations.Kaz Kylheku2020-06-041-60/+20
| | | | | | * eval.c (map_common): New static function. (mapcarv, mappendv, mapdov): Now one-line wrappers for map_common.
* maprod: bugfix: not reducing to mapcar.Kaz Kylheku2020-06-041-5/+6
| | | | | | | | | | | The one list case of maprod reduces to mappend rather than mapcar, so that [maprod identity '(1 2 3)] fails instead of producing (1 2 3). * eval.c (prod_common): Take pointer to mapping function to use in one-list case, and use it. (maprodv): Pass mapcarv to prod_common. (maprendv): Pass mappendv to prod_common.
* Convert mapping functions to new iterators.Kaz Kylheku2020-06-031-57/+63
| | | | | | | | | | | | | | | | | * eval.c (get_iter_f): Renamed to iter_from_binding_f. (iter_begin_f, iter_more_f, iter_item_f, iter_step_f): New global variables. (op_each): Follow rename of get_iter_f. (mapcarv, mappendv, lazy_mapcar_func, lazy_mapcar, lazy_mapcarv_func, lazy_mapcarv, mapdov, prod_common): Convert from car/cdr/null-test iteration to iter-begin. (eval_init): gc-protect and initialize new variables. * lib.c (mapcar_listout, mappend, mapdo): Convert to seq_iter iteration. List argument renamed to seq. (mapcar): List argument renamed to seq. * lib.h: Declarations updated with renamed arguments.
* Convert each-family operators to use iter-begin.Kaz Kylheku2020-06-021-10/+11
| | | | | | | | | | | | | | | | | | | With this change we can do (each ((x vec)) ...) with reasonable efficiency, because we are no longer marching through the vector with cdr, copying the suffix. * eval.c (get_iter_f): New global variable. (op_each): Obtain iterators for all the objects with iter_begin, instead of treating them as lists. Probe the iterators for termination with iter_more, get the items with iter_item instead of car and step with iter_step instead of cdr. (eval_init): gc-protect the get_iter_f function and initialize it. * share/txr/stdlib/compiler.tl (expand-each): Replace the car/cdr and null testing with iter-init, iter-more, iter-item and iter-step.
* New style iteration functions.Kaz Kylheku2020-06-021-0/+5
| | | | | | | | | | | | | | | | | | | | | | | | iter-begin provides a paradigm for iteration that is more compatible with lists. If the sequence is a list, then the list itself is returned as the iterator, and the other functions are basicaly wrappers for car/cdr and null testing. Yet the API is defined in such a way that other objects can be iterated with good efficiency, at the cost of allocating a new iterator object (which can be re-used). * eval.c (eval_init): Register iter-begin, iter-more, iter-item, iter-step and iter-reset. * lib.c (seq_iter_init_with_info): New static function. (seq_iter_init): Now a thin wrapper for seq_iter_init_with_info. (iter_begin, iter_more, iter_item, iter_step, iter_reset): New functions. * lib.h (iter_begin, iter_more, iter_item, iter_step, iter_reset): New functions. * txr.1: Documented.