diff options
-rw-r--r-- | eval.c | 26 | ||||
-rw-r--r-- | eval.h | 1 | ||||
-rw-r--r-- | parser.c | 18 | ||||
-rw-r--r-- | txr.1 | 69 |
4 files changed, 112 insertions, 2 deletions
@@ -1370,6 +1370,32 @@ val eval_intrinsic(val form, val env) return ret; } +val eval_intrinsic_noerr(val form, val env, val *error_p) +{ + val result = nil; + uw_frame_t uw_handler; + uw_push_handler(&uw_handler, cons(defr_warning_s, nil), + func_n1v(uw_muffle_warning)); + + uw_catch_begin (cons(t, nil), exsym, exvals); + + result = eval_intrinsic(form, env); + + uw_catch(exsym, exvals) { + (void) exsym; (void) exvals; + *error_p = t; + break; + } + + uw_unwind; + + uw_catch_end; + + uw_pop_frame(&uw_handler); + + return result; +} + static val do_eval(val form, val env, val ctx, val (*lookup)(val env, val sym)) { @@ -69,6 +69,7 @@ val apply_intrinsic(val fun, val args); val eval_progn(val forms, val env, val ctx_form); val eval(val form, val env, val ctx_form); val eval_intrinsic(val form, val env); +val eval_intrinsic_noerr(val form, val env, val *error_p); void trace_check(val name); val format_field(val string_or_list, val modifier, val filter, val eval_fun); val subst_vars(val forms, val env, val filter); @@ -62,7 +62,7 @@ val parser_s, unique_s, circref_s; val listener_hist_len_s, listener_multi_line_p_s, listener_sel_inclusive_p_s; -val listener_pprint_s; +val listener_pprint_s, listener_greedy_eval_s; val rec_source_loc_s; val intr_s; @@ -1142,6 +1142,7 @@ val repl(val bindings, val in_stream, val out_stream) val multi_line_var = lookup_global_var(listener_multi_line_p_s); val sel_inclusive_var = lookup_global_var(listener_sel_inclusive_p_s); val pprint_var = lookup_global_var(listener_pprint_s); + val greedy_eval = lookup_global_var(listener_greedy_eval_s); val rw_f = func_f1v(out_stream, repl_warning); val saved_dyn_env = set_dyn_env(make_env(nil, nil, dyn_env)); @@ -1243,11 +1244,22 @@ val repl(val bindings, val in_stream, val out_stream) read_eval_ret_last(nil, prev_counter, in_stream, out_stream)); val pprin = cdr(pprint_var); + val (*pfun)(val, val) = if3(pprin, pprinl, prinl); reg_varl(var_sym, value); sethash(result_hash, var_counter, value); - if3(pprin, pprinl, prinl)(value, out_stream); + pfun(value, out_stream); lino_set_result(ls, utf8_dup_to(c_str(tostring(value)))); lino_hist_add(ls, line_u8); + if (cdr(greedy_eval)) { + val error_p = nil; + while (bindable(value) || consp(value)) + { + value = eval_intrinsic_noerr(value, nil, &error_p); + if (error_p) + break; + pfun(value, out_stream); + } + } } } @@ -1328,6 +1340,7 @@ void parse_init(void) listener_multi_line_p_s = intern(lit("*listener-multi-line-p*"), user_package); listener_sel_inclusive_p_s = intern(lit("*listener-sel-inclusive-p*"), user_package); listener_pprint_s = intern(lit("*listener-pprint-p*"), user_package); + listener_greedy_eval_s = intern(lit("*listener-greedy-eval-p*"), user_package); rec_source_loc_s = intern(lit("*rec-source-loc*"), user_package); unique_s = gensym(nil); prot1(&stream_parser_hash); @@ -1338,6 +1351,7 @@ void parse_init(void) reg_var(listener_multi_line_p_s, t); reg_var(listener_sel_inclusive_p_s, nil); reg_var(listener_pprint_s, nil); + reg_var(listener_greedy_eval_s, nil); reg_var(rec_source_loc_s, nil); reg_fun(circref_s, func_n1(circref)); } @@ -62576,6 +62576,75 @@ using the .code pprinl function. +.coNP Special variable @ *listener-greedy-eval-p* +.desc +The special variable +.code *listener-greedy-eval-p* +controls whether or not a "greedy evaluation" feature is enabled +in the listener. The default value is +.codn nil , +disabling the feature. + +Greedy evaluation means that after the listener evaluates an expression +successfully and prints its value, it then checks whether that value is +an expression that may be further subject to non-trivial evaluation. +If so, it evaluates that expression, and prints the resulting value. +The process is then repeated with the resulting value. It keeps repeating until +evaluation throws an error, or produces a self-evaluating object. + +These additional evaluations are performed in such a way that all warnings are +suppressed and all other exceptions are intercepted. + +Greedy evaluation doesn't affect the state of the listener. +Only the original expression is entered into the +history. Only the value of the original expression is saved in the result hash +or a numbered variable. The command line number +.code *n +is incremented by one. The additional evaluations are only performed for +the purpose of producing useful output. Of course, the evaluations may +have side effects. + +.TP* Example: + +.cblk + 1> (set *listener-greedy-eval-p* t) + t + 2> 'a + a + 3> (defvar b 2) + b + 2 + 4> (defvar c '(+ 2 2)) + c + (+ 2 2) + 4 + 5> (defvar d '(list '+ 2 2)) + d + (list '+ 2 2) + (+ 2 2) + 4 +.cble + +The +.code "(defvar d ...)" +form produces +.code d +symbol as its result value. That symbol has a variable binding as a result +of that +.code defvar +and so evaluates; that evaluation produces +.codn "(list '+ 2 2)" , +the contents of +.codn d . +That object is a Lisp expression and is evaluated, producing +.code "(+ 2 2)" +and that of course is also an expression, which reduces to +.codn 4 . +The object +.code 4 +is self-evaluating, and so the greedy evaluation process stops. + + .SH* SETUID/SETGID OPERATION On platforms with the Unix filesystem and process security model, \*(TX has |