summaryrefslogtreecommitdiffstats
path: root/match.c
Commit message (Collapse)AuthorAgeFilesLines
* lookup_var: don't pass dyn_env explicitly.Kaz Kylheku2021-09-031-1/+1
| | | | | | | | | | | | | Since lookup_var(nil, ...) skips the environment and goes for dyn_env, there is no need to pass dyn_env explicitly; it's a bit of an anti-pattern. The argument is intended for lexical scopes. * eval.c (eval_exception, expand_eval, load): Pass nil to lookup_var instead of the current dynamic environment. * match.c (v_load): Likewise. * parser.c (txr_parse, read_eval_ret_last): Likewise.
* load: new *load-hooks* feature.Kaz Kylheku2021-09-021-1/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | *load-hooks* lets a .txr, .tl or .tlo file specify actions to be taken when the loading of that file completes, whether normally or via an exception. They are also honored by process exit. For instance, with this, we can have a Lisp file that behaves like a script which cleans up after itself (e.g. removing temporary files) even if it is not run as a stand-alone program, but invoked via (load ...). Because it's not a stand-alone program, it cannot simply use the at-exit-call mechanism. The unwind-protect operator could be used, but it's inconvenient because it protects a single form. The *load-hooks* feature in effect protects all the top level forms of a load, similarly to unwind-protect. Also, unwind-protect does not guard against a process exit. (However, *load-hooks* does not guard against an abnormal exit, only normal termination). * eval.c (load_hooks_s): New symbol variable. (run_load_hooks): New function. (run_load_hooks_atexit): New static function. (load): bind *load-hooks* to nil around load. Implement the hooks processing via run_load_hooks, taking care to pass the load-time dynamic environment that has already been undone. (eval_init): Initialize load_hooks_s and register the *load-hooks* variable. Register run_load_hooks_atexit with atexit, so the current value of *load-hooks* is processed on process exit. * eval.h (load_hooks_s, run_load_hooks): Declared. * match.c (v_load): Similar changes as in load. * txr.c (txr_main): Run the load hooks with run_load_hooks immediately after processing the .txr or .tl file, before entering the listener. * tests/019/load-hook.tl: New directory and file * tests/load-hook.tl: New file. * txr.1: Documented. * stdlib/doc-syms.tl: Updated.
* license: reformat to fit 80 columns.Kaz Kylheku2021-08-161-12/+13
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * Makefile, alloca.h, args.c, args.h, arith.c, arith.h, buf.c, buf.h, chksum.c, chksum.h, chksums/crc32.c, chksums/crc32.h, combi.c, combi.h, 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, lib.c, lib.h, lisplib.c, lisplib.h, match.c, match.h, parser.c, parser.h, parser.l, parser.y, rand.c, rand.h, regex.c, regex.h, signal.c, signal.h, socket.c, socket.h, stdlib/asm.tl, stdlib/awk.tl, stdlib/build.tl, stdlib/compiler.tl, stdlib/constfun.tl, stdlib/conv.tl, stdlib/copy-file.tl, stdlib/debugger.tl, stdlib/defset.tl, stdlib/doloop.tl, stdlib/each-prod.tl, stdlib/error.tl, stdlib/except.tl, stdlib/ffi.tl, stdlib/getopts.tl, stdlib/getput.tl, stdlib/hash.tl, stdlib/ifa.tl, stdlib/keyparams.tl, stdlib/match.tl, stdlib/op.tl, stdlib/optimize.tl, stdlib/package.tl, stdlib/param.tl, stdlib/path-test.tl, stdlib/pic.tl, stdlib/place.tl, stdlib/pmac.tl, stdlib/quips.tl, stdlib/save-exe.tl, stdlib/socket.tl, stdlib/stream-wrap.tl, stdlib/struct.tl, stdlib/tagbody.tl, stdlib/termios.tl, stdlib/trace.tl, stdlib/txr-case.tl, stdlib/type.tl, stdlib/vm-param.tl, stdlib/with-resources.tl, stdlib/with-stream.tl, stdlib/yield.tl, 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.c, txr.h, unwind.c, unwind.h, utf8.c, utf8.h, vm.c, vm.h, vmop.h: License reformatted. * lex.yy.c.shipped, y.tab.c.shipped, y.tab.h.shipped: Updated.
* lazy-stream-cons: control close throwing behavior.Kaz Kylheku2021-08-071-5/+6
| | | | | | | | | | | | | | | | | | | | | | | | | * eval.c (eval_init): Update registrations of lazy-stream-cons and get-lines with one more optional argument. * lib.c (simple_lazy_stream_func_nt, lazy_stream_func_nt): New static functions. (lazy_stream_cons): Take a new argument, no_throw_close, defaulting it to nil. When calling close_stream directly, pass the inverted value of no_throw_close. Choose the new _nt functions for the lazy list if no_throw_close is true; those functions pass nil as the second argument of close_stream. * lib.h (lazy_stream_cons): Declaration updated. * match.c (v_next_impl, open_data_source, match_fun): Pass down the nothrow value to lazy_stream_cons, or else nil in situations when that is not applicable or there is no such value. Thus the :nothrow feature of v_next will now not only ensure that there is no exception when opening the stream but also when closing it. Unusual situations encountered when the lazy list reads from the stream still throw. * txr.1: Documented.
* txr: @(eof) takes argument for binding termination status.Kaz Kylheku2021-08-051-21/+48
| | | | | | | | | | | | | | | | | | | | | | | | | | | | We extend the matching context structures to keep track of the underlying stream from which lines are being taken via the lazy list. Then the implementation of the @(eof) directive, when it hits the eof condition, can use this stream to gain access to the termination status. * match.c (match_line_ctx, match_files_ctx): New member, stream. (ml_all): Take stream argument and initialize new member. (h_call, do_match_line): Pass stream argument to h_call. (mf_all, mf_file_data): Take stream argument and initialize new member. (mf_from_ml): Propagate stream from line context to file context. (freeform_prepare, v_next_impl, match_filter, match_fun, extract): Pass stream argument where now needed. (v_eof): Implement termination status binding via the stream stored in the context. (open_data_source): Store stream in match files context. * tests/010/eof-status.txr: New file. * tests/010/eof-status.expected: New file. * Makefile (tst/tests/010/eof-status.ok): -B option for new test. * txr.1: Documented eof directive, argument and all. * stdlib/doc-syms.tl: Updated.
* hash: change make_hash interface.Kaz Kylheku2021-07-221-4/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The make_hash function now takes the hash_weak_opt_t enumeration instead of a pair of flags. * hash.c (do_make_hash): Take enum argument instead of pair of flags. Just store the option; nothing to calculate. (weak_opt_from_flags): New static function. (tweak_hash): Function removed. (make_seeded_hash): Adjust to new do_make_hash interface with help from weak_opt_from_flags. (make_hash, make_eq_hash): Take enum argument instead of pair of flags. (hashv): Calculate hash_weak_opt_t enum from the extracted flags, pass down to make_eq_hash or make_hash. * hash.h (tweak_hash): Declration removed. (make_hash, make_eq_hash): Declarations updated. * eval.c (me_case, expand_switch): Update make_hash calls to new style. (eval_init): Update make_hash calls and get rid of tweak_hash calls. This renders the tweak_hash function unused. * ffi.c (make_ffi_type_enum, ffi_init): Update make_hash calls to new style. * filter.c (make_trie, trie_add, filter_init): Likewise. * lib.c (make_package_common, obj_init, obj_print): Likewise. * lisplib.c (lisplib_init): Likewise. * match.c (dir_tables_init): Likewise. * parser.c (parser_circ_def, repl, parse_init): Likewise. * parser.l (parser_l_init): Likewise. * struct.c (struct_init, get_slot_syms): Likewise. * sysif.c (get_env_hash): Likewise. * lex.yy.c.shipped, y.tab.c.shipped: Updated.
* type: disallow structs using built-in type names.Kaz Kylheku2021-07-081-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This is a big commit motivated by the need to clean up the situation with built-in type symbols, COBJ objects and structs. The struct type system allows struct types to be defined for symbols like regex or str, which are used by built-in or cobj types. This is a bad thing. What is worse, structure instances are COBJ types which identify their type using the COBJ class symbol mechanism. There are places in the C implementation which assume that when a COBJ has a certain class symbol, it is of a certain expected type, which is totally different from and incompatible form a struct instance. User code can define a structure object which will fool that code. There are multiple things going on in this patch. The major theme is that the COBJ representation is changing. Instead of a class symbol, COBJ instances now carry a "struct cobj_class *" pointer. This pointer is obtained by registration via the cobj_register function. All modules must register their class symbols to obtain these class handles, which are then used in cobj() calls for instantiation. The CPTR type was identical to COBJ until now, except for the type tag. This is changing; CPTR objects will keep the old representation with the class symbol. commit 20fdfc6008297001491308849c17498c006fe7b4 Author: Kaz Kylheku <kaz@kylheku.com> Date: Thu Jul 8 19:17:39 2021 -0700 * ffi.h (carray_cls): Declared. * hash.h (hash_cls): Declared. (hash_early_init): Declared. * lib.h (struct cobj_class): New struct. (struct cobj): cls member changing to struct cobj_class *. (struct cptr): New struct, same as previous struct cobj. (union obj): New member cp of type struct cptr, for CPTR. (builtin_type): Declared. (class_check): Declaration moved closer to COBJ-related functions and updated. (cobj_register, cobj_register_super, cobj_class_exists): New functions declared. (cobjclassp, cobj_handle, cobj_ops): Declarations updated. * parser.h (parser_cls): Declared. * rand.h (random_state_cls): Declared. * regex.h (regex_cls): Declared. * stream.h (stream_cls, stdio_stream_cls): Declared. * struct.h (struct_cls): Declared. * tree.h (tree_cls, tree_iter_cls): Declared. * vm.h (vm_desc_cls): Declared. * buf.c (buf_strm, make_buf_stream): Pass stream_cls functions instead of stream_s class symbol. * chksum.c (sha256_ctx_cls, md5_ctx_cls): New static class handles. (sha256_begin, sha256_hash, sha256_end, md5_begin, md5_hash, md5_end): Pass class handles to instead of class symbols. (chksum_init): Initialize class handle variables. * ffi.c (ffi_type_cls, ffi_call_desc_cls, ffi_closure_cls, union_cls): New static class handles. (carray_cls): New global variable. (ffi_type_struct_checked, ffi_type_print_op, ffi_closure_struct_checked, ffi_closure_print_op, make_ffi_type_builtin, make_ffi_type_pointer, make_ffi_type_struct, make_ffi_type_union, make_ffi_type_array, make_ffi_type_enum, ffi_call_desc_checked, ffi_call_desc_print_op, ffi_make_call_desc, ffi_make_closure, carray_struct_checked, carray_print_op, make_carray, cptr_getobj, cptr_out, uni_struct_checked, make_union_common): Pass class handles instead of class symbols. (ffi_init): Initialize class handle variables. * filter.c (regex_from_trie): Use hash_cls class handle instead of hash_s. * gc.c (mark_obj): Split COBJ and CPTR cases since the representation is different. * hash.c (hash_cls, hash_iter_cls): New class handles. (make_similar_hash, copy_hash, gethash_c, gethash_e, remhash, clearhash, hash_count, get_hash_userdata, set_hash_userdata, hashp, hash_iter_init, hash_begin, hash_next, hash_peek, hash_reset, hash_reset, hash_uni, hash_diff, hash_symdiff, hash_isec): Pass class handles instead of class symbols. (hash_early_init): New function. (hash_init): Set the class symbols in the class handles that were created in hash_early_init at a time when these symbols did not exist. * lib.c (nelem): New macro. (cobj_class): New static array. (cobj_ptr): New static pointer. (cobj_hash): New static hash. (seq_iter_cls): New static class handle. (builtin_type_p): New function. (typeof): Struct instances now all carry the same symbol, struct, as their COBJ class symbol. To get their type, we must call struct_type_name. (subtypep): Rearrangement of two cases: let's make the reflexive case first. Adjust code for different location of COBJ class symbol. (seq_iter_init_with_info, seq_begin, seq_next, seq_reset, iter_begin, iter_more, iter_item, iter_step, iter_reset, make_like, list_collect, do_generic_funcall): Use class handles instead of class symbols. (class_check, cobj, cobjclassp, cobj_handle, cobj_ops): Take class handle argument instead of class symbol. (cobj_register, cobj_register_super, cobj_class_exists): New functions. (cobj_populate_hash): New static function. (cobj_print_op): Adjust for different location of class (cptr_print_op, cptr_typed, cptr_type, cptr_handle, cptr_get): cptr functions now refer to obj->cp rather than obj->co. (copy, length, sub, ref, refset, replace, dwim_set, dwim_del, obj_print): Use class handles for various COBJ types rather than class symbols. (obj_init): gc-protect cobj_hash. Initialize seq_iter_cls class symbol and cobj_hash. Populate cobj_hash as the last initialization step. (init): Call hash_early_init immediately after gc_init. diff --git a/lib.c b/lib.c * match.c (do_match_line): Refer to regex_cls class handle instead of regex_s.. * parser.c (parser_cls): New global class handle. (parse, parser_get_impl, lisp_parse_impl, txr_parse, parser_errors): Use class handles instead of class symbols. (parse_init): Initialize parser_cls. * rand.c (random_state_cls): New global class handle. (make_state, random_state_p, make_random_state, random_state_get_vec, random_fixnum, random_float, random): Use class handles instead of class symbols. (rand_init): Initialize random_state_cls. * regex.c (regex_cls): New global class handle. (chset_cls): New static class handle. (reg_compile_csets, reg_derivative, regex_compile, regexp, regex_source, regex_print, regex_run, regex_machine_init): Use class handles instead of class symbols. (regex_init): Initialize regex_cls and chset_cls. * socket.c (make_dgram_sock_stream): Use stream_cls class symbol instead of stream_s. * stream.c (stream_cls, stdio_stream_cls): New class handles. (make_null_stream, stdio_get_fd, make_stdio_stream_common, stream_fd, sock_family, sock_type, sock_peer, sock_set_peer, make_dir_stream, make_string_input_stream, make_string_byte_input_stream, make_strlist_input_stream, make_string_output_stream, make_strlist_output_stream, get_list_from_stream, make_catenated_stream, make_delegate_stream, make_delegate_stream, stream_set_prop, stream_get_prop, close_stream, get_error, get_error_str, clear_error, get_line, get_char, get_byte, get_bytes, unget_char, unget_byte, put_buf, fill_buf, fill_buf_adjust, get_line_as_buf, format, put_string, put_char, put_byte, flush_stream, seek_stream, truncate_stream, get_indent_mode, test_set_indent_mode, test_neq_set_indent_mode, set_indent_mode, get_indent, set_indent, inc_indent, width_check, force_break, set_max_length, set_max_depth): Use class handle instead of symbol. (stream_init): Initialize stream_cls and stdio_stream_cls. * struct.c (struct_type_cls, struct_cls): New class handles. (struct_init): Initialize struct_type_cls and struct_cls. (struct_handle): Static function moved to avoid forward declaration. (stype_handle): Refer to struct_type_cls class handle instead of struct_type_s symbol. Handle instance objects in addition to types. (make_struct_type): Throw error if a built-in type is being defined as a struct type. Refer to class handle instead of class symbol. (find_struct_type, allocate_struct, make_struct_impl, make_lazy_struct, copy_struct): Refer to class handle instead of class symbol. * strudel.c (make_struct_delegate_stream): Refer to stream_cls class handle instead of stream_s symbol. * sysif.c (dir_cls): New class handle. (poll_wrap): Use typep instead of subtypep, eliminating access to class symbol. (opendir_wrap, closedir_wrap, readdir_wrap): Use class handles instead of class symbols. (sysif_init): Initialize dir_cls. * syslog.c (make_syslog_stream): Refer to stream_cls class handle instead of stream_s symbol. * tree.c (tree_cls, tree_iter_cls): New class handles. (tree_insert_node, tree_lookup_node, tree_delete_node, tree_root, tree_equal_op, tree, copy_search_tree, make_similar_tree, treep, tree_begin, copy_tree_iter, replace_tree_iter, tree_reset, tree_next, tree_peek, tree_clear): Use class handle instead of class symbol. (tree_init): Initialize tree_cls and tree_iter_cls. * unwind.c (sys_cont_cls): New static class handle. (revive_cont, capture_cont): Use class handle instead of class symbol. (uw_late_init): Initialize sys_cont_cls. * vm.c (vm_desc_cls): New global class handle. (vm_closure_cls): New static class handle. (vm_desc_struct, vm_make_desc, vm_closure_struct, vm_make_closure, vm_copy_closure): Use class handle instead of class symbol. (vm_init): Initialize vm_desc_cls and vm_closure_cls.
* txr: stack protection in pattern language.Kaz Kylheku2021-06-241-0/+4
| | | | | | | | | * txr.c (do_match_line, match_files): call gc_stack_check on entry. * tests/012/stack2.txr: New file. * tests/012/stack2.expected: New file.
* c_str now takes a self argument.Kaz Kylheku2021-06-231-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Adding a self parameter to c_str so that when a non-string occurs, the error is reported against a function. Legend: A - Pass existing self to c_str. B - Define self and pass to c_str and possibly other functions. C - Take new self parameter and pass to c_str and possibly other functions. D - Pass existing self to c_str and/or other functions. E - Define self and pass to other functions, not c_str. X - Pass nil to c_str. * buf.c (buf_strm_put_string, buf_str): B. * chksum.c (sha256_str, md5_str): C. (sha256_hash, md5_hash): D. * eval.c (load): D. * ffi.c (ffi_varray_dynsize, ffi_str_put, ffi_wstr_put, ffi_bstr_put): A. (ffi_char_array_put, ffi_wchar_array_put): C. (ffi_bchar_array_put): A. (ffi_array_put, ffi_array_out, ffi_varray_put): D. * ftw.c (ftw_wrap): A. * glob.c (glob_wrap): A. * lib.c (copy_str, length_str, coded_length,split_str_set, list_str, cmp_str, num_str, out_json_str, out_json_rec, display_width): B. (upcase_str, downcase_str, string_extend, search_str, do_match_str, do_rmatch_str, sub_str, replace_str, cat_str_append, split_str_keep, trim_str, int_str, chr_str, span_str, compl_span_str, break_str, length_str_gt, length_str_ge, length_str_lt, length_str_le, find, rfind, pos, rpos, mismatch, rmismatch): A. (c_str): Add self parameter and use in type mismatch diagnostic. If the parameter is nil, use "internal error". (flo_str): B, and correction to "flot-str" typo. (out_lazy_str, out_quasi_str, obj_print_impl): D. * lib.h (c_str): Declaration updated. * match.c (dump_var): X. (v_load): D. * parser.c (open_txr_file): C. (load_rcfile): E. (find_matching_syms, provide_atom): X. (hist_save, repl): B. * parser.h (open_txr_file): Declaration updated. * parser.y (chrlit): X. * regex.c (search_regex): A. * socket.c (getaddrinfo_wrap, sockaddr_pack): A. (dgram_put_string): B. (open_sockfd): D. (sock_connect): E. * stream.c (stdio_put_string, tail_strategy, vformat_str, open_directory, open_file, open_tail, remove_path, rename_path, tmpfile_wrap, mkdtemp_wrap, mkstemp_wrap): B. (do_parse_mode, parse_mode, make_string_byte_input_stream): B. (normalize_mode, normalize_mode_no_bin): E. (string_out_put_string, formatv, put_string, open_fileno, open_subprocess, open_command, base_name, dir_name, short_suffix, long_suffix): A. (run): D. (win_escape_cmd, win_escape_arg): X. * stream.h (parse_mode, normalize_mode, normalize_mode_no_bin): Declarations updated. * sysif.c (mkdir_wrap, do_utimes, dlopen_wrap, dlsym_wrap, dlvsym_wrap): A. (do_stat, do_lstat): C. (mkdir_nothrow_exists, ensure_dir): E. (chdir_wrap, rmdir_wrap, mkfifo_wrap, chmod_wrap, symlink_wrap, link_wrap, readlink_wrap, exec_wrap, getenv_wrap, setenv_wrap, unsetenv_wrap, getpwnam_wrap, getgrnam_wrap, crypt_wrap, fnmatch_wrap, realpath_wrap, opendir_wrap): B. (stat_impl): statfn pointer-to-function argument now takes self parameter. When calling it, we pass name. * syslog.c (openlog_wrap, syslog_wrapv): A. * time.c (time_string_local, time_string_utc, time_string_meth, time_parse_meth): A. (strptime_wrap): B. * txr.c (txr_main): D. * y.tab.c.shipped: Updated.
* txr: gather: report list of missing required vars.Kaz Kylheku2021-04-131-2/+8
| | | | | * match.c (v_gather): Identify all required variables that are missing, and list them all in the diagnostic.
* txr: tighten keyword arg parsing in @(next).Kaz Kylheku2021-02-221-13/+17
| | | | | | | | | | | | This fixes the bug of not allowing @(next :list nil). Also the bug of @(next :string) or @(next :string nil) reporting a nonsensical error message, instead of correctly complaining that nil isn't a string. * match.c (v_next_impl): Capture the conses returned by assoc, so we know whether a keyword is present. Then use those conses in tests which detect whether the keyword is present, rather than the values, which could be nil.
* txr: typo in comment.Kaz Kylheku2021-02-221-1/+1
| | | | * match.c (match_files): Fix bungled wording.
* txr: bugfix: give @(call) same semantics as direct call.Kaz Kylheku2021-02-221-10/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | The @(call) directive is buggy in the following ways, which cause an indirect call to behave differently from a direct call. It creates a new context, and so if the opening of a data source is deferred into the indirectly called function, that data source is lost when the indirect call terminates. Furthermore, if a data source is already established, there is no progress through the data: two consecutive @(call ...) directives operate on the same data. It also fails to implement vertical to horizontal fallback; if a function is not vertically defined, the directive fails. * match.c (v_call): Rewrite the core logic in the following way: we rewrite the indirect @(call) syntax into direct call syntax, substitute that into c->spec, and then just call v_fun. * tests/008/call-2.expected: New file. * tests/008/call-2.txr: New file. Test fails before this commit because both calls are matching against the same "A" element of the list.
* txr: pattern function calls are non-matching.Kaz Kylheku2021-02-211-22/+23
| | | | | | | | | | | | | | | | | | | | | | | | | | | This patch causes TXR to treat calls to verticatl functions, as well as the @(call) directive to be considered non-matching directives, so that opening the data source is deferred. This allows included .txr files to call the funtions that they define, without the side effect of standard input being read. * match.c (open_data_source): Function refactored to reduce duplication. c->data is checked first, and if it is not t, nothing is done, making the function cheaper in the frequent case. The non_matching_dir condition changes. We now check that the first element of the first spec is a non-nil symbol. If it has a function binding as a vertical function, then that is considered non_matching. (dir_tables_init): Treat @(call) as a non-matching directive. * Makefile (tst/tests/008/no-stdin-hang.ok): Add -n argument for non-interactive, which will cause stdin to be read in that test case if there is a regression in this change. If make tests is run in a terminal, this will hang make tests. * tests/no-stdin-hang.txr: New file. * tests/no-stdin-hang.expected: New file.
* @(call): bugfix: matching doesn't continue.Kaz Kylheku2021-02-171-1/+2
| | | | | | | | | | | * match.c (v_call): This function must propagate the next_spec_k return value, rather than return a short-circuiting match object, which causes the parent to immediately succeed. * tests/008/call.txr: New test case, from Frank Schwidom. * tests/008/call.expected: Likewise.
* @(rebind): bugfix: don't clobber right side variable.Kaz Kylheku2021-01-301-1/+1
| | | | | | | | | | | | | | | | | | | | | * Makefile (tst/tests/000/binding.ok): Pass -B to txr for this new test. * match.c (v_rebind): Fix gaping copy-and-paste bug here, which causes rebind to take on the behavior of local/forget; it takes all symbols that appear as its arguments from the environment and produces an environment in which they don't exist. What we want is to remove the left variables from the environment, and since that is a nested pattern, the right way to do that is to flatten it. Bug reported by Frank Schwidom. * tests/000/binding.txr: New file. * tests/000/binding.expected: New file. * txr.1: Improve documentation of @(rebind), also making improvements in @(set) documentation.
* 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.
* txr, eval: eliminate some func_n1 calls.Kaz Kylheku2020-12-101-3/+3
| | | | | | | | | * 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.
* env: move function to sysif.cKaz Kylheku2020-10-161-0/+1
| | | | | | | | | | | | | | | | | * lib.c (env_list): Static variable removed; now appears in sysif.c (env): Function removed; now in sysif.c. (obj_init): Don't gc-protect env_list here any more. * lib.h (env): Declaration removed. * match.c: Must include "sysif.h" now for env. * sysif.c (env_list): Static variable moved here. (env): Function moved here. (sysif_init): env_list gc-protected here. * sysif.h (env): Declared.
* tags: address small issue with tag lookup.Kaz Kylheku2020-09-011-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* txr: identify output repeat vars at parse timeKaz Kylheku2020-08-171-51/+7
| | | | | | | | | | | | | | | | | | | | | | | | | | Up to now the @(repeat) and @(rep) directives have scanned their interior to find output variables. We now hoist that into the parser; the variables are found up-front and integrated into the abstract syntax. This work anticipates doing a more proper job of identifying free variables in Lisp expressions. * match.c (extract_vars): Delete static this function here. It moves into parser.y. (extract_bindings): Don't call extract_vars to obtain the variables occurring in the repeat body. Get it as a new argument, occur_vars. (do_output_line, do_repeat): Extract the new occur_vars element of the abstract syntax node and pass it to extract_bindings. * parser.y (extract_vars): New static function, moved here from match.c. (repeat_rep_helper): Scan over each of the repeat subclauses with extract vars. Catenate the resulting lists together and pass through uniq to squash repeated symbols. Then add the resulting vars as a new element of the returned syntax node.
* Remove unnecessary forward declarations.Kaz Kylheku2020-08-171-1/+0
| | | | | | * lib.c (length_proper_list): Forward decl removed. * match.c (do_match_line): Likewise.
* match.c: revert bad commits.Kaz Kylheku2020-08-141-158/+118
| | | | | | | | | | | | | | | | | | | This contains two reverts, folded into one. "txr: spurious retention in @(next)." commit fe1e960389a89f481d46c02aa040fdc762da735f. "txr: avoid by-value match_files_ctx passing." commit 3d7330b827d6e9cc0d9e87edd30388374cb45900. These are dependent. The second of these two (i.e. the one that was done first) is the problematic one. By-reference passing of contexts means contexts become shared objects between callers and callees. But this is incorrect, because mutations are going on, like c->spec = rest(c->spec) or c->data = rest(c->data). These mutations were done under the assumption of safety: that the caller is not affected due to by-value semantics of the entire context.
* Change noreturn to NORETURN.Kaz Kylheku2020-08-071-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* txr: support @(if)/@(elif)/@(else) in @(output).Kaz Kylheku2020-07-071-0/+14
| | | | | | | | | | | | | | | | | | | This turns out to be way easier than I thought. * match.c (do_output_if): New static function. (do_output): Handle if via do_output_if. * parser.y (out_if_clause, out_elif_clauses_opt, out_else_clause_opt): New nonterminal symbols and grammar rules. (out_clause): Now produces out_if_clause. (not_a_clause): Remove ELIF and ELSE; these entries here cause conflicts now. Here, continue to recognize the Lisp if, which is distinguished by having at least two arguments. out_if_clause matches only a one-argument if, and a no-argumeent one that is diagnosed as erroneous. * txr.1: Documented.
* txr: factor repeat out of output.Kaz Kylheku2020-07-071-97/+107
| | | | | * match.c (do_repeat): New static function. (do_output): Repeat processing logic moved into do_repeat.
* c_num: now takes self argument.Kaz Kylheku2020-06-291-23/+32
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* pattern lang: vertical-horizontal fallback regression.Kaz Kylheku2020-06-291-3/+6
| | | | | | | | | | | | | | | | | | | | | | | | | | | Commit c9cab7138636c6c1d6e47f8d1a4053bec2dd0ad4, on Feb 1, 2019, breaks the following case: @(define horiz)whatever@(end) @(horiz) The code assumes that if v_fun returned :decline, then the function doesn't exist. That is false, because the function may have a horizontal definition, as in the above example. That's why in the original code, nothing was done in this case to just allow the flow to proceed to the horizontal fallback, where the call will be tried as a horizontal function. The small problem with that was lack of a diagnosis when the function actually doesn't exist (neither vertical nor horizontal). In that case, the horizontal fallback will expect a line of data. If no data arrives, then the undefined function call is undiagnosed. The idea behind c9cab7138636c6c1d6e47f8d1a4053bec2dd0ad4 was to provide a diagnostic immediately. The right way to do that is to check for a horizontal definition of the function. If there isn't one, then error out, otherwise fall back on the horizontal processing.
* Remove unnecessary #include directives.Kaz Kylheku2020-04-221-2/+0
| | | | | | | | | | Time for some spring cleaning. * args.c, arith.c, buf.c, cadr.c, chksum.c, debug.c, ftw.c, gc.c, gencadr.txr, glob.c, hash.c, lisplib.c, match.c, parser.c, parser.l, parser.y, rand.c, signal.c, stream.c, strudel.c, syslog.c, tree.c, unwind.c, utf8.c, vm.c: Numerous unnecessary #include directives removed.
* load: release warnings before throwing exception.Kaz Kylheku2020-04-141-1/+3
| | | | | | | | | | | | * eval.c (load): When we parse TXR code, let's not release warnings unconditionally. Let's do that when throwing an exception though due to parse errors. If the load is not recursed it will release warnings at the bottom of the function. * match.c (v_load): Consistently with load, release deferred warnings if throwing exception due to the parse having failed.
* txr: spurious retention in @(next).Kaz Kylheku2020-04-111-3/+16
| | | | | | | | | | | | | | * match.c (mf_file_lazy): New static function. The lazy list is created here and stored directly into the data field of the context structure. Function is marked NOINLINE because on an older system with gcc 4.4.5, it didn't solve the problem. We need the function to have a stack frame so any spurious copies of the linked list go into a frame that disappears when the function returns. (v_next_impl): Use mf_file_lazy instead of mf_file_data. (open_data_source): Also make this function INLINE just in case because it contains calls to lazy_stream_cons.
* txr: avoid by-value match_files_ctx passing.Kaz Kylheku2020-04-111-117/+144
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Passing the match_files_ctx structure by value looks nice in the code, but it is contributing to a long standing false retention issue. This test case runs in constant memory: $ yes | txr -c '@(skip) n' skip scans through the lazy list of "y" lines looking for an "n" that never comes. This version should also run in constant memory, but shows unbounded memory growth. $ yes | txr -c '@(next *stdin*) @(skip) n' This patch doesn't fix it, but it moves things in that direction. * match.c (mf_all, mf_args, mf_data, mf_spec, mf_spec_bindings, mf_file_data, mf_from_ml): Take pointer to structure which to initialize and return that pointer, instead of initializing a local structure and returning it by value. (match_files): Take pointer to context rather than copy. (h_call, do_match_line, v_fuzz, v_block, v_next_impl, v_parallel, v_gather, v_collect, v_bind, hv_trampoline, v_try, v_fun, v_if, v_assesrt, v_load, v_call, match_filter, match_fun, extract): Adjust to by-pointer context handling of mf_all, match_files and other functions.
* exceptions: improve non-error @(throw) and @(assert).Kaz Kylheku2020-04-071-3/+4
| | | | | | | | | | | | | | | When @(throw) generates a non-error exception that is unhandled, we just want it to continue. In the same situation, an @(assert) should behave as a failed match; that is, the failure of the query material that follows the assert, which activated it, should propagate through the assert. * match.c (v_throw): Return next_spec_k if uw_rthrow returns. (v_assert, h_assert): Return nil if uw_rthrow returns. * txr.1: Expanded @(throw) and @(assert) documentation with discussion of unhandled exceptions.
* exceptions: use uw_rthrow for non-error exceptions.Kaz Kylheku2020-04-071-3/+3
| | | | | | | | | | | | | | | | | | | * eval.c (eval_exception): This function is shared by warnings and errors. Use uw_throw. The eval_error caller already has an abort() after its eval_exception call, which makes that code path continue to be equivalent to uw_throw. The behavior changes for the other caller, eval_warn, which will now return if the warning is not handled. (eval_defr_warn, gather_free_refs, gather_free_refs_nw): Throw non-error exception with uw_rthrow. * match.c (v_throw, v_assert, h_assert): Use uw_rthrow for these directives, just like the throw function. * parser.c (repl_intr, repl_warning): Use uw_rthrow. * unwind.c (uw_muffle_warning, uw_release_deferred_warnings): Likewise.
* internals: rename misnamed curry_* functions.Kaz Kyheku2020-03-171-13/+13
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The various curry_xx_yy functions perform partial application, not currying. The curry prefix is being renamed to pa (partially apply). * lib.c (remq_lazy, remql_lazy, remqual_lazy, tree_Find): Updated. (do_curry_12_1, do_curry_12_1_v, do_curry_12_2, do_curry_123_1, do_curry_123_23, do_curry_123_2, do_curry_123_3, do_curry_1234_1, do_curry_1234_34): Renamed to do_pa_12_1, do_pa_12_1_v, do_pa_12_2, do_pa_123_1, do_pa_123_23, do_pa_123_2, do_pa_123_3, do_pa_1234_1, do_pa_1234_34. (curry_12_1, curry_12_1_v, curry_12_2, curry_123_1, curry_123_23, curry_123_2, curry_123_3, curry_1234_1, curry_1234_34): Renamed to pa_12_1, pa_12_1_v, pa_12_2, pa_123_1, pa_123_23, pa_123_2, pa_123_3, pa_1234_1, pa_1234_34. (transposev, do_juxt): Updated. * lib.h: Declarations renamed. * eval.c (subst_vars, qquote_init, expand_catch, weavev): Updated. * filter.c (get_filter, build_filter_from_list, filter_string_tree, filter_init): Updated. * match.c (tx_subst_vars, do_txeval, v_freeform, v_bind, v_throw, v_deffilter, v_assert, h_assert): Updated. * parser.y (gather_clause): Updated. * regex.c (regex_range_full_fun, regex_range_left_fun, regex_range_right_fun, regex_range_search_fun): Updated. * stream.c (open_files, open_files_star): Updated. * txr.c (txr_main): Updated. * unwind.c (me_defex): Updated.
* @(line): get meaningful value in horizontal mode.Kaz Kylheku2020-02-131-1/+10
| | | | | | | | | | | | | | | When @(line var) is used in a horizontal match, line is bound to zero. This is because the line number isn't being propagated. * match.c (mf_from_ml): Both the file and line context structurs have a data_lineno, yet this function doesn't propagate it. Instead of using ml_all, whose name tells a subtle lie since it neglects the data_lineno, let's just do the member for member logic here. This function is used in one place, the hv_trampoline. So this fixes the line number for all vertical directives called out of horizontal context.
* bugfix: regression in @(skip).Kaz Kylheku2020-02-091-4/+4
| | | | | | | | | | | | | | When @(skip :greedy) is used, there is an exception complaining that :greedy isn't an integer. Reported by a user "natrys" in the IRC channel. This was introduced in July 2016, by commit a208fafe0b0bf6dd5a78c939e55f0153f6bd6b19, "Address silly uses of fixnump". * match.c (h_skip, v_skip): Re-introduce the integer check that was indadvertently removed.
* c_str: don't allow symbols.Kaz Kyheku2020-01-311-1/+1
| | | | | | | | | | | | | | | | | | | | | | | On 2009-10-02, prior to TXR 014, I made a change to the c_str function to allow symbolic arguments, so that c_str(sym) could be used in the code base instead of c_str(symbol_name(sym)). This was a bad idea, and is allowing numerous functions that operate on strings to accept symbols also. That behavior is not documented and not consistently supported. Ironically, I completely forgot about this and have been consistently using symbol_name(sym) anyway. Let us remove this. Compat support is required because this will break user code that accidentally depends on this undocumented behavior. * lib.c (c_str): If the object is type SYM, only return the symbol_name if compatibility with 231 or older is requested, otherwise fall through to the error case. * match.c (dump_var): Fix one case where a symbol is passed directly to put_string. This fails one of the test cases. More testing is required to see if any other such cases occur. * txr.1: New entry in the compatibility notes.
* Copyright year bump 2020.Kaz Kylheku2019-12-311-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * LICENSE, LICENSE-CYG, METALICENSE, 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, 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/debugger.tl, share/txr/stdlib/defset.tl, share/txr/stdlib/doloop.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/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, 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: Extended copyright notices to 2020.
* @(collect): don't default vars if all required missing.Kaz Kylheku2019-08-121-34/+50
| | | | | | | | | | | | | | | | | | | | | | | | | The @(collect) directive disallows the situation when there are required vars, but some are missing (not bound by the collect body). However, the special case is allowed when none of the required variables are bound; that doesn't trigger the exception. There is a poor specification in this area: the issue is that when there are optional variables, and all variables are missing (optional and required), the optional ones are still bound to their default values. Thus, the situations is half-baked: some of the :vars are bound and some are not. This violates the all-or-nothing principle of :vars. This patch addresses the poor specification: if all variables are missing, then the optional variables are not bound to their defaults. * match.c (h_collect, h_coll): Detect the situation when at least one variable is required, and all optional variables are defaulted. In this case, don't propagate any bindings to the collected lists. * txr.1: Doc updated.
* @(collect)/@(coll): streamline list accumulation code.Kaz Kylheku2019-08-071-10/+17
| | | | | | | | | * match.c (h_coll, v_collect): Revising the code for accumulating items into lists. Duplicate assoc lookups via assoc and acons_new are eliminated in favor of doing rplacd or acons. We don't call assoc to look up a binding if have_vars is false. car(binding) is called once and captured in the local vaiable sym.
* txr: regression: lack of file name in error messages.Kaz Kylheku2019-07-221-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This was broken on April 21, 2019 in commit 2e36e0feae8d1dd75c8410b365d7dc33b30ce66b (April 21, 2019) which changed parse_once in such a way that the name being passed down was no longer stored in the parser. The ensure_parser function being relied upon doesn't take on the responsibility of propagating the name from the stream to the parser, so the parser ends up with a nil name. Let's just smooth this over by having ensure_parser take a name parameter. If ensure_parser creates a new parser, it puts in the name. If the name is nil, then it is taken from the stream. * eval.c (load): Pass name to ensure_parser. * match.c (v_load): Likewise. * parser.c (parser): Take name parameter, and plant into newly constructed parser. (ensure_parser): Take name parameter. When creating a parser, give it that name, or if name is specified as nil, then give it the name taken from the stream. (parser_set_lineno): Pass nil name to ensure_parser. (lisp_parse_impl, read_file_common): Pass name to ensure_parser. * parser.h (parser, ensure_parser): Declarations updated. * parser.y (parse_once): Pass name to ensure_parser. * txr.c (txr_main): Pass spec_file_str to ensure_parser.
* @{var1 var2}: bugfix: broken when var2 is regex.Kaz Kylheku2019-07-021-1/+1
| | | | | | | | | | * match.c (h_var): When processing variable bound over a regex or text match, if that datum came from a modifier which was a variable, we must process the substituted modifier, not the original variable symbol. This is a regression that was introduced on November 16, 2011, in commit b86a599bbfcd591f64f31ddfc9ab1a659d39a7c0: "Variable matches can span over function calls.". Reported by user vapnik spaknik.
* Replace lt(x, zero) pattern.Kaz Kylheku2019-06-151-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | | This slight inefficiency occurs in some 37 places in the code. In most places we replace lt(x, zero) with minusp(x). In a few places, !plusp(x) is used and surrounding logic is simplified. In one case, the silly pattern lt(x, zero) ? t : nil is replaced with just minusp(x). * buf.c (sub_buf, replace_buf): Replace lt. * combi.c (perm, rperm, comb, rcomb): Likewise. * eval.c (do_format_field): Likewise. * lib.c (listref, sub_list, replace_list, split_func, split_star_func, match_str, lazy_sub-str, sub_str, replace_str, sub_vec, replace_vec): Likewise. * match.c (weird_merge): Likewise. * regex.c (match_regex, match_regex_right_old, match_regex_right, regex_prefix_match, regex_range_left, regex_range_right): Likewise.
* parser: always use stream-associated parser for parse_once.Kaz Kylheku2019-04-211-5/+6
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This refactoring is needed for fixing the off-by-one line number bug when the hash bang line is processed. * eval.c (load): Don't define parser locally; ensure there is one in the stream and use it. * match.c (v_load): Likewise. * parser.c (get_parser_impl): Renamed to parser_get_impl and changed from internal to external linkage. (ensure_parser): Changed to external linkage. (lisp_parser_impl, read_file_common): Follow rename of get_parser_impl. * parser.h (parse_once): Declaration updated. (parser_get_impl, ensure_parser): Declared. * parser.y (parse_once): Take self parameter; drop parser parameter. Ensure a parser to the stream, rather than declaring one locally. Don't clean up the parser when done, just let the stream clean it up. * txr.c (parse_once_noerr): Parser argument is dropped and not passed to parse_once. Program name is passed as self argument to parse_once. (txr_main): When parsing the TXR pattern query, don't define a parser locally; ensure there is one in the stream and use it, like in load and v_load.
* debug support: crude debugger removed.Kaz Kylheku2019-04-091-38/+14
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * debug.c (debug_depth, debug_quit_s): Variables removed. (step_mode, next_depth, breakpoints, last_command, cols): Static variables removed. (debug_check): C99 inline instantiation removed. (help, show_bindings): Static functions removed. (debug): Function removed. (debug_set_state): Now takes one int argument, returns int. It's anticipated that the new debug system will have a simple on-off switch; there won't be a debug_depth hack. (debug_restore_state): Function removed. (debug_init): Emptied. * debug.h (debug_depth, debug_state_t): Declarations removed. (debug_enter, debug_leave, debug_return): Macros removed. (debug_check): Inline function removed. (debug_set_state): Declaration updated. (debug_restore_state): Declaration removed. (debug_frame, debug_end): Macros removed. * eval.c (do_eval, me_interp_macro): Debugging support scrubbed. * lisplib.c (lisplib_try_load): Adapt to debug_set_state interface change. * match.c (h_fun, do_match_line, v_fun, match_files, match_fun): Debugging support scrubbed. * parser.y (parse_once): Adapt to debug_set_state interface change. * protsym.c: Regenerated. * signal.h (debug_depth): Declaration removed. (EJ_DBG_MEMB, EJ_DBG_SAVE, EJ_DBG_REST): Macros removed. (EJ_OPT_MEMB, EJ_OPT_SAVE, EJ_OPT_REST): Reduced to unconditionally empty definitions for future use. * unwind.c (uw_push_debug): Function removed. * unwind.h (uw_frtype_t): UW_DBG enum member removed. (struct uw_debug): struct declaration removed. (union uw_frame): db member removed. (uw_push_debug): Declaration removed. * txr.1: Debugger doc removed.
* unwind: rename env frames.Kaz Kylheku2019-04-061-16/+16
| | | | | | | | | | | | | | | | | | | | | | Unwind frames of type ENV exist for the sake of the pattern language. Let's rename them accordingly. * match.c (tleval, tleval_progn, h_fun, tx_subst_vars, v_bind, v_output, v_filter, v_fun): Occurrences of the macros uw_env_begin and uw_env_end are renamed. * unwind.c (uw_env_stack): Renamed to uw_menv_stack. (uw_unwind_to_exit_point, uw_abscond_to_exit_point, uw_find_env, uw_pop_frame, revive_cont): Follow rename of UW_ENV to UW_MENV and uw_env_stack to uw_menv_stack. (uw_push_env): Renamed to uw_push_match_env, and updated to follow renames. * unwind.h (enum uw_frtype, uw_frtype_t): UW_ENV renamed to UW_MENV. (uw_push_env): Renamed to uw_push_match_env. (uw_env_begin, uw_env_end): Renamed to uw_match_env_begin an uw_match_env_end.
* @(output): bugfix: lazy evaluation doesn't work.Kaz Kylheku2019-04-051-4/+15
| | | | | | | | | | | | | | | In an @(output), if we reference a variable bound to a lazy list, and the generation of that logic references TXR pattern variables, things break: the lazy list's code doesn't see the binding. This is because the lazy list is forced by some logic that doesn't establish the proper environment for that evaluation. Inside a @(repeat), the do_output function measures the lengths of lists emanating from variables, and that has the effect of forcing the lazy lists. * match.c (v_output): Just set up the dynamic environment around the entire function, so that any Lisp evaluation that occurs is happening as if it were via tleval.
* c++ maintenance: multiple defs of mod_s and bit_s.Kaz Kylheku2019-03-301-1/+2
| | | | | | | | | * arith.h (mod_s, bit_s): Add extern declarations. * ffi.c (bit_s): Remove definition. * match.c (mod_s): Remove definition. Include "arith.h" to obtain declaration of mod_s.
* pattern lang: diagnose undefined function facing EOF.Kaz Kylheku2019-02-011-3/+10
| | | | | | | | | | | | | | | | | | | | | | | | | | | This addresses the following issue. Suppose the query is something like this: @abc @(nonexistent) and there is one line of data. In this case, there is no error about a nonexistent function. The function lookup fails in vertical mode, so horizontal mode fallback takes place. But that just concludes that there is no data, and reports a failed match. But the programmer might have intended to invoke some function or directive that doesn't need to match anything, but rather has an important effect. In this patch we fix that. As part of the change, we disallow functions from shadowing horizontal directives. * match.c (match_files): Do not look up sys:var and sys:text through the directive table, but check for these. If the directive is not found in the vertical table, check the horizontal table; if found there, don't try it as a function but go to horizontal processing. Then if the function lookup fails, we diagnose a failed lookup; don't fall through to horizontal processing.