summaryrefslogtreecommitdiffstats
path: root/eval.c
Commit message (Collapse)AuthorAgeFilesLines
* lib: get rid of preprocessor macros for packages.Kaz Kylheku2018-04-051-10/+7
| | | | | | | | | | | | | | | | | | | | | | | The identifiers user_package, system_package and keyword_package are preprocessor symbols that expand to other preprocessor symbols for no good reason. Time to get rid of this. * lib.c (system_package_var, keyword_package_var, user_package_var): Variables renamed to system_package, keyword_package and user_package. (symbol_package, keywordp, obj_init): Fix variable references to follow rename. * lib.h (keyword_package, user_package, system_package): Macros removed. (system_package_var, keyword_package_var, user_package_var): Variables renamed. * eval.c (eval_init): Fix variable references to follow rename. * parser.y (sym_helper): Likewise.
* compiler: bugfix: quasilit cannot use append.Kaz Kylheku2018-04-041-0/+6
| | | | | | | | | | | append is too generic, and produces nil sometimes. Let's use a custom run-time support function sys:fmt-join. * eval.c (fmt_join): New function. (eval_init): Intern sys:fmt-join. * share/txr/stdlib/compiler.tl (expand-quasi): Generate a sys:fmt-join call to combine the pieces rather than append.
* eval: define sys:*load-recursive*Kaz Kylheku2018-04-041-0/+1
| | | | | | | | | * eval.c (eval_init): The existing variable sys:*load-recursive* is formally defined. This is necessary if a form is evaluated from the command line using -p or -e, which somewhere accesses this variable. txr_main sets up the variable dynamicaly, but later. It should have an entry for it in the global environment.
* Implement compiled file loading.Kaz Kylheku2018-04-041-1/+7
| | | | | | | | | | | | | | | | | | | | | | | | | | * 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.
* macro param lists: remove colon hack.Kaz Kylheku2018-04-041-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | Going forward, when : appears as the argument of an optional parameter in destructuring, it is treated as an ordinary object, and not as "this argument is missing". That is now a feature of function calls only. Rationale: interferes with macros. For instance, the pattern (test : then else) doesn't correctly express the arguments of if, because (if x y :) eats the semicolon. The defaulting behavior is not useful because usually there is no default value for optional structure, other than nil. * eval.c (bind_macro_params): Only implement the colon hack under compatibility with 190. * share/txr/stdlib/place.tl (defplace gethash, defplace fun, defplace symbol-function, defplace symbol-macro, defplace symbol-value): Remove uses of : for defaulting the ssetter argument. This illustrates how useless the feature is for macro destructuring; all these just replace with nil. * txr.1: Clarify that macro parameter lists don't implement the colon trick. It was never explicitly specified that this is the case, but could have been inferred from the statements which indicate that macro parameter lists copy the features of function parameter lists. Added compat notes.
* eval/compile: special ops compile-only & eval-only.Kaz Kylheku2018-04-031-0/+2
| | | | | | | | | | | | | | | | These forms will be specially recognized by the file compiler when they appear as top-level forms. eval-only will mean this: only execute this form (possibly after compiling it); do not emit any compiled code into the output file. compile-only will mean: only emit the compiled code into the output file; do not execute it. * eval.c (eval_init): Register special operators compile-only and eval-only. In the interpreter, these are equivalent to progn and so route to op_progn. * share/txr/stdlib/compiler.tl (compiler compile): Similarly to interpreter, handle compile-only and eval-only as progn.
* expander: bugfix: fixed params visible to optionals.Kaz Kylheku2018-03-311-0/+1
| | | | | | | | | | | * eval.c (expand_params_rec): Add the parameter to the macro-time environment before processing rest of parameter list. This is already done for all the symbols of a macro-style destructuring; just not for a simple parameter. This is necessary, because the init forms of optional parameters occur in a lexical environment in which prior parameters are visible. The test case for this is that (lambda (x : (y x))) must not produce a warning about unbound x.
* eval: add missing checks in fun operator.Kaz Kylheku2018-03-301-0/+13
| | | | | | * eval.c (do_expand): When traversing (fun ...) operator, warn if the function isn't defined or if it is being applied to a special operator.
* case macros: translate big case forms to hash+switch.Kaz Kylheku2018-03-291-1/+50
| | | | | | | | | | | | | | | | | | | | | | | | | | | Currently, the case macros (caseq, caseql, casequal, caseq*, caseql* and casequal*) all translate to a cond statement which tries the cases one by one. With this change, larger cases are translated to a lookup through a hash table, which produces an integer value. The integer value is then used as the index in an op:switch form for table lookup dispatch. If the hash lookup fails, then the else-clause is evaluated. op:switch is handled efficiently in the interpreter, and turned into an efficient swtch VM instruction by the new compiler. * eval.c (me_case): Add variables and logic to the function such that while it gathers the materials for the cond-based translation, it also builds materials for a hash-switch-based translation. Then, at the end, a decision is made by looking at how many keys there are and other factors. Because we don't have hash tables based on the eq function, but only eql, we must be careful not to turn caseq into hash lookup, unless we verify that the keys which occur are fixnum integers, characters or symbols.
* eval: bugs/regressions in handling nil in param expansion.Kaz Kylheku2018-03-291-8/+12
| | | | | | | | | | | | | | | | | | | | Due to a number of changes since December 2016, we have two problems in the evaluator: (lambda (nil)) is accepted rather than complaining that nil is not bindable; and (tree-bind (()) '(3)) silently proceeds rather than diagnosing that the atom 3 doesn't match the empty pattern (). * eval.c (expand_opt_params_rec, expand_params_rec): When not expandin macro-style params, check for a parameter not being bindable, and also avoid recursion entirely when not doing macro style. (bind_macro_params): Don't assume that an atom parameter is a variable, but rather tha a non-list parameter is a variable. Otherwise we bind nil rather than treating it as an empty sub-pattern. Before the December 2016 change (744340ab), we were checking bindablep here; the idea was to hoist the detailed checking to expansion time. But then the pattern versus variable distinction was bungled here.
* eval: refactor op_prof to support reuse.Kaz Kylheku2018-03-271-2/+18
| | | | | | | | | | | * eval.c (prof_call): New function, contents based on op_prof. (struct prof_ctx): New struct type. (op_prof_callback): New static function. (op_prof): Reduced to call to prof_call, passing context through to callback which performs the evaluation that is timed. * eval.h (prof_call): Declared.
* compiler: implement defsymacro special op.Kaz Kylheku2018-03-251-0/+9
| | | | | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Handle defsymacro via expand-defsymacro expander. (expand-defsymacro): New function. * eval.c (rt_defsymacro): New static function. (eval_init): register sys:rt-defsymacro intrinsic.
* eval: remove hack of macro deffers evaled on expansion.Kaz Kylheku2018-03-251-2/+3
| | | | | | | | | | | | | | | | | | * eval.c (do_expand): When a defmacro or defsymacro form is traversed, do not evaluate it, except in backward compatibility mode. Unfortunately, this breaks some code. * tests/011/macros-1.txr: A defmacro form has to be wrapped in macro-time. * tests/011/macros-2.txr: Likewise. * tests/011/mandel.txr: Likewise. * tests/012/man-or-boy.tl (defun-cbn): This macro generates a progn which which expects that a defmacro form will come into effect for the subsequent lambda in the same form. We must wrap it in macro-time to make this happen now.
* eval/compiler: run-time support for compiled defun.Kaz Kylheku2018-03-251-8/+18
| | | | | | | * eval.c (rt_defun, rt_defmacro): New static functions. (op_defun): Use static functions. (eval_init): Register sys:rt-defun and sys:rt-defmacro intrinsics.
* eval/compiler: run-time support for compact defvarl.Kaz Kylheku2018-03-251-5/+20
| | | | | | * eval.c (rt_defvarl): New static function. (op_defvarl): Simplified using rt_defvarl. (eval_init): Register sys:rt-defvarl.
* new special op sys:upenvKaz Kylheku2018-03-211-0/+9
| | | | | | | | | | | | | | | | | | | | | | | This is something that will be useful in compiling some forms. At first I added it to the compiler only, but it seems wise to have it in the interpreter also. (sys:upenv form) causes form to be treated as if it were not in the immediately surrounding lexical environment but its parent. Thus (let ((a 1)) (let ((a 2)) (list a (sys:upenv a)))) yields (2 1). This operator needs no special treatment in the expander; it is expanded as a function call. This is not 100% correct in the face of all conceivable use. For instance given (symacrolet ((a 1)) (let ((a 2)) (sys:upenv a))), we probably want sys:upenv to skip the inner environment at expansion time too so that a is replaced by 1. However, it is not documented for application use, and will never be used in such a situation in the compiler. * eval.c (op_upenv): New static function. (eval_init): Register sys:upenv special operator. * compiler.tl (compiler compile): Implement compiled version of sys:upenv.
* expander: bugfix: sys:for-op init forms.Kaz Kylheku2018-03-201-5/+8
| | | | | | | * eval.c (do_expand): The first argument of the sys:for-op special operator isn't "vars" but a sequence of initialization forms. Name the variable appropriately. The neglected expansion of these forms is now performed.
* lib: new ldiff function.Kaz Kylheku2018-03-201-1/+2
| | | | | | | | | | * eval.c (eval_init): Use the old ldiff function under compatibility with 190 or lower. * lib.c (ldiff): Rewritten. (ldiff_old): New function, copy of previous version of ldiff. * lib.h (ldiff_old): Declared.
* compile-toplevel: expand with warnings.Kaz Kylheku2018-03-171-0/+1
| | | | | | | | * eval.c (eval_init): Expose raw expand function as sys:expand*, since sys:expand squelches warnings. * share/txr/stdlib/compiler.tl (usr:compile-toplevel): Use expand* instead of expand.
* quasi: factor out repeated code.Kaz Kylheku2018-03-161-19/+24
| | | | | | | | * eval.c (fmt_tostring, fmt_cat): New static functions. (do_format_field): Replace code block with call to fmt_cat. (fmt_simple, fmt_flex): Insert needed call to fmt_tostring. (subst_vars): Replace blocks of code with calls to fmt_tostring and fmt_cat.
* quasilit: expose access to field formatting.Kaz Kylheku2018-03-161-0/+35
| | | | | | | | | | | | | | | | | | | | | | | | | This is the second round of changes in perparation for compiling the string quasiliterals special form. Having split format_fields into a lower level do_format_field and format_field, we now provide two functions which allow Lisp code to call do_format_field. The sys:fmt-simple function has fixed arguments for the field width/alignment, indexing/slicing, separator and plist. Any of them can be defaulted with nil. This function will be useful when the quasiliteral specifies modifiers that are simple literals or constant expressions. The sys:fmt-flex function takes a variable number of arguments, after the object and the plist. This function has to scan through the arguments and classify them by type: a string is a separator, an integer is a width and left/right alignment and so on. The compiler will use sys:flex when format field modifiers are present whose arguments contain expressions that get evaluated. * eval.c (fmt_simple, fmt_flex): New static functions. (eval_init): sys:fmt-simple and sys:fmt-flex registered.
* quasilit: split format_field into two functions.Kaz Kylheku2018-03-161-46/+55
| | | | | | | | | | | | | | | | | | | | | | | | The objective of this work is to isolate the field-formatting logic so we can target it in the compiler. Currently, the sys:quasi special operator relies on calling subst_vars, which calls format_field. Both subst_vars and format_field perform dynamic evaluation, requiring an environment. In the compiler, this will be replaced by macro-generated logic; but we would like to obtain the use of the lower-level field formatting as a pure function. * eval.c (do_format_field): New static function. Does the field formatting previously done in format_field. Also performs the indexing on the object implied by the numeric or range modifier; but the range or index is already computed and comes in as a parameter. (format_field): Perform the modifier parsing only, requiring the dynamic evaluations via eval_fun, and then call do_format_field on the extracted data. The range indexing on the input sequence is no longer done during the parsing of the modifiers. That unfortunately changes some behaviors that are possible but are fortunately obscure and undocumented.
* structs: spurious hiding of defmeth: fix needed.Kaz Kylheku2018-03-141-1/+1
| | | | | | | | | | * eval.c (op_defun): There is a hidden reference to the sys:defmeth function here, which should have been updated in commit 0ae617f463290ff4463db2e479604808f940cc76 that renamed the function to define-method! Caught this by incidental code inspection, browsing through special forms in the context of working on the compiler.
* eval: remove eval_initing, which does nothing.Kaz Kylheku2018-03-141-11/+0
| | | | | | | | | | | None of the statements which are conditional on eval_initing are ever executed, because no code is interpreted during eval init time; all intrisinc functions are C functions defined using reg_fun. * eval.c (eval_initing): Global variable removed. (op_defun, op_defmacro, eval_init): References to eval_initing and code conditional on it are removed.
* expander bug: sequential vars with no init forms.Kaz Kylheku2018-03-131-1/+2
| | | | | | | | | | | | | | | | The test case for this is (let* (a (b a))) which raises suspicion by diagnosing an "unbound variable a" error against the (b a) var-init pair. The error goes away if we make it (let* ((a nil) (b a))), a perfectly equivalent form. The diagnostic is just a symptom; the problem is that in the case when a doesn't have an initform, the (b a) var-init pair is being incorrectly expanded in an environment that hasn't been extended with the a variable. * eval.c (expand_vars): In the sequential binding situation (let*), we must extend the environment for each variable in the no-init-form case exactly as we do in the with-init-form case.
* New: virtual machine with assembler.Kaz Kylheku2018-03-101-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This commit is the start of compiler work to make TXR Lisp execute faster. In six days of part time work, we now have a register-style virtual machine with 32 instructions, handling exceptions, unwind-protect, lexical closures, and global environment access/mutation. We have a complete assembler and disassembler for this machine. The assembler supports labels with forward referencing with backpatching, and features pseudo-ops: for instance the (mov ...) pseudo-instruction chooses one of three kinds of specific move instruction based on the operands. * Makelfile (OBJS): Add vm.o. * eval.c (lookup_sym_lisp1): Static function becomes external; the virtual machine needs to use this to support that style of lookup. * genvmop.txr: New file. This is the generator for the "vmop.h" header. * lib.c (func_vm): New function. (generic_funcall): Handle the FVM function type via new vm_execute_closure function. In the variadic case, we want to avoid the argument copying which we do for the sake of C functions that get their fixed arguments directly, and then just the trailing arguments. Thus the code is restructured a bit in order to switch twice on the function type. (init): Call vm_init. * lib.h (functype_t): New enum member FVM. (struct func): New member in the .f union: vm_desc. (func_vm): Declared. * lisplib.c (set_dlt_entries_impl): New static function, formed from set_dlt_entries. (set_dlt_entries): Reduced to wrapper for set_dlt_entries_impl, passing in the user package. (set_dlt_entries_sys): New static function: like set_dlt_entries but targetting the sys package. (asm_instantiate, asm_set_entries): New static functions. (lisplib_init): Auto-load the sys:assembler class. * share/txr/stdlib/asm.tl: New file. * vm.c, vm.h, vmop.h: New files.
* args: overhaul for clarity and reduced consing.Kaz Kylheku2018-03-091-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * args.c (args_normalize): Renamed to args_normalize_exact, because this tries to split the arguments between an exact array fill quantity and trailing list. Not all places using this function actually need an exact fill, which causes unnecessary consing when args->fill is reduced in order to move items to args->list. (args_normalize_least): New function. Variant of args_normalize that can be used by functions which only require a minimum fill. (args_normalize_fill): Use args_normalize_least rather than args_normalize_exact. This reduces consing in generic_funcall, in handling variadic calls where arrayed arguments have been supplied for trailing parameters. * args.h (args_normalize): Renamed to args_normalize_exact. (args_normalize_least): Declared. (args_get_list, args_get_rest): Use args_normalize_exact. (args_clear): Inline function removed. Was used only in one place in generic_funcall and is no longer. * eval.c (gather_free_refs): Use args_normalize_least. (prod_common): Use args_normalize_exact. * ffi.c (ffi_call_wrap): Use args_normalize_least. * lib.c (generic_funcall): Use args_normalize_least in switch statement that handles various callable non-function objects. When copying args, ensure that there are ARGS_MIN. A different strategy is used for producing the trailing args for variadic calls, further reducing consing. Rather than normalize the args to the fixed number, and then set args->fill to zero so that args contains just the list, we use args_cat_zap_from to create a copy of the args in which the fixed ones are trimmed out. The resulting args is not renormalized to be purely a list so no consing or list traversal takes place. If the rebalancing is needed, the called function will have to do it. (dwim_set): Streamline the code that handles hashes assigned via two or three args. * struct.c (method_args_fun, umethod_args_fun): Use args_normalize_exact.
* New listener feature: greedy evaluation feature.Kaz Kylheku2018-02-171-0/+26
| | | | | | | | | | | | | | | | * 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.
* Lisp load function supports .txr files.Kaz Kylheku2018-02-161-8/+26
| | | | | | | | | | | | * eval.c (load): Instead of throwing error when a .txr file is opened, process it according to sensible requirements. * match.c (v_load): Store bindings in the current environment frame before evaluating Lisp, and then update afterward. This allows .txr files loaded from Lisp to continue matching with the current bindings and extend those bindings. * txr.1: Update documentation of load.
* bugfix: broken expansion of sys:lisp1-setq places.Kaz Kylheku2018-02-151-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | This bug shows up as a spurious warning and incorrect expansion from a from like (do set [@1 x] y). In this situation, sys:lisp1-setq is involved in the assignment to the place denoted by @1, because of the way the do operator expands the (set [@1 x] y) expression. The @1 meta-variable is replaced by a gensym, but some intermediate expansion takes place in an environment which has no binding for the gensym, causing the place to be treated as if it were a global variable, using sys:lisp1-setq. The subsequent real expansion in the environment in which the gensym is now bound then calls upon the expansion of sys:lisp1-setq, which proceeds via the expand_lisp1_setq function. But now the variable has a lexical binding. This bug doesn't show up in ordinary expressions like (set [foo x] y) which is why it went undetected for a year. * eval.c (expand_lisp1_setq): Fix the missing symbol in the generated code for the case when the symbol has a lexical variable binding. We must emit (sys:setq <sym> <value>), not (sys:setq <new-value>).
* 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.
* bugfix: op module inversely depends on sys:l1-val.Kaz Kylheku2018-02-141-1/+64
| | | | | | | | | | | | | | | | | | | The problem is that the lop macro in op.tl generates code that uses sys:l1-val. That requires the place.tl module. But there is no autoload trigger for sys:l1-val. Even if there were, it wouldn't work because op.tl is lower level w.r.t. place.tl; place.tl uses op.tl. Let's just rewrite sys:l1-val and sys:l1-setq in C, so they live in the run-time core. * eval.c (sys_l1_val_s, sys_l1_setq_s): New symbol variables. (me_l1_val, me_l1_setq): New static functions. (eval_init): Intern sys:l1-setq and sys:l1-val symbols, binding these to the macro expanding functions. * share/txr/stdlib/place.tl (sys:l1-setq, sys:l1-val): Macros removed.
* cleanup: harmonize lisp1-eval-related symbol variables.Kaz Kylheku2018-02-141-6/+6
| | | | | | | | | | | | | | * eval.c (sys_lisp1_value_s): Declaration moved to be collocated with lisp1_setq_s. (lisp1_setq_s): Variable renamed to sys_lisp1_setq_s to match sys_lisp1_value_s. (do_expand): Follow rename of lisp1_setq_s. (eval_init): Follow rename; collocate initialization of vars. * protsym.c (lisp1_setq_s): Manually renamed to sys_lisp1_setq_s instead of full regeneration, which we do at release time.
* term: move near site of use.Kaz Kylheku2018-01-071-0/+7
| | | | | | | | | * eval.c (term): Function here from lib.c, and changed to static. It is used only by iapply. * lib.c (term): Function moved to eval.c. * lib.h (term): Declaration removed.
* Use rplaca and rplacd instead of set over car_l/cdr_l.Kaz Kylheku2018-01-011-2/+2
| | | | | | | | | | | | | | | | | | | | | | | 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.
* New methods rplaca and rplacd.Kaz Kylheku2017-12-301-2/+2
| | | | | | | | | | | | | | | * eval.c (eval_init): Register rplaca and rplacd using new rplaca_s and rplacd_s symbol variables. * lib.c (rplaca_s, rplacd_s): New symbol variables. (rplaca): Handle struct object via rplaca method, if it has one, otherwise lambda-set, if it has that, or else error out. (rplacd): Handle struct object via rplacd method. * lib.h (rplaca_s, rplacd_s): Declared. * txr.1: Documented rplaca and rplacd methods.
* read, iread: source location recording now conditional.Kaz Kylheku2017-12-291-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* New functions: rlist and rlist*.Kaz Kylheku2017-12-181-0/+40
| | | | | | | | | | These easily express discontinuous ranges. * eval.c (rlist_fun, rlist_star_fun, rlist, rlist_star): New static functions. (eval_init): Register rlist and rlist* intrinsics. * txr.1: Documented.
* expander: do constant folding of a..b range exprs.Kaz Kylheku2017-12-181-0/+9
| | | | | | | | | * eval.c (do_expand): In the function call case, check for the operator being the rcons function. If it is called with exactly two arguments and they are constantp in the given environment, then evaluate them and replace with a range literal object. Rationale: ranges often appear in constant form like [array 1..:] and whatnot.
* prof: deal with overflowing mem counters.Kaz Kylheku2017-12-041-2/+17
| | | | | | | | * eval.c (op_prof): Deal with the cases when alloc_bytes_t value cannot be converted to a val in a single call to unum. * lib.h (SIZEOF_ALLOC_BYTES_T): New macro.
* bugfix: code-walk the result of a declined macro.Kaz Kylheku2017-11-291-2/+3
| | | | | | | | | | | | | | | | When a form is a macro, but the macro declines to expand the form, the form must still be code walked; we can't just return it and be done. For instance if it is a function call, its argument expressions have to be expanded. This also causes undefined function warning to be generated properly if a macro declines, and the resulting form is a function call to a not-yet-defined function. * eval.c (do_expand): If expand_macro yields the original form, branch backwards to re-execute the whole if statement again. Use the fact that the local variable macro is now non-nil to skip the macro expansion case.
* macros: expand declined form in outer env.Kaz Kylheku2017-11-241-0/+14
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This patch implements a new requirement which clarifies what happens when a macro declines to expand a form. To decline expanding a form means to return the original form (same object) without returning it. The expander detects this situation with an eq comparison on the input and output. The current behavior is that no further attempts are made to expand the form. This is problematic for various reasons. In code which is expanded more than once, this can lead to the expansion being different between the expansion passes. In the first pass, a local macro M might decline to expand a form. In the second pass, the local macro definition no longer exists, and the form does get expanded by a global macro M. This kind of instability introduces a flaw into complex macros which expand their argument material more than once. The new requirement is that if a macro definition declines to expand a macro, then a search takes place through the outer lexical scopes, and global scope, for the innermost macro definition which will expand the form. The search tries every macro in turn, stopping if a macro is found which doesn't decline the expansion, or after passing the global scope. * eval.c (expand_macro): Implement new searching behavior. * txr.1: Documented the expansion declining mechanism under defmacro and macrolet. * tests/011/macros-3.tl: New file. * tests/011/macros-3.expected: New file.
* New function: grade.Kaz Kylheku2017-11-231-0/+1
| | | | | | | | | | | | Inspired by APL. * eval.c (eval_init): Register grade intrinsic. * lib.c (grade): New function. * lib.h (grade): Declared. * txr.1: Documented.
* caseq, caseql, casequal: improvement in expansion.Kaz Kylheku2017-10-251-0/+3
| | | | | | | | | | * eval.c (me_case): When a list of case keys is one element long, reduce it to an atom. Then a simple equality is applied whether the item is equal to the key, rather than whether it is a member of a list containing that one key. This helps with the (t) case which is mandatory, since t is ruled out as a key.
* tprint and -t option: handle infinite list.Kaz Kylheku2017-10-121-11/+32
| | | | | | | | | | | | | | | | Test case: txr -t '(gun "foo")' must run in constant memory. * eval.c (tprint): Rewritten to iterate over lists using open loop rather than mapdo. Classification of the sequence is done using the new seq_info, as must be for all new sequence functions. * txr.c (txr_main): Implementation of -t, -p and -P captures the result of the expression in a variable whose value is zapped when it is passed to the function. A gc_hint is added so that this isn't optimized away. Thus, this code won't hold on to the original pointer to a lazy, infinite list.
* cleanup: remove unnecessary header includes.Kaz Kylheku2017-09-191-1/+0
| | | | | | | | | | * eval.c: doesn't need rand.h. * filter.c: doesn't need gc.h. * parser.l: doesn't need eval.h. * parser.y: doesn't need utf8.h, stream.h, args.h or cadr.h.
* new: macroexpand-lisp1 and macroexpand-1-lisp1.Kaz Kylheku2017-08-311-4/+28
| | | | | | | | | | | | | | | | * eval.c (do_macroexpand_1, do_macroexpand): New static functions; take symbol macro lookup function poiner as argument. (macroexpand_1): Reimplemented as wrapper around do_macroexpand_1. (macroexpand): Reimplemented as wrapper around do_macroexpand. (macroexpand_1_lisp1, macroexpand_lisp1): New static functions. (eval_init): Registered intrinsics macroexpand-1-lisp1 and macroexpand-lisp1. * txr.1: Documented.
* New function: inverse of cumulative normal dist.Kaz Kylheku2017-08-311-0/+1
| | | | | | | | | | * arith.c (inv_cum_norm): New function. * arith.h (inv_cum_norm): Declared. * eval.c (eval_init): Register inv-cum-norm intrinsic. * txr.1: Documented.
* Rewriting op/do macros in Lisp.Kaz Kylheku2017-08-291-3/+10
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The new implementation treats the @1, @2 ... @rest op arguments as local macros, leveraging the power of the macro expander to perform the substitution which renames these to gensyms. As a result, the implementation is correct. The old implementation blindly walks the tree structure doing the substitution, so that @1 is substituted even though it is in a quoted literal: [(op list '(@1)) 42] -> ((#:arg-01-0166)) under the new implementation, '(@1) is left alone: [(op list '(@1)) 42] -> ((@1) 42) * eval.c (expand_quasi): Because the new op macro doesn't rudely reach into quasi forms to substitute sys:var elements, relying on macro expansion, we must now macro-expand sys:var elements. The sys:var macro created by op is smart enough to skip the compound ones that have modifiers; they are handled via the inner expansion of the symbol. That is to say, `@@1` contains the structure (sys:var (sys:var 1)). The sys:var macro ignores the outer sys:var. But existing behavior in expand_quasi expands the inner (sys:var 1), so the substitution takes place. (eval_init): Do not register the hacky old op and do macros, except in compatibility mode with 184 or older. * lisplib.c (op_set_entries, op_instantiate): New functions. (dlt_register): Register auto-loads for op and do macros via new functions, except when in compatibility mode with 184 or older, in which case we want the old build-in hacky op to be used. * share/txr/stdlib/op.tl: New file. * txr.1: Fixed or removed no-longer-true text which hints at special hacks implemented in the op expander. Added compatibility notes for all new compat-switched op behaviors.
* Allow sys:var and sys:expr redefinition.Kaz Kylheku2017-08-281-0/+2
| | | | | * eval.c (builtin_reject_test): Suppress warning if the symbol is sys:var or sys:expr.