summaryrefslogtreecommitdiffstats
path: root/parser.c
Commit message (Collapse)AuthorAgeFilesLines
* compile-file: need endian mark in .tlo files.Kaz Kylheku2018-04-121-1/+8
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | VM machine code is endian-specific: it consists of 32 bit instruction words which are 32 bit in the local byte order. Thus code assembled on a little-endian machine won't run on a big endian-machine, or vice versa: unless we identify the situation and byte-swap the code when we load it. * buf.c (buf_swap32): New function. * buf.h (buf_swap32): Declared. * parser.c (read_file_common): Decode the third element from the version: a Boolean indicating big endian, if true. If the object file's endian is opposite from our endian, then byte swap the code. * itypes.c (itypes_init): Oops, calculation of itypes_little_endian was broken due to classic C =/== typo. Luckily, nothing has used this flag so far; it's been waiting for this first use. I caught this due to testing on a PPC64 box. * share/txr/stdlib/compiler.tl (%big-endian%, %tlo-ver%): New variables. (usr:compile-file): The file version comes from %tlo-ver% now, which includes the big-endian flag.
* load: fix vm gc issue.Kaz Kylheku2018-04-101-0/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | This issue manifested itself as a segfault on Mac OS while compiling a library file using the compiled implementation (hash.tl -> hash.tlo2). The problem is premature reclamation of a virtual machine description. While the asm.tlo module is loaded, suddenly a function table goes corrupt. When we execute machine using vm_execute_toplevel, the vm's stack doesn't actually contain a reference to the description object anywhere. It's passed in as a parameter, and right away converted to the (struct vm_desc *) handle which is planted in the struct vm representing the running instance, which lives on the stack. That pointer isn't a reference traversed by the garbage collector. If the original Lisp object is optimized away and overwritten both in vm_execute_toplevel and in that function's caller, then it can be reclaimed even as it executes. * parser.c (read_file_common): Add a gc_hint(desc) after the vm_execute_toplevel so that the compiler thinks the value of the variable is still needed after the call. That keeps it around on the stack or in a register so that the garbage collector can see it as a root pointer.
* listener: completion: wrong use of package fallback.Kaz Kylheku2018-04-081-3/+3
| | | | | | | | | | | | | | | | | | | | | | | The problem is that completion on pub:sym[Tab] is completing on the fallback list, because pub is the current package. If we type pub:l[Tab], we might complete to pub:list. But that's because usr:list was found in the fallbacklist; pub:list isn't that symbol, and its use will shadow usr:list. This is against the documentatiion too, which describes it the way it should work: simply that the fallback list of the current package is used under completion when no package qualifier prefix is present. * parser.c (get_visible_syms): Rename second parameter to reflect its actual meaning, rather than an original intended use. (find_matching_syms): Only allow get_visible_syms to traverse package fallback lists if qualify is false. Thus even if we are completing against the current package, if that package is being explicitly indicated with a prefix, then only the package local symbols are included.
* compile-file: handle gensyms and such.Kaz Kylheku2018-04-051-7/+10
| | | | | | | | | | | | | | | | | | | * parser.c (read_file_common): The entire compiled representation is now one big list. We must walk the list to visit the individual compiled top-level forms. * share/txr/stdlib/compiler.tl (compile-file): Collect all the compiled top-level forms into one list, and emit it as one object. This way, gensym references among the items will resolve; for instance tests/012/man-or-boy.tl now compiles. That file defines a function named by a gensym, and a macro which expands to calls to that function. These end up in separate top-level forms and have to resolve. Because we are emitting everything as one big object, we cannot rely on (in-package ...) forms influencing the reading of the symbols. So we create a dummy package and switch to that during the writing, which forces all symbols to be fully qualified.
* compile-file/load: add version to files.Kaz Kylheku2018-04-051-1/+9
| | | | | | | | | | * parser.c (read_file_common): Treat first form in file as a version number of the form (major minor), where major nad minor are non-negative integers. If the major number is greater than zero, reject the file as incompatible. * share/txr/stdlib/compiler.tl (usr:compile-file): Emit version number (0 0) as the first item in a compiled file.
* load: remove hack for loading compiler.tlo.Kaz Kylheku2018-04-041-2/+1
| | | | | | | * parser.c (read_file_common): Remove the check whether the data vector is a list (due to have been converted to sys:vector-lit by the presence of unquotes). This doesn't happen any more, thanks to the previous parser commit.
* parser: don't generate special lits outside quasiquote.Kaz Kylheku2018-04-041-0/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The parser generates a sys:hash-lit, sys:struct-lit or sys:vector-lit whenever a hash, struct or vector literal contains unquotes. This allows the quasiquote expander to treat these objects as ordinary list structure when interpolating inside them, and then recognize these symbols and construct the implied real objects. The issue is that these literals are generated even if the unquotes occur outside of a backquote. For instance if a vector literal like #(,a) occurs out of the blue, not in any backquote, this is still a (sys:vector-lit (sys:unquote a)) and not an actual vector. The issue is compounded because this substitution takes place even if there is no actual comma or splice notation. Even the following is a sys:vector-lit: #((sys:unquote x)). In any case, it causes problems for compiled files, because such material can occur in the data vector of a compiled toplevel form. In this patch we modify the parser to keep track of the quasiquote/unquote level. The special literals are generated only when the object occurs inside a quasiquote. * parser.h (struct parser): New member, quasi_level. * parser.c (parser_common_init): Initialize the parser's new quasi_level member. * parser.y (vector, hash, struct): To decide whether to generate the special literal, don't just check whether unquotes occur in the list. Check that we are in a quasiquote, indicated by the quasiquoting level being positive. (i_expr, n_expr): Use a mid-rule actions on the quasiquote, unquote and splice rules to bump the quasiquoting level in one direction before recognizing the object, and then bump in the opposite direction when reducing the rule. (parse): Initialize quasi_level.
* Implement compiled file loading.Kaz Kylheku2018-04-041-7/+41
| | | | | | | | | | | | | | | | | | | | | | | | | | * eval.c (load): If open_txr_file indicates compiled file by setting txr_lisp_p to character #\o, use read_compiled_file. * match.c (v_load): Likewise. * parser.c (open_txr_file): Recognize the .tlo suffix, and also try to open a .tlo version of an unsuffixed file before trying it as .tl. Indicate a .tlo file by setting txr_lisp_p to the character #\o rather than t. (read_file_common): New static function, made from contents of read_eval_stream. Will either evaluate forms or load compiled code by instantiating virtual machine descriptions and performing their top-level execution. (read_eval_stream): Now a wrapper for read_file_common. (read_compiled_file): New function. * parser.h (read_compiled_file): Declared. * txr.c (help): List new --compiled option. (txr_main): If --compiled is specified, set txr_lisp_p to #\o to load as compiled code. Update error message that -c is not compatible with --lisp or --compiled. If txr_lisp_p is #\o, then use read_compiled_file.
* compiler: first cut compile-file implementation.Kaz Kylheku2018-04-031-0/+3
| | | | | | | | | | | | | | | | | | | | | | * lisplib.c (compiler_set_entries): Autoload on compile-file. * parser.c (parse_init): Expose get-parser, parser-errors and parser-eof intrinsics in system package. * share/txr/stdlib/compiler.tl (compiler): Wrap defstruct form in compile-only. What this means is that when we invoke comile-file on compiler.tl, the compiler will only compile this defstruct and not evaluate it. I.e. it will not try to redefine the structure. Redefining the core structure of the compiler while it is compiling itself wreaks havoc on the compilation. (%fille-suff-rx%, *emit*, *eval*): New variables. (open-compile-streams, list-from-vm-desc, usr:compile-file): New functions. * vm.c (vm_desc_nlevels, vm_desc_nregs): New static functions. (vm_init): Register new intrinsics vm-desc-nlevels and vn-desc-nregs in system package.
* listener: fix poor regex handling in balance check.Kaz Kylheku2018-03-171-1/+33
| | | | | | | * parser.c (is_balanced_line): Introduce the ST_RGXC state to which we switch when we encounter a regex character class. Also introduce ST_RGXE for regex subexpressions. In these states, do not recognize / as the regex terminator.
* New listener feature: greedy evaluation feature.Kaz Kylheku2018-02-171-2/+16
| | | | | | | | | | | | | | | | * eval.c (eval_intrinsic_noerr): New function. * eval.h (eval_intrinsic_noerr): Declared. * parser.c (listener_greedy_eval_s): New symbol variable. (repl): Implement greedy evaluation loop, enabled by the *listener-greedy-eval-p* special. (parse_init): Intern the *listener-greedy-eval-p* symbol, storing it in the listener_greedy_eval_s variable. Register the symbol as a special variable. * txr.1: Documented *listener-greedy-eval-p* variable and the greedy evaluation feature that it controls.
* Copyright year bump 2018.Kaz Kylheku2018-02-151-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * LICENSE, LICENSE-CYG, METALICENSE, Makefile, args.c, args.h, arith.c, arith.h, buf.c, buf.h, cadr.c, cadr.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, 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/awk.tl, share/txr/stdlib/build.tl, share/txr/stdlib/cadr.tl, share/txr/stdlib/conv.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/path-test.tl, share/txr/stdlib/place.tl, share/txr/stdlib/pmac.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/txr-case.tl, share/txr/stdlib/type.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, txr.1, txr.c, txr.h, unwind.c, unwind.h, utf8.c, utf8.h, win/cleansvg.txr: Extended Copyright line to 2018.
* New listener variable: *listener-pprint-s*.Kaz Kylheku2018-02-121-1/+6
| | | | | | | | | | * parser.c (listener_pprint_s): New symbol variable. (repl): Check new variable after each evaluation and print accordingly. (parse_init): Initialize listener_print_s with interned symbol and register the variable. * txr.1: Document *listener-pprint-s*.
* Use rplaca and rplacd instead of set over car_l/cdr_l.Kaz Kylheku2018-01-011-1/+1
| | | | | | | | | | | | | | | | | | | | | | | This reduces the proliferation of car_l and cdr_l. With this change, nreverse should work on chains of objects that implement rplacd. * combi.c (comb_gen_fun_common, rcomb_gen_fun_common): Use rplaca. * eval.c (mappendv, mapdov): Likewise * hash.c (hash_equal_op): Likewise. * lib.c (nreverse, acons_new, aconsql_new, sort_list): Use rplaca and rplacd. * match.c (dest_set, v_gather, v_collect, v_flatten, v_cat, v_output, v_filter): Likewise * parser.c (ensure_parser): Use sys_rplacd. * unwind.c (uw_register_subtype): Use rplacd.
* read, iread: source location recording now conditional.Kaz Kylheku2017-12-291-4/+20
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Recording of source location info incurs a time and space penalty. We don't want to impose this on programs which are just reading large amounts of Lisp data that isn't code. * eval.c (eval_init): Register lisp-parse and read functions to the newly introduced nread function rather than lisp_parse. lisp_parse continues to record source location info unconditionally. * parser.c (rec_source_loc_s): New symbol variable. (parser_common_init): Set the new member of the parser structure, rec_source_loc, according to the current value of the special var *rec-source-loc*. (lisp_parse_impl): New second argument, rlcp_p. If true, it overrides the rec_source_loc member of the parser structure to true. (lisp_parse): Pass true argument to rlcp_p parameter of lisp_parse_impl, so parsing via lisp_parse always records source loc info. (nread): New function. (iread): Pass true argument to rlcp_p parameter of lisp_parse_impl, so *rec-source-loc* controls whether source location info is recorded. (parse_init): Initilize rec_source_loc_s symbol variable, and register the *rec-source-loc* special var. * parser.h (struct parser): New member, rec_source_loc. (rec_source_loc_s, nread): Declared. * parser.y (rlcp_parser): New static function. Like rlcp but does nothing if parser->rec_source_loc is false. (rlc): New macro. (grammar): Replace rlcp uses with rlc, which expands to a call to rlcp_parser. (rlrec): Do nothing if source loc recording is not enabled in the parser. (make_expr, uref_helper): Replace rlcp with rlc. This is possible because these functions have a parser local variable that the macro expansion can refer to. (parse_once): Override rec_source_loc in the parser to 1, so that source loc info is always recorded when parsing is invoked through this function. * txr.1: Documented *rec-source-loc* and added text under read and iread.
* listener: handle incomplete buf literals.Kaz Kylheku2017-07-301-1/+23
| | | | | * parser.c (is_balanced_line): Handle #b'...' syntax with some new states and transitions.
* listener: inform linenoise of incomplete syntax.Kaz Kylheku2017-06-161-1/+151
| | | | | | | | | | | | | | Multi-line expressions can now be entered just using Enter for line breaks without Ctrl-V. Multi-line mode becomes default. * parser.c (is_balanced_line): New static function. (repl): Install is_balanced_line as enter callback in linenoise object. (parse_init): Default *listener-multi-line-p* variable to t. * txr.1: Documentation about multi-line mode updated.
* Refactoring hash bang support; hash bang null hack.Kaz Kylheku2017-05-301-12/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The hash bang mechanism is handled in one place, and disentangled from all parsing logic. It is also endowed with special powers. * eval.c (load): Pass one less argument to read_eval_stream. * match.c (v_load): Likewise. * parser.c (read_eval_stream): hash_bang_support Boolean argument removed. Hash bang logic removed. (load_rcfile): Pass only two arguments to read_eval_stream. * parser.h (read_eval_stream): Declaration updated. * txr.c (remove_hash_bang_line): Function removed. (check_hash_bang): New static function. (txr_main): Recognize the script file name while still inside the argument processing loop. Open the file, and check for a hash bang line, doing the special processing which can generate more arguments from material after a null byte in the hash bang line. The parse_stream variable is now initialized to nil and doubles as a Boolean indicating whether a stream has been opened. After the loop, we remove the script file from the arguments, if we have an open stream and the spec_file_str matches. read_eval_stream is called only with two arguments. * txr.1: Revised existing documentation and described new features.
* cobj: rename poorly named default operation.Kaz Kylheku2017-05-151-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Renaming cobj_hash_op to cobj_eq_hash_op. This function is only appropriate to use with COBJ objects which use eq as their equal funtion. I've spotted one instance of an inappropriate use which have to be addressed by a different commit: the equal function is other than eq, but cobj_hash_op is used for the equal hash. * lib.h (cobj_hash_op): Declaration renamed to cobj_eq_hash_op. * hash.c (cobj_hash_op): Renamed to cobj_eq_hash_op. (hash_iter_ops): Refer to renamed cobj_hash_eq_op. * ffi.c (ffi_type_builtin_ops, ffi_type_struct_ops, ffi_type_ptr_ops, ffi-closure_ops, ffi_call_desc_ops): Likewise. * lib.c (cptr_ops): Likewise. * parser.c (parser_ops): Likewise. * rand.c (random_state_ops): Likewise. * regex.c (char_set_ops, regex_obj_ops): Likewise. * socket.c (dgram_strm_ops): Likewise. * stream.c (null_ops, stdio_ops, tail_ops, pipe_ops, dir_ops, string_in_ops, byte_in_ops, strlist_in_ops, string_out_ops, strlist_out_ops, cat_stream_ops, record_adapter_ops): Likewise. * struct.c (struct_type_ops): Likewise. * sysif.c (cptr_dl_ops): Likewise. * syslog.c (syslog_strm_ops): Likewise. * unwind.c (cont_ops): Likewise.
* listener: :p and :prompt commands.Kaz Kylheku2017-04-061-0/+8
| | | | | | | | | * parser.c (repl): Support :p and :prompt commands for printing the current prompt, which is useful in plain mode. * txr.1: Document the new commands under Interactive Listener. Also plain mode is documented again here, though it is described for -n/--noninteractive.
* Connect -n option to linenoise noninteractive mode.Kaz Kylheku2017-04-041-0/+3
| | | | | | | | | | * parser.c (repl): Set noninteractive mode from noninteractive option. * txr.c (help): Mention effect of -n upon listener. * txr.1: Documented effect of -n/--noninteractive on the listener.
* listener: completion sensitive for slots and methods.Kaz Kylheku2017-03-211-8/+19
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | When completing .prefix[TAB], .(prefix[TAB] or .[prefix[TAB], restrict identifiers to the appropriate namespace. The former will report only symbols from the relevant package which are struct slots; the latter further restricts it to those which are static slots defined as functions. * lib.c (symbol_visible): Static function becomes extern. * lib.h (symbol_visible): Declared. * parser.c (find_matching_syms): par parameter is renamed kind and can hold additional values 'S' (slots) and 'M' (methods). New get_slot_syms function is used to fetch the slots, as necessary, instead of the visible syms, if the kind is 'S' or 'M'. The same loop as before (with the minor change of recognizing 'S' and 'M' also) performs the prefix matching. (provide_completions): Recognize . .( and .[ prefix, calculating the kind argument of find_matching_syms in a new way. * struct.c (get_slot_syms): New function. * struct.h (get_slot_syms): Declared. * txr.1: Add some notes about this under the description of completion. The full rules are not given though; let the user discover.
* Rename badly named default_bool_argKaz Kylheku2017-03-171-4/+4
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * lib.h (default_bool_arg): Inline function renamed to default_null_arg. * eval.c (if_fun, pad, ginterate, giterate, range_star, range, constantp, macroexpand_1, macro_form_p, expand_with_free_refs, do_expand, eval_intrinsic, func_get_name, make_env_intrinsic): Follow rename. * arith.c (lognot): Likewise. * gc.c (gc_finalize): Likewise. * glob.c (glob_wrap): Likewise. * hash.c (group_reduce, gethash_n): Likewise. * lib.c (print, multi_sort, lazy_str, vector, iff, tok_str, split_str_keep, search_str, remove_if, val): Likewise. * match.c (match_fun): Likewise. * parser.c (lisp_parse_impl, regex_parse): Likewise. * rand.c (make_random_state): Likewise. * regex.c (read_until_match, search_regex, regex_compile): Likewise. * socket.c (sock_accept, sock_connect): Likewise. * stream.c (open_files_star, open_files, run, open_process, open_tail, get_string, record_adapter): Likewise. * struct.c (static_slot_ensure, static_slot_ens_rec, clear_struct, make_struct_type): Likewise. * sysif.c (exec_wrap, errno_wrap, cobj_ops_init): Likewise. * unwind.c (uw_capture_cont, uw_find_frames_impl): Likewise.
* Better way for releasing deferred warnings.Kaz Kylheku2017-02-101-1/+1
| | | | | | | | | | | | | | | | | | | | We should be re-throwing deferred warnings as ordinary warnings, not dumping them to a stream. * eval.c (eval_exception): Use uw_release_deferred_warnings instead of uw_dupm_deferred_warnings. (load): Likewise. * parser.c (read_eval_ret_last): Likewise. * txr.c (txr_main): Likewise. * unwind.c (uw_release_deferred_warnings): New function. * unwind.h (uw_release_deferred_warnings): Declared. * txr.1: Documented release-deferred-warnings and updated documentation for dump-deferred-warnings.
* Bump copyright year to 2017.Kaz Kylheku2017-01-231-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | * LICENSE, LICENSE-CYG, METALICENSE, Makefile, args.c, args.h, arith.c, arith.h, cadr.c, cadr.h, combi.c, combi.h, configure, debug.c, debug.h, eval.c, eval.h, filter.c, filter.h, ftw.c, ftw.h, gc.c, gc.h, glob.c, glob.h, hash.c, hash.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, stream.c, stream.h, struct.c, struct.h, sysif.c, sysif.h, syslog.c, syslog.h, termios.c, termios.h, txr.1, txr.c, txr.h, unwind.c, unwind.h, utf8.c, utf8.h, share/txr/stdlib/awk.tl, share/txr/stdlib/build.tl, share/txr/stdlib/cadr.tl, share/txr/stdlib/conv.tl, share/txr/stdlib/except.tl, share/txr/stdlib/getopts.tl, share/txr/stdlib/getput.tl, share/txr/stdlib/hash.tl, share/txr/stdlib/ifa.tl, share/txr/stdlib/package.tl, share/txr/stdlib/path-test.tl, share/txr/stdlib/place.tl, share/txr/stdlib/socket.tl, share/txr/stdlib/struct.tl, share/txr/stdlib/tagbody.tl, share/txr/stdlib/termios.tl, share/txr/stdlib/txr-case.tl, share/txr/stdlib/type.tl, share/txr/stdlib/with-resources.tl, share/txr/stdlib/with-stream.tl, share/txr/stdlib/yield.tl: Add 2017 to all copyright headers and strings.
* Dump deferred warnings in eval_intrinsic.Kaz Kylheku2017-01-151-2/+9
| | | | | | | | | | | | * eval.c (eval_intrinsic): Dump deferred warnings after expansion, unless in the middle of a load. * parser.c (read_eval_ret_last): Bind *load-recursive* around all evaluations to t, then dump warnings if prior value of *load-recursive* is nil. Thus the repl's :read feature behaves like load. (repl_warning): We can now unconditionally defer deferrable warnings here now, whether or not in a load.
* Rebind *stderr* on entry into repl.Kaz Kylheku2017-01-151-0/+4
| | | | | * parser.c (repl): Create a new dynamic env and rebind *stderr* variable to the repl's output stream.
* Deferred warnings.Kaz Kylheku2017-01-131-3/+11
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Warnings about undefined functions and variables are now deferred during loading, so forward references do not generate nuisance diagnostics. * eval.c (load_recursive_s): New symbol variable. (eval_defr_warn): New static function. (op_defvarl, op_defun): Purge any deferred warning about the given function or variable not being defined. (load): Rebind the sys:*load-recursive* special var to true around the load. After the load, dump deferred warnings if the prior binding of sys:*load-recursive* is false. Discard deferred warnings in the case of termination by a nonlocal control transfer. (do_expand): Treat unbound vars and functions as deferrable warnings, specially tagged for individual purging frkm the deferred list. (eval_init): Intern sys:*load-recursive* and initialize load_recursive_s variable. * eval.h (load_recursive_s): Declared. * parse.c (repl_warning): Accept variable arguments. Check whether we are loading and if so, defer deferrable (repl): Adjustment for altered signature of repl_warning. warnings. * txr.c (txr_main): dump deferred warnings after evaluating Lisp stream. * unwind.c (deferred_warnings): New static variable. (uw_throw): When a deferrable warning is caught, suppress the usual message and add it to the deferred_warnings list. (uw_defer_warning, uw_dump_deferred_warnings, uw_dump_deferred_warnings, uw_purge_deferred_warnings): New functions. (uw_late_init): gc-protect deferred_warnings. * unwind.h (uw_defer_warning, uw_dump_deferred_warnings, uw_dump_deferred_warnings, uw_purge_deferred_warnings): New functions declared.
* parser: fix problems at EOF involving #; syntax.Kaz Kylheku2016-12-061-10/+29
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This patch addresses a problem whereby if a TXR Lisp file ends with an erased object notation such as #;(a b c), there is a syntax error. The strategy is to simplify the grammar so that a single yyparse primed with SECRET_ESCAPE_E or SECRET_ESCAPE_I will read either an object, or just one instance of the #; notation. If #;OBJ is read, then the parse tree is returned as the nao value. The caller knows that #;OBJ must have occurred because there are no errors and the parser isn't at EOF, yet there is no parse tree. Then in lisp_parse we can loop on this situation, and make adjustments elsewhere also. So that iread continues to work, we must separate the parser_eof condition from the lookahead token. Under iread, we were clearing the token in prime_parser_post, but that was having the side effect of making the parser look like it is in EOF. We now preserve the EOF indication in a flag, so we can manipulate the token. * parser.h (struct parser): new member, eof. * parser.c (parser_common_init): Initialize new eof flag in parser structure to zero. (prime_parser_post): Set the eof flag if the parser's most recent token is zero. (lisp_parse_impl): Call the parser repeatedly while there are no errors, and no EOF, yet no object has been produced. This indicates that a #; erasure has been processed. (read_eval_stream): Restructure the logic here for clarity. Do not break the loop if error_val was returned from the parser, but there are no errors, and the parser isn't at EOF. This is behavior is probably redundant with respect to the loop in lisp_parse_impl. (read_eval_ret_last): Bugfixes here. Pass an error indicating value down to lisp_parse, like in read_eval_stream and make the logic similar. (parser_eof): Just return an indication based no the eof flag. * parser.y (hash_semis_n_expr, hash_semis_i_expr, ignored_i_exprs, ignored_n_exprs): Grammar rules removed. (hash_semi_or_n_expr, hash_semi_or_i_expr): New grammar rules. (spec): Retarget SECRET_ESCAPE_E and SECRET_ESCAPE_I cases to new rules. (parse): Clear eof flag to zero.
* Expander warns about unbound variables.Kaz Kylheku2016-11-261-0/+12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * eval.c (eval_exception): New static function. (eval_error): Reduced to wrapper around eval_exception. (eval_warn): New function. (me_op): Bind the rest symbol in a shadowing env to suppress watnings about unbound rest. (do_expand): Throw a warning when a bindable symbol is traversed that has no binding. (expand): Don't install atoms as last_form_expanded. * lib.c (warning_s, restart_s, continue_s): New symbol variables. (obj_init): Initialize new symbol variables. * lib.h (warning_s, restart_s, continue_s): Declared. * lisplib.c (except_set_entries): New entries for ignwarn and macro-time-ignwarn. * parser.c (repl_warning): New static function. (repl): Use repl_warning function as a handler for warning exceptions: to print their message and then continue by throwing a continue exception. * parser.y (warning_continue): New static function. (parse_once): Use warning_continue to ignore warnings. In other words, we suppress warnings from Lisp that is mixed into TXR pattern language code, because this produces too many false positives. * share/txr/stdlib/except.tl (ignwarn, macro-time-ignwarn): New macros. * share/txr/stdlib/place.tl (call-update-expander, call-clobber-expander, call-delete-expander): Ignore warnings around calls to sys:expand, because of some gensym-related false positives (we expand code into which we inserted some gensyms, without having inserted the constructs which bind them. * tests/011/macros-2.txr: Suppress unbound variable warnings from a test case. * tests/012/ifa.tl: Bind unbound x y variables in one test case. * tests/012/struct.tl: Suppress unbound variable warnings in some test cases. * uwind.c (uw_throw): If a warning is unhandled, then print its message with a "warning" prefix and then throw a continue exception. (uw_register_subtype): Eliminate the check for sub already being a subtype of sup. This allows us to officially register new types against t. (uw_late_init): Register continue exception type as a subtype of the restart type. Formally register warning type. * txr.1: Documented ignwarn.
* bugfix: reading hash literals with circ notation.Kaz Kylheku2016-11-231-1/+12
| | | | | | | | | | | | | | | | | | | The backpatching of literal hash objects containing circular notation labels is incorrect, because it directly mutates the hash keys, without regard for the fact that this alters their hash values. This change makes the test case #1=#H(() (#1# #1#)) work properly: a hash which contains itself as a key and corresponding value. When this object is constructed by the reader, we can do a gethash call on it, using itself as the key, and it emerges as the value. Before this fix, nil would be returned indicating that the key is not found, although it is listed in the table (corrupt hash). * parser.c (circ_backpatch): When traversing a hash, local list of the cells. Then clear the hash, iterate the list of old cells, and re-insert the key-value pairs.
* Completion of fallback list implementation.Kaz Kylheku2016-11-161-2/+28
| | | | | | | | | | | | | | | | | | | | | | | | * lib.c (find_symbol): New function. (symbol_present): Search the fallback list also to determine whether the symbol is visible. * lib.h (find_symbol): Declared. * parser.y (sym_helper): Implement a new behavior for qualified symbols. Interning new symbols is only allowed for packages that have an empty fallback list. * parser.c (get_visible_syms): New static function. (find_matching_syms): Use get_visible_syms to get the list of eligible symbols. This way the fallback list of the package is included if it is the current package. * share/txr/stdlib/package.tl (defpackage): Do not insert a default (:use usr) if there is no :usr clause. Since defpackage is very new, no need for backward compatibility; the amount of code depending on this is likely zero. * txr.1: Documented fallback list feature.
* Handle interpreted functions in circle printing.Kaz Kylheku2016-11-101-0/+7
| | | | | | | | | | | | | | | | | | | Interpreted functions print as #<interpreted fun: name args>, thus repeating some list structure in their notation. This means we must traverse them when populating the object hash during printing, and also when backpatching after parsing. Test case: evaluate and print (let ((s '(lambda (a b c) d))) (list s (eval s))) with *print-circle* enabled. * lib.c (populate_obj_hash): Handle FUN objects of functype FINTERP. * parser.c (circ_backpatch): Likewise.
* Implement *package* special var; package overhaul.Kaz Kylheku2016-11-081-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * eval.c (load): Rebind *package* in the local dynamic environment already established for the sake of *load-path*. By doing this we cause *package* to be restored to its prior value, which allows the loaded file to alter it. Common Lisp works this way. (eval_init): Register *package* variable, with the user package as its default value. * lib.c (package_s): New symbol variable. (intern, rehome_sym): Default the package argument to the current package, not to user_package. (get_user_package, get_system_package, get_keyword_package): Functions removed. (get_current_package): New function. (obj_print_impl): Revise symbol printing. Keyword and uninterned symbols are printed with : and #: prefixes. The remainder are printed with a package prefix if their home package isn't the current package. * lib.h (keyword_package, user_package, system_package): These macros are just straight aliases for the global variables, not going through the lookup mechanism, which was pointless. (cur_package): New macro. (package_s): Declared. (get_current_package): Declared. * lisplib.c (lisplib_try_load): Establish a local dynamic environment, and bind the *package* variable to the user package which the library modules expect. * parser.c (find_matching_syms, provide_completions): Treat unqualified symbols in the current package rather than user package. * parser.y (sym_helper): Intern unqualified symbols in the current package, not user package. * txr.1: Document that the variables user-package, system-package and keyword-package should not be modified. Document the *package* special variable, and that intern and rehome-sym default their package argument to its value. (Here we get rid of wrong references to the undocumented variable *user-package*).
* New #; syntax for erasing following object.Kaz Kylheku2016-11-071-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * parser.c (parser_circ_ref): Don't generate the circular reference if circular suppression is in effect. * parser.h (struct parser): New member, circ_suppress. We use this for suppressing the generation of circular #n# references in erased objects. * parser.l (grammar): Scan #; producing HASH_SEMI token. * parser.y (HASH_SEMI): New token. (hash_semis_n_expr, hash_semis_i_expr, ignored_i_exprs, ignored_n_exprs): New nonterminals, needed for supporting the use of #; in front of top-level forms. (spec): Use hash_semis_n_expr and hash_semis_i_expr instead of n_expr and i_expr. (r_expr): Support object erasure within nested syntax. (yybadtoken): Handle H_SEMI token. (parse): Initialize new circ_suppress member of parser struct to zero. * txr.1: Documented. * genvim.txr (txr_ign_par, txr_ign_bkt, txr_ign_par_interior, txr_ign_bkt_interior): New regions for colorizing erased objects (partial support). (txr_list, txr_bracket, txr_mlist, txr_mbrackets): Include erased objects by including regions txr_ign_par and txr_ign_bkt. * txr.vim, tl.vim: Regenerated.
* repl: don't send error trace to *stderr*.Kaz Kylheku2016-10-211-1/+1
| | | | | | | * parser.c (repl): Pass out_stream rather than std_error to error_trace. I don't remember the original intent here. All it does is create strange puzzling behavior when an error occurs in the middle of a line of output that isn't flushed yet.
* Check call graph circularity in circ_backpatch.Kaz Kylheku2016-10-201-7/+13
| | | | | | | | | | | | | | | | | The circ_backpatch function could suffer runaway recursion, so we must add a cycle check. This could happen due to hitting cyclical objects when traversing structs. Structs have static slots that could contain cyclic objects, as well as construction logic which can generate slots that contain cycles and are not overridden by anything in the literal. * parser.c (circ_backpatch): Take struct circ_stack * argument; extend the circ_stack in recursive calls. Do circular check on entry. (parser_resolve_circ): Pass null pointer as the new stack argument to circ_backpatch.
* Adding notation for cycles and shared structure.Kaz Kylheku2016-10-181-1/+176
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This commit implements the parse-side support for handling a notation that exists in ANSI Common Lisp for specifying objects with cycles and shared substructure. * parser.h (struct parser): New members, circ_ref_hash and circ_count. (circref_s, parser_resolve_circ, parser_circ_def, parser_circ_ref): Declared. * parser.c (circref_s): New symbol variable. (parser_mark): Visit the new circ_ref_hash member of the parser structure. (parser_common_init): Initialize new members circ_ref_hash and circ_count of parser structure. (patch_ref, circ_backpatch): New static functions. (parser_resolve_circ, parser_circ_def, parser_circ_ref): New functions. (circref): New static function. (parse_init): Initialize circref_s as sys:circref symbol. Register sys:circref function. * parser.l (grammar): Scan #<num>= and #<num># notation as tokens, extracting their numeric value. * parser.y (HASH_N_EQUALS, HASH_N_HASH): New token types. (i_expr, n_expr): Adding phrases for hash-equalsign and hash-hash syntax. (yybadtoken): Handle new token types in switch. (parse_once): Call parser_resolve_circ after parsing to rewrite any remaining #<num># references in the structure to the objects they denote. (parse): Reset new struct parse members to initial state. Call parser_resolve_circ after parsing to rewrite any remaining #<num># references.
* Detect cycles in rlcp_tree.Kaz Kylheku2016-10-181-0/+10
| | | | | | | | | | | | | This will be required when the parser becomes capable of creating object graphs with cycles. * parser.c (parser_callgraph_circ_check): New function. * parser.h (struct circ_stack): New struct. (parser_callgraph_circ_check): Declared. * parser.y (rlcp_tree_rec): New static function. (rlcp_tree): Reduced to wrapper for rlcp_tree_rec.
* listener: put each result into linenoise.Kaz Kylheku2016-10-121-0/+1
| | | | | | | | * parser.c (repl): After each successful command that produces a value, not only print the value but also call lino_set_result to install its string representation into the linenoise object, so it is available for insertion via Ctrl-X Ctrl-P.
* Synchronize license comments with LICENSE.Kaz Kylheku2016-10-011-16/+17
| | | | | | | | | | | | | | | | | | | | * Makefile, args.c, args.h, arith.c, arith.h, cadr.c, cadr.h, combi.c, combi.h, configure, debug.c, debug.h, eval.c, eval.h, filter.c, filter.h, ftw.c, ftw.h, gc.c, gc.h, glob.c, glob.h, hash.c, hash.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, share/txr/stdlib/awk.tl, share/txr/stdlib/build.tl, share/txr/stdlib/cadr.tl, share/txr/stdlib/conv.tl, share/txr/stdlib/except.tl, share/txr/stdlib/hash.tl, share/txr/stdlib/ifa.tl, share/txr/stdlib/path-test.tl, share/txr/stdlib/place.tl, share/txr/stdlib/socket.tl, share/txr/stdlib/struct.tl, share/txr/stdlib/termios.tl, share/txr/stdlib/txr-case.tl, share/txr/stdlib/type.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, sysif.c, sysif.h, syslog.c, syslog.h, termios.c, termios.h, txr.1, txr.c, txr.h, unwind.c, unwind.h, utf8.c, utf8.h: Revert to verbatim 2-Clause BSD.
* Overhaul of self-load-path mechanism.Kaz Kylheku2016-09-261-4/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The self-load-path symbol macro is as of now deprecated. It simply expands to *load-path*. *load-path* is a new special variable which is dynamically bound to the path of a file being loaded. * eval.c (self_load_path_s): Global variable renamed to load_path_s. (sys_load): Bind *load-path* around processing of loaded file. (me_load): Expand (load x) simply to (sys:load x *load-path*). (set_get_symacro): Function removed. (reg_symacro): New static function. (eval_init): Initialize renamed load_path_s with interned symbol having the name *load-path*. Register the *load-path* special variable. Set up the sel-load-path symbol macro aliasing for *load-path*. * eval.h (self_load_path_s): Declaration renamed. * match.c (v_load): Bind *load-path* around loading or inclusion. * parser.c (load_rcfile): Bind *load-path* around loading of .txr_profile file. * txr.c (txr_main): Bind *load-path* instead of self-load-path symbol macro. * txr.1: Updated documentation for @(load) directive and load macro. Replaced documentation of self-load-path with *load-path*.
* Bugfix: -Dvar=val not seen in some Lisp code.Kaz Kylheku2016-09-231-3/+7
| | | | | | | | | | | | | | | | | | | TXR Lisp files run from the command line do not see -Dvar=val bindings, whereas -p expressions do. The REPL sees the bindings, but not code loaded from it using (load "file.tl") because they are lexical. Let's keep these bindings as local lexicals for -p and -e forms, but install them as global lexicals for the other situations. * parser.c (repl): Get rid of the local repl_env made from the bindings that are passed in. Instead, before starting the REPL, loop through the bindings and install them as global lexicals with reg_varl. * txr.c (txr_main): Before processing a Lisp file, install the bindings as global lexicals with reg_varl.
* Check for Cygnal when deciding where user home is.Kaz Kylheku2016-07-271-19/+9
| | | | | | | * parser.c (get_home_path): Do not try HOME first and then USERPROFILE. If running on Cygnal, use strictly USERPROFILE, and do not fall back on HOME. In all other situations, try the HOME variable only.
* Handle two possible home dir locations on Cygwin.Kaz Kylheku2016-06-271-1/+27
| | | | | | | | | | | | | | | | | Under the Cygwin port, if we are running in the Cygwin shell enviroment, there is a HOME variable which contains a POSIX path like /home/kaz. This path works fine and we use that. If we are not running in the Cygwin environment, but running as an application that uses the Cygwin DLL, then the HOME variable is still defined, but the path doesn't resolve. We must detect this, and fall back on the USERPROFILE environment variable, which holds something like C:\Users\kaz. * parser.c (get_home_path): New static function, defined separately for Cygwin and other platforms. (repl): Use get_home_path to determine home directory.
* Handle nonexistent HOME env var in repl.Kaz Kylheku2016-06-271-3/+3
| | | | | | | * parser.c (repl): If home is nil, don't try to extract UTF-8 string from histfile, which is also nil. Use the UTF-8 pointer for subsequent checks, since it is that pointer's use which is subject to those checks.
* Fix memory leak in parser object.Kaz Kylheku2016-06-071-0/+1
| | | | | * parser.c (parser_destroy): Don't just clean up the parser_t structure, free it.
* Implement listener variable for selection style.Kaz Kylheku2016-05-191-2/+5
| | | | | | | | | | | * parser.c (listener_sel_inclusive_p_s): New symbol variable. (repl): Install current value of *listener-sel-inclusive-p* variable into linenoise. (parse_init): Initialize the symbol variable and register the Lisp special variable. * txr.1: Documented special variable and selection mode semantics.
* New feature: self-load-path symbol macro.Kaz Kylheku2016-05-181-0/+4
| | | | | | | | | | | | | | | | | | | | | * eval.c (self_load_path_s): New symbol variable. (sys_load): Save, set-up and restore self-load-path around load. (set_get_symacro): New function. (eval_init): Register load function using sys_load_s instead of redundant intern. * eval.h (set_get_symacro): Declared. * match.c (v_load): Save, set-up and restore self-load-path macro. * parser.c (load_rcfile): Likewise. * txr.c (txr_main: Set up self-load-path when opening file. * txr.1: Documented self-load-path.
* Regex syntax errors trigger exception.Kaz Kylheku2016-04-211-1/+5
| | | | | * parser.c (regex_parse): Don't return nil if there were errors; throw a syntax-error exception.