summaryrefslogtreecommitdiffstats
path: root/eval.c
Commit message (Collapse)AuthorAgeFilesLines
...
* Muffle only deferrable warnings in sys:expand.Kaz Kylheku2017-02-091-1/+1
| | | | | | | | | | | | | | | | | The problem is that if some macrology is performing its own expansion with sys:expand, and if all warnings are muffled in sys:expand, it means that some warnings will never be seen. Expansion is the last chance to produce warnings issued by macros. Once they are expanded, a redundant expansion pass won't issue the warnings any more. * eval.c (no_warn_expand); Use the uw_muffle_deferrable_warning handler isntead of uw_muffle_warnings. * unwind.c (uw_muffle_deferrable_warning): New function. * unwind.h (uw_muffle_deferrable_warning): Declared.
* New system function: expand-with-free-refs.Kaz Kylheku2017-02-081-0/+35
| | | | | | | | | | | | | | | | This interface to the expander returns not only the expanded form, but also a list of the free variables and functions occurring in that form. This interface to the expander works by installing a handler which intercepts and muffles warnings. When a warning occurs indicating an unbound variable or function, the information is retained. The expander then returns the information along with the expanded form. * eval.c (gather_free_refs): New static function. (expand_with_free_refs): New function. (eval_init): Register sys:expand-with-free-refs intrinsic.
* Expose rlcp_tree function.Kaz Kylheku2017-02-041-0/+1
| | | | | | | * eval.c (eval_init): Register rlcp-tree intrinsic. * txr.1: Documented rlcp-tree. Also documented that rlcp doesn't overwrite location info.
* bugfix: "expansion at nil" in error trace.Kaz Kylheku2017-02-031-1/+1
| | | | | * eval.c (error_trace): Wrong variable was checked as basis for selecting one of two variants of diagnostic.
* Dump deferred warnings when eval exception thrown.Kaz Kylheku2017-02-031-0/+2
| | | | | | | | * eval.c (eval-exception): Call uw_dump_deferred_warnings before throwing exception. The warnings could provide valuable clues about the cause of the error. * share/txr/stdlib/error.tl (compile-error): Likewise.
* Expand sys:setqf separately, with better accuracy.Kaz Kylheku2017-02-031-1/+25
| | | | | | | * eval.c (expand_setqf): New static function. (do_expand): Handle sys:setqf via new function, which avoids expanding the symbol, checks that it isn't a lexical function, and warns about an unbound function.
* Forbid lexical function mutation.Kaz Kylheku2017-02-031-1/+39
| | | | | | | | | | | * eval.c (expand_lisp1_setq): New static function. (op_setqf): Check that the function binding which was found is the global one. If not, throw an error that lexical functions can't be mutated. (do_expand): Handle sys:lisp1-setq operator expansion seprately from the other setq operators, via the new function, which enforces an expansion-time check against mutation of lexical functions.
* Expander check for macro destination in setq forms.Kaz Kylheku2017-02-031-0/+4
| | | | | * eval.c (do_expand): Throw an error if the destination is a symbol macro which requires expanding.
* When expanding sys:lisp1-value, check for bad form.Kaz Kylheku2017-02-031-1/+5
| | | | | * eval.c (expand_lisp1_value): If the first argument is an object other than a bindable symbol, throw an error.
* More accurate error wording from Lisp-1 operators.Kaz Kylheku2017-02-031-2/+2
| | | | | | | * eval.c (op_lisp1_setq, op_lisp1_value): If a Lisp-1 binding is not found, this is because it is neither a function nor variable, not because it is not a variable. The error message now reflects this.
* Expose expand_params as sys:expand-params.Kaz Kylheku2017-01-291-0/+1
| | | | | * eval.c (eval_init): Register sys:expand-params intrinsic bound to expand_params.
* bugfix: :filter not handled right in output var.Kaz Kylheku2017-01-261-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This issue was fixed in quasiliterals only. Because of the implementation duplicity between output vars and quasiliteral vars, we have to fix it in two places. When the parser handles quasiliterals, it builds vars without expanding the contents. The quasiliteral expander takes care of recognzing (sys:var ...) forms and properly handles them and their attributes, avoiding expanding the argument of a :filter keyword. When the parser handles an o_var that is a braced variable, it calls expand on its contents right there, then builds the (sys:var ...) form from the expanded contents. Why don't we just call expand_quasi in the o_var rule to have a single (sys:var ...) form expanded exactly how it is done in quasiliterals. * eval.c (expand_quasi): Change static function to external. * eval.c (expand_quasi): Declared. * parser.y (o_var): Construct an unexpanded (sys:var ...) form, and then wrap it in a one-element list. This is a de-facto quasi-items list, which can be expanded by expand_quasi. Then we pull the car of the expansion to get our expanded var.
* New catch*, giving access to exception symbol.Kaz Kylheku2017-01-251-1/+4
| | | | | | | | | | | | | | | | | | * eval.c (op_catch): The sys:catch operator now passes the exception symbol as the first argument of each clause. This means the catch macro must be adjusted. * share/txr/stdlib/except.tl (catch): Macro now inserts a gensym dummy first argument into each clause to take the symbol passed by the sys:catch operator. (catch*): New macro, which is identical to the previous catch macro, and thus exposes the symbol passed as the first argument. * txr.1: Documented catch*. * tests/012/struct.tl: Some gensym numbers need adjusting in one test case.
* bugfix: wrong context form in mac-param-bind.Kaz Kylheku2017-01-251-1/+1
| | | | | | | * eval.c (do_expand): Expander for mac-param-bind is redundantly expanding the main expression and taking that as the epanded context form, rather than expanding the context form.
* Expose plist to alist functions.Kaz Kylheku2017-01-241-0/+2
| | | | | | | | * eval.c (eval_init): Register plist-to-alist and improper-plist-to-alist intrinsics. * txr.1: Documented improper plist concept and new functions.
* New memp function for searching a plist.Kaz Kylheku2017-01-241-0/+1
| | | | | | | | | | * eval.c (eval_init): Register memp intrinsic. * lib.c (memp): New function. * lib.h (memp): Declared. * txr.1: Documented.
* bugfix: wrong macro env across param expansion.Kaz Kylheku2017-01-241-10/+22
| | | | | | | | | | | | | | | | The issue is that optional argument init forms have visibility to prior arguments. However, they are being expanded in the original macro environment which doesn't take into account any preceding variable bindings. This is wrong: the preceding variables must shadow any symbol macros in the outer environment. * eval.c (expand_opt_params_rec, expand_params_rec): Create a var shadowing macro environment for every parameter name (or destructuring parameter list) that is traversed, and use that macro environment to process the remaining parameters. (make_var_shadowing_env): Allow the function to take a single symbol instead of a list of symbols.
* Support keyword params via :key param list macro.Kaz Kylheku2017-01-231-3/+7
| | | | | | | | | | | | | | | | | | * eval.c (expand_param_macro): Use lisplib_try_load to retry failed parameter macro lookup, thereby supporting auto-loading of modules that define parameter macros. * lisplib.c (keyparams_set_entries, keyparams_instantiate): New static functions. (lisplib_init): Support autoloading of keyparams.tl via new functions. * share/txr/stdlib/keyparams.tl: New file. * txr.1: Documented :key param list macro. * checkman.txr: Support "Parameter list macro" documentation section type.
* diagnose (:whole . blah) as dangling :whole.Kaz Kylheku2017-01-231-1/+1
| | | | | * eval.c (bind_macro_params): Test that the rest of the param list after the keyword is consp, not just non-nil.
* bugfix: :whole and :form allow destructuring.Kaz Kylheku2017-01-231-13/+13
| | | | | | | | | | | | | | In bind_macro_params allow the argument of :whole and :form to be a destructuring pattern. Yet, in expand_params, we are wrongly requiring it to be a bindable symbol, thus blocking the feature. * eval.c (expand_opt_params_rec): Only require the argument of a keyword to be a bindable symbol if that keyword is :env. (expand_params_rec): Some refactoring here not to recursively expand keyword as parameters, removing a hacky test in the atom case. Also car_ex is renamed to param_ex. Other than that, same fix as in expand_opt_params_rec.
* 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.
* bugfix: expansion order in face of param macros.Kaz Kylheku2017-01-221-27/+33
| | | | | | | | | | | | | | | | | | | | | | | We are following an incorrect expansion order for parameters and bodies in the face of parameter macros. We are expanding the body first, using the raw, untransformed parameters, which is wrong. Secondly, we then neglect to expand the body which emerges from param expansion. The fix is to pass the unexpanded body to expand_params. Then expand the body which emerges. This also fixes another bug: the macro env passed to param expanders is documented as excluding the parameters. This is now actually true. * eval.c (expand_macrolet, expand_tree_cases, expand_catch_clause): Rearrange expansion logic surrounding call to expand_params. (do_expand): Likewise, and also introduce expansion for the sys:with-dyn-rebinds operator. This is now needed because under the new order, with-dyn-rebinds is now introduced into unexpanded code. If it isn't expanded, then it then wrongly protects its enclosed forms from expansion.
* Don't expand arg in @{var :filter arg}.Kaz Kylheku2017-01-221-1/+27
| | | | | | | * eval.c (expand_var_mods): New static function. (expand_quasi): Use expand_var_mods to expand variable modifies, rather than expand_forms. The new expand_var_mods avoids expanding the argument of the :filter keyword.
* Muffle expansion warning in op macro.Kaz Kylheku2017-01-181-2/+6
| | | | | * eval.c (me_op): Install handler to intercept warnings and route them to uw_muffle_warning.
* Bugfix: macros not expanded in quasiliterals.Kaz Kylheku2017-01-181-0/+2
| | | | | | * eval.c (expand_quasi): Add all-important missing case which expands compound forms. This looks like a txr-160 regression.
* Use tentative def mechanism for functions and vars.Kaz Kylheku2017-01-151-0/+6
| | | | | | * eval.c (do_expand): When walking a defun or defvarl, register them as tentative defs. Thus warnings are nicely supressed in code like (progn (defun foo ()) (foo)).
* Dump deferred warnings in eval_intrinsic.Kaz Kylheku2017-01-151-1/+3
| | | | | | | | | | | | * 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.
* Functions for error reporting out of macros.Kaz Kylheku2017-01-151-0/+2
| | | | | | | | | | | | | | | | | * eval.c (eval_init): Register sys:ctx-form and sys:ctx-name intrinsics. * lisplib.c (error_set_entries, error_instantiate): New static functions. (lisplib_init): Register autoloading of error.tl via new functions. * share/txr/stdlib/error.tl: New file. * struct.c (make_struct_type): Purge deferred warnings. * unwind.c (uw_late_init): Register purge-deferred-warning intrinsic.
* bugfix: diagnose dotted form calls consistently.Kaz Kylheku2017-01-131-13/+13
| | | | | | | * eval.c (do_expand): Warn about unbound functions or non-bindable symbols in function position regardless whether the form is a dotted form that was subject to the apply transformation.
* Deferred warnings.Kaz Kylheku2017-01-131-8/+58
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* Allow last var to be omitted in whilet.Kaz Kylheku2017-01-061-3/+13
| | | | | | | * eval.c (me_whilet): insert gensym if last var is missing. Warn if init-form looks like a variable. * txr.1: Documented by copy and paste from iflet.
* New Lisp feature: param list expander.Kaz Kylheku2017-01-041-6/+40
| | | | | | | | | | | | | | | | | | | | | * eval.c (pm_table): New static variable. (expand_param_macro): New static function. (expand_params): Expand parameter list macros via expand_param_macro. (eval_init): gc-protect pm_table and initialize it. Register *param-macro* variable. * lisplib.v (pmac_set_entries, pmac_instantiate): New static functions. (lisplib_init): Register autoloading of pmac.tl via new functions. * share/txr/stdlib/pmac.tl: New file. * txr.1: Notes under defun, lambds, flet/labels and defmacro about the existence of parameter macros which add to the syntax. New Parameter List Macros section. Documented *param-macro* and define-param-expander.
* bugfix: sys:setq bindable check must be warning.Kaz Kylheku2017-01-011-1/+7
| | | | | | | | | | | | | | | The problem is that during the expansion of something like (do inc @1), the place expansion will generate a (sys:setq @1 ...) form which undergoes expansion before the processing which converts @1 to a gensym. But now that throws an error during the expansion of the sys:setq form that @1 isn't a bindable symbol. Since warnings are suppressed during this expansion phase, we can make it a warning. * eval.c (not_bindable_warning): New static function. (do_expand): For the assignment special forms, throw a warning if the target isn't a bindable symbol, not an error.
* Bugfix: repeated expansion of catch unstable.Kaz Kylheku2016-12-311-12/+17
| | | | | | | | | | | | | | | | | | | | | | | | | | | It turns out we have a silly problem: catch is a special operator, which undergoes a macro-like expansion which alters its syntax, but uses the same operator symbol. We turn catch into a macro which expands to a sys:catch operator. * eval.c (sys_catch_s): New symbol variable. (expand_catch): Function now expands sys:catch forms without altering any syntax. (do_expand): Check for sys:catch rather than catch. Call expand_catch differently: it takes the form now instead of just the arguments, so it can return the original form if no expansion takes place. (eval_init): Initialize sys_catch_s variable. Change registration of op_catch to sys:catch symbol. * lisplib.c (except_set_entries): Add catch to the list of autoload symbols for except.tl. * share/txr/stdlib/except.tl (catch): New macro for transforming catch to sys:catch. * txr.1: Reclassify catch operator as a macro.
* Check for non-symbols in catch clauses.Kaz Kylheku2016-12-311-0/+2
| | | | | * eval.c (expand_catch_clause): Check added that clause sym must be a symbol.
* Check assignment special forms at expansion time.Kaz Kylheku2016-12-291-35/+29
| | | | | | | | | | | | | | * eval.c (lispq_setq_s, setqf_s): New symbol variables. (op_defvarl, op_defsymacro, op_defmacro, op_setq, op_lisp1_setq, op_setq): Drop bindability checks. In the case of defmacro, this is already taken care of so the check is redundant. (do_expand): Add bindable check to defvar_s and cousins. In the function form fallback case, check for the various assignment operators and check their argument count and bindability of destination symbol. (eval_init): Initialize new symbol variables; register corresponding special operators using variables.
* Reintroduce lambda checks and macro param bugfix.Kaz Kylheku2016-12-291-37/+67
| | | | | | | | | | | | | | | | | | | | | | Fix nested macro parameters not being expanded properly in all cases. Diagnose uses of :env, :form and :whole in function parameter lits. * eval.c (expand_opt_params_rec, expand_params_rec): New parametr, macro_style_p, indicating destructuring macro parameter list is to be expanded. Restructure the cases in expand_opt_params_rec to fix a bug: only recursively treating a nested parameter A only when A stands alone, or without a default form as (A), failing to do so when it is (A B ...). Diagnose :env, :whole or :form inside a function parameter list. Do not process recursive parameter lists for functions; diagnose nesting as bad syntax. (expand_params): Add macro_style_p parameter. (expand_macrolet, expand_tree_cases): Pass t as argument to new parameter of expand_params. (do_expand): Pass t or nil as argument to new parameter of expand params, based on whether expanding a macro or function parameter list.
* Bugfix: optarg presence indicators may be specials.Kaz Kylheku2016-12-291-0/+7
| | | | | | | | | | | This fixes the incorrect treatment of the x-p parameter in (lambda (: (x form x-p))) when x-p is a special variable. It is being lexically bound. * eval.c (expand_opt_params_rec): When processing a (var initform) pair, check for (var initform sym). Error out if sym is not bindable. Check if it is special and if so, push it into the list of specials.
* Hoist binding and arg checking to expansion time.Kaz Kylheku2016-12-291-171/+124
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Checking for uses of non-bindable symbols in variable binding and argument lists is moved to expansion time. Also checked at expansion time are macro lambda list conventions. :env and others must have a bindable parameter, and the optional arg colon cannot occur twice. * eval.c (bind_args): Remove run-time checks that are now done at expansion time. (not_bindable_error): New function. (expand_opt_params_rec, expand_params_rec): Take form argument for reporting errors. Implement more detailed checking against non-bindable symbols, and against :env, :form and :whole having missing or unsuitable arguments. (expand_params): Take form argument for error reporting, and pass to expand_params_rec. (bind_macro_params, bindings_helper): Remove run-time checks that are now done at expansion time. (check_lambda_list): Function removed, because expand_params now does the bulk of this check. We have a regression here in that we lose the check against :env and others occurring in a function parameter list; this has to be worked into expand_params. (op_defvarl, op_defsymacro, op_defmacro, op_setq, op_lisp1_setq, op_setqf): Replace repeated code with call to not_bindable_error. However, these should be replaced by expansion-time checks anyway, and eventually will be. (expand_macrolet): Pass form to expand_params. (expand_tree_cases): Take form argument for error reporting. Pass to expand_params. (expand_tree_case): Pass form to expand_tree_cases. (me_def_variable, me_mlet): Replace repeated code with call to not_bindable_error. (expand_vars): Do bindable symbol check here, so it doesn't have to be done at the run time in bindings_helper. (me_flet_labels): Don't call check_lambda_list. Expansion of the generated lambdas will do argument list checking. (expand_catch_clause): Pass form to expand_params. (do_expand): Don't call check_lambda_list. Pass form to expand_params.
* Add qquot optimization for ranges.Kaz Kylheku2016-12-251-0/+10
| | | | | | * eval.c (optimize_qquote_form): Check for a rcons forms. If thearguments are nothing but quoted forms, convert to literal range.
* Bugfix: incorrect quasi-quoting over #R syntax.Kaz Kylheku2016-12-251-1/+5
| | | | | | | | | | | | | | | | | | | The issue is that ^#R(,(+ 2 2) ,(+ 3 3)) produces 4..6 rather than #R(4..6). 4..6 is, of course, the syntax (rcons 4 6) which evaluates to a range. Here we want the range to which it evaluates, not the syntax. * eval.c (expand_qquote_rec): Handle the case when the qquoted_form is a range atom: expand the from and to parts, and generate a rcons expression. Though this seems to be opposite to the previous paragraph, it's the right thing. * parser.y (range): Drop the unquotes_occurs case which produces rcons syntax. Produce a range object, always. This is the source of the problem: a (rcons ...) expression was produced here which was just traversed by the qquote expander as list. It's the expander that must produce the rcons expression.
* bugfix: dynamic env handling in parallel bindingKaz Kylheku2016-12-231-18/+57
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | In the parallel binding (let ((x s) (s 0) (y s)) ...), both x and y must bind to the prior value of s, not to the new value 0. We have the bug that if s is a special variable, the initialization of y sees the new dynamic environment which contains the new value, so x gets the previous, y gets new. This commit fixes it. * eval.c (reparent_env): New static function. (bindings_helper): Separate logic into two loops, for sequential and parallel binding, so we don't have to repeatedly test this condition in the loop body, and can think separately about each case and streamline it. Nothing new happens under sequential binding; the behavior that is wrong for parallel binding is right for sequential. Under parallel binding, what we do is reset the dynamic environment to the original one prior to each evaluation of an initform. Then if the evaluation changes to a new dynamic environment (a special variable is being bound), we notice this and hook the new environment into a local stack, changing it parent pointer. At the end, we install this stack as the new dynamic env. Thus each init form is evaluated in the original dynamic env. * tests/011/special-1.tl: New tests added.
* Last var may be omitted in iflet/whenlet/condlet.Kaz Kylheku2016-12-221-2/+16
| | | | | | | | * eval.c (me_iflet_whenlet): Allow the last binding to be (init-form) instead of (sym init-form), for situations in which sym is never used. * txr.1: Documented.
* comment change in expander.Kaz Kylheku2016-12-201-4/+3
| | | | | * eval.c (do_expand): Fix outdated comment about what forms are expanded like function calls.
* Different approach for specials in let/let*.Kaz Kylheku2016-12-201-36/+49
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This addresses a problem with the new scheme for handling specials. If we let specials be bound in the lexical environment and then do the swizzle into the dynamic environment using sys:with-dyn-rebinds, that only works correctly for parallel bindings (and thus also for lambda and macro parameters). For sequential bindings, it exposes the possibility that a closure is created during the sequential binding which captures a would-be special variable while it is still in the lexical stage. That closure can be thrown out of there, so the sys:with-dyn-rebinds is never reached which swizzles the variable. The new scheme is very simple. When expanding a let, we tranform (s init) to (s (sys:dvbind s init)) if s is a special variable. This new sys:dvbind operator binds s to the value of the init expression in a newly created dynamic environment, and returns the #:unbound symbol, which is received by the lexical s. Problem solved. The only thing remains is that the let special operator must save and restore the dynamic environment. There is no need for sys:with-dyn-rebinds around the body of a let, but we keep that mechanism and approach for handling specials in argument lists. * eval.c (dvbind_s): New symbol variale. (bindings_helper): Lose the env_out argument; return the new environment. No caller uses the returned bindings any more. (op_let): Call bindings_helper in initializing expression of new_env. Save the dyn_env, and restore it after evaluating the body. (op_dvbind): New static function. (expand_vars): Lose the pspecials argument. Perform the insertion of sys:dvbind. (do_expand): Simplify the let expander: expand_vars no longer outputs a list of specials and there is no need to insert with_dyn_rebinds_s. Add a case for sys:dvbind: assume it requires no expansion. (eval_init): Intern sys:dvbind, and bind it as an operator to the new op_dvbind function.
* Bugfix: sys:unbound mechanism lacks hygiene.Kaz Kylheku2016-12-201-2/+2
| | | | | | | | | | | The genvim.txr program iterates over package symbols and encounters sys:unbound. It binds that to a local variable, creating a problem due to the special hack. Let's turn sys:unbound into a gensym. * eval.c (eval_init): Protect unbound_s from gc. Initialize unbound_s with an uninterned symbol created by make_sym.
* Remove more vestiges of old specials handling.Kaz Kylheku2016-12-201-6/+0
| | | | | | | | * eval.c (struct bindings_helper_vars): Remove de member. (copy_bh_env_handler): Remove copying of dynamic environment. (bindings_helper): Remove all code dealing with de. The sequential binding will no longer introduce a dynamic environment.
* Remove vestiges of old special binding scheme.Kaz Kylheku2016-12-191-66/+17
| | | | | | | | | | | | | | | | | | | | | Removing code which handles the special function argument (sys:special ...) which can occur ahead of the other arguments, indicating the names of arguments which require special binding. Removing code which handles (sys:special init-form var) bindings in let/let*. * eval.c (env_vbind_special): Function removed. (bind_args): Do not look for special list; no such thing occurs. Use env_vbind directly rather than env_vbind special. (bind_macro_params): Likewise. (funcall_interp): Streamlined by not having to check for presence of specials list and setting up the dynamic environment frame for it. (bindings_helper): Don't look for the (sys:special initform sym) syntax among the bindings.
* Changing how binding of special variables works.Kaz Kylheku2016-12-181-60/+72
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The old way: process, at expansion time, bindings in lambda lists and all binding constructs to find special variables (symbols marked special). Replace these bindings with an annotation. Then when the interpreter performs binding, the binding helper functions process these annotations. Also, if specials occur, wrap the construct in sys:with-save-specials to set up the necessary dynamic environment frame. The new way: process, at expansion time, bindings in lambda lists and binding constructs (which have been reduced to just let and let*). If special variables occur, then wrap the body in in sys:with-dyn-rebinds which re-binds specific symbols in the dynamic namespace, copying their value from their lexical binding. The lexical bindings are then replaced with the value sys:unbound, which indicates that the value should be resolved in the dynamic environment. * eval.c (with_saved_vars_s): Symbol variable removed. (with_dyn_rebinds_s): New symbol variable. (lookup_var, lookup_sym_lisp1): If a lexical binding contains the value sys:unbound, then continue the search through the dynamic environment; ignore the remaining lexical environments. (expand_params_rec): Bugfix: neglected collect of special variable in fallback case. (expand_params): Takes body environment, and returns two values as a cons cell. The additional return value is a body that is either the original body, or else is wrapped with sys:with-dyn-rebinds. Removed is the special variable hack inserted into the syntax. (expand_macrolet, expand_tree_cases): Adjust to new expand_params interface. (op_with_saved_vars): Static function removed. (op_with_dyn_rebinds): New static function. (expand_vars): Return list of special variables via pointer argument, rather than just a Boolean which indicates that specials are present. Transformation to special representation is removed. (expand_catch_clause): Adjust to new expand_params interface. (expand_save_specials): Static function removed. (do_expand): Adjust let/let* expansion to new expand_vars interface. Generate the sys:with-dyn-rebinds wrapping around the body. Adjust the defun, lambda and mac-param-bind expanders to the new expand_params interface. Recognize sys:with-dyn-rebinds and don't expand it; all places which generate this form have to expand the internals themselves. (eval_init): Remove initialization of with_saved_var_s, and its registration as an operator. Initialize with_dyn_rebinds_s with interned symbol, and register as operator.
* Refactoring internals of for/each operators.Kaz Kylheku2016-12-181-60/+124
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | NOTE: The socket test cases do not pass under this commit: this is expected. The for and each family of operators will now be macros which expand to let/let* binding construct wrapping a lower level special operator. This is in preparation for a change to how special variable binding is implemented. This change reduces the number of special forms which bind variables. There is a single low-level operator for for loops called sys:for-op. Its syntax is a lot like the C89 for loop: (sys:for-op init-forms test step-forms body). The init-forms do not bind anything; it is just forms. There is a sys:each operator for implementing each, each*, append-each and all those operators. Its syntax is (sys:each-op type-sym optional-vars . body). The type-sym is one of each, append-each or collect-each. If optional-vars is nil, then the operator looks at the immediate lexical environment, and assumes all the bindings there are the each iteration variables and it works with those bindings, like its predecessor did. Otherwise optional-vars is a list of symbols: the operator walks the list and resolves each element to a binding. This is used in two situations: when some of the variables are special (dynamically scoped) or when the variables are bound sequentially with let* and are thus scattered in multiple levels of environment. * eval.c (for_op_s, each_op_s): New symbol variables. (get_bindings): New static function. (op_each): Now implements sys:each-op. (op_for): Now implements sys:for-op. (get_var_syms): New static function. (me_each, me_for): New static functions. (do_expand): Do not expand the each operator family under the same rule. New case handling sys:each-op is introduced due to the different syntax. The for case restructured to handle for_op_s. (eval_init): Intern sys:each-op and sys:for-op symbols. Register the corresponding operators. Move registrations of the public symbols each, each*, for, for* and all the other each variants to be macros. * tests/011/macros-2.expected: Updated with different macro expansion which is now produced for a while loop.