summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--eval.c26
-rw-r--r--eval.h1
-rw-r--r--parser.c18
-rw-r--r--txr.169
4 files changed, 112 insertions, 2 deletions
diff --git a/eval.c b/eval.c
index 324722d2..ac023eef 100644
--- a/eval.c
+++ b/eval.c
@@ -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))
{
diff --git a/eval.h b/eval.h
index 966361de..8cd5516e 100644
--- a/eval.h
+++ b/eval.h
@@ -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);
diff --git a/parser.c b/parser.c
index 6b3d00e5..849de26d 100644
--- a/parser.c
+++ b/parser.c
@@ -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));
}
diff --git a/txr.1 b/txr.1
index e560a764..3643989f 100644
--- a/txr.1
+++ b/txr.1
@@ -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