summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2015-11-30 07:43:00 -0800
committerKaz Kylheku <kaz@kylheku.com>2015-11-30 07:43:00 -0800
commite8f6f8d3aa516b4154dd9832bf50de82ddb07840 (patch)
tree774fac61fad3f04968fb7f404a32ba27150e803f
parenta35352076ebdadf1a522e0e80ffaef83c91ef1e1 (diff)
downloadtxr-e8f6f8d3aa516b4154dd9832bf50de82ddb07840.tar.gz
txr-e8f6f8d3aa516b4154dd9832bf50de82ddb07840.tar.bz2
txr-e8f6f8d3aa516b4154dd9832bf50de82ddb07840.zip
defun can define methods.
* eval.c (op_defun): Handle (meth type name) syntax in place of name via sys:defmeth function, which is dynamically resolved and autoloaded as necessary. (builtin_reject_test): When defun is being checked, recognize a (method ...) form and allow it. * struct.h (meth_s): Declaration added. * txr.1: Documented new defun capability.
-rw-r--r--eval.c33
-rw-r--r--struct.h2
-rw-r--r--txr.124
3 files changed, 49 insertions, 10 deletions
diff --git a/eval.c b/eval.c
index 99f0ac0f..9ff820ca 100644
--- a/eval.c
+++ b/eval.c
@@ -1522,16 +1522,29 @@ static val op_defun(val form, val env)
val name = first(args);
val params = second(args);
val body = rest(rest(args));
- val block = cons(block_s, cons(name, body));
- val fun = cons(name, cons(params, cons(block, nil)));
- remhash(top_mb, name);
+ if (!consp(name)) {
+ val block = cons(block_s, cons(name, body));
+ val fun = cons(name, cons(params, cons(block, nil)));
- /* defun captures lexical environment, so env is passed */
- sethash(top_fb, name, cons(name, func_interp(env, fun)));
- if (eval_initing)
- sethash(builtin, name, defun_s);
- return name;
+ remhash(top_mb, name);
+
+ /* defun captures lexical environment, so env is passed */
+ sethash(top_fb, name, cons(name, func_interp(env, fun)));
+ if (eval_initing)
+ sethash(builtin, name, defun_s);
+ return name;
+ } else {
+ val binding = lookup_fun(nil, intern(lit("defmeth"), system_package));
+ val type_sym = second(name);
+ val meth_name = third(name);
+ val block = cons(block_s, cons(meth_name, body));
+ val fun = cons(meth_name, cons(params, cons(block, nil)));
+
+ bug_unless (binding);
+
+ return funcall3(cdr(binding), type_sym, meth_name, func_interp(env, fun));
+ }
}
static val op_defmacro(val form, val env)
@@ -1617,7 +1630,9 @@ static void builtin_reject_test(val op, val sym, val form)
val builtin_kind = gethash(builtin, sym);
val is_operator = gethash(op_table, sym);
- if (!bindable(sym)) {
+ if (op == defun_s && consp(sym) && car(sym) == meth_s) {
+ return;
+ } else if (!bindable(sym)) {
eval_error(form, lit("~s: cannot bind ~s, which is not a bindable symbol"),
is_operator, sym, nao);
} else if (opt_compat && opt_compat <= 107) {
diff --git a/struct.h b/struct.h
index f0dacaf7..c5c9d193 100644
--- a/struct.h
+++ b/struct.h
@@ -24,7 +24,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-extern val struct_type_s;
+extern val struct_type_s, meth_s;
val make_struct_type(val name, val super,
val static_slots, val slots,
val static_initfun, val initfun, val boactor);
diff --git a/txr.1 b/txr.1
index 163c7745..9ff4b35f 100644
--- a/txr.1
+++ b/txr.1
@@ -10932,6 +10932,30 @@ and
.code nil
may not be used as function names. Neither can keyword symbols.
+It is possible to define methods with
+.codn defun ,
+as an alternative to the
+.code defmeth
+macro.
+
+To define a method, the syntax
+.cblk
+.meti (meth < type << name )
+.cble
+should be used as the argument to the
+.meta name
+parameter.
+
+The syntax
+.cblk
+.meti (defun (meth type name) args forms)
+.cble
+is equivalent to the
+.cblk
+.meti (defmeth type name args forms)
+.cble
+syntax.
+
.TP* "Dialect Note:"
In ANSI Common Lisp, keywords may be used as function names.
In TXR Lisp, they may not.