aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/builtins.c2
-rw-r--r--src/interp.h1
-rw-r--r--src/primitives.c33
-rw-r--r--tests/lambda.lisp22
4 files changed, 42 insertions, 16 deletions
diff --git a/src/builtins.c b/src/builtins.c
index f1c7d10..efad674 100644
--- a/src/builtins.c
+++ b/src/builtins.c
@@ -75,7 +75,7 @@ SExpRef builtin_foldl(Interp *interp, SExpRef args) {
}
SExpRef fn = CAR(args), init = CADR(args), lst = CADDR(args);
SExpRef ret = init;
- if (VALTYPE(fn) != kUserFuncSExp && VALTYPE(fn) != kFuncSExp) {
+ if (!CALLABLE(fn)) {
return new_error(interp, "foldl: type error.\n");
}
if (!lisp_check_list(interp, lst)) {
diff --git a/src/interp.h b/src/interp.h
index 1d3a2b4..4e43cd8 100644
--- a/src/interp.h
+++ b/src/interp.h
@@ -60,6 +60,7 @@ SExpRef Interp_load_file(Interp *interp, const char *filename);
|| REF((_x))->type == kBreakSignal \
|| REF((_x))->type == kContinueSignal)
#define VALTYPE(_x) (REF((_x))->type)
+#define CALLABLE(_x) (VALTYPE(_x) == kFuncSExp || VALTYPE(_x) == kUserFuncSExp)
#define NIL (interp->nil)
#define CAR(_x) (lisp_car(interp, (_x)))
#define CDR(_x) (lisp_cdr(interp, (_x)))
diff --git a/src/primitives.c b/src/primitives.c
index 0eadbb7..73812b8 100644
--- a/src/primitives.c
+++ b/src/primitives.c
@@ -321,17 +321,28 @@ error:
SExpRef primitive_defun(Interp *interp, SExpRef args, bool istail) {
SExpRef name, param, body, function;
- if (LENGTH(args) < 3) goto error;
- if (CAR(interp->stack).idx != interp->top_level.idx) {
- return new_error(interp, "defun: functions can only be defined in top level.\n");
- }
- name = CAR(args);
- if (VALTYPE(name) != kSymbolSExp) goto error;
- param = CADR(args);
- body = CDDR(args);
- function = new_lambda(interp, param, body, interp->top_level);
- lisp_defun(interp, name, function);
- return name;
+ if (LENGTH(args) == 2) {
+ if (CAR(interp->stack).idx != interp->top_level.idx) {
+ return new_error(interp, "defun: functions can only be defined in top level.\n");
+ }
+ name = CAR(args);
+ if (VALTYPE(name) != kSymbolSExp) goto error;
+ function = EVAL(CADR(args));
+ if (!CALLABLE(function)) goto error;
+ lisp_defun(interp, name, function);
+ return name;
+ } else if (LENGTH(args) >= 3) {
+ if (CAR(interp->stack).idx != interp->top_level.idx) {
+ return new_error(interp, "defun: functions can only be defined in top level.\n");
+ }
+ name = CAR(args);
+ if (VALTYPE(name) != kSymbolSExp) goto error;
+ param = CADR(args);
+ body = CDDR(args);
+ function = new_lambda(interp, param, body, interp->top_level);
+ lisp_defun(interp, name, function);
+ return name;
+ } else goto error;
error:
return new_error(interp, "defun: syntax error.\n");
}
diff --git a/tests/lambda.lisp b/tests/lambda.lisp
index 759a217..c7337ba 100644
--- a/tests/lambda.lisp
+++ b/tests/lambda.lisp
@@ -3,15 +3,12 @@
(lambda (g) (funcall g g))
(lambda (h)
(funcall f (lambda args (apply (funcall h h) args))))))
-
(defun fibo-impl (self)
(lambda (n)
(if (<= n 2)
1
(+ (funcall self (- n 1)) (funcall self (- n 2))))))
-
(defvar fibo (Y #'fibo-impl))
-
(assert (= 55 (funcall fibo 10)))
(defun generate-counter (init)
@@ -19,7 +16,6 @@
(lambda ()
(setq i (+ 1 i))
i)))
-
(let ((c (generate-counter 0)))
(assert (= 1 (funcall c)))
(assert (= 2 (funcall c)))
@@ -37,3 +33,21 @@
((f
(lambda (x) (funcall f 1) x)))
(funcall f 1)))
+
+(defun my-add (lambda (x y) (+ x y)))
+(assert (= 3 (my-add 1 2)))
+
+(defun my-add #'+)
+(assert (= 3 (my-add 1 2)))
+
+(defvar flag 0)
+(defun func ()
+ (incq flag)
+ (incq flag))
+(defun func
+ (let ((old-func #'func))
+ (lambda ()
+ (funcall old-func)
+ (incq flag))))
+(func)
+(assert (= 3 flag))