summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2018-04-15 13:58:46 -0700
committerKaz Kylheku <kaz@kylheku.com>2018-04-15 13:58:46 -0700
commitfc7a6a883b663ea58edf8b190d210f11e91d4552 (patch)
treed67b4ff82a0961e0397f39051b19b8717af0d734
parent1b86c3b4edd40f7b97c9e2f2af2554fcc098d30d (diff)
downloadtxr-fc7a6a883b663ea58edf8b190d210f11e91d4552.tar.gz
txr-fc7a6a883b663ea58edf8b190d210f11e91d4552.tar.bz2
txr-fc7a6a883b663ea58edf8b190d210f11e91d4552.zip
compiler: lambda call to let optimization.
Normalize ((lambda ...) args) to (call (lambda ...) args). Reduce (apply (lambda ...) args) and (call (lambda ...) args) to let (let (vars-inited-from-args ...) ...). * lisplib.c (error_set_entries): Autoload for new error functions lambda-too-many-args, lambda-too-few-args, lambda-short-apply-list. * share/txr/stdlib/compiler.tl (comp-fun-form): Restructure to recognize lambda and handle via comp-inline-lambda. (compiler comp-inline-lambda): New method. (lambda-apply-transform): New function. * share/txr/stdlib/error.tl (lambda-too-many-args, lambda-too-few-args, lambda-short-apply-list): New functions.
-rw-r--r--lisplib.c3
-rw-r--r--share/txr/stdlib/compiler.tl76
-rw-r--r--share/txr/stdlib/error.tl9
3 files changed, 81 insertions, 7 deletions
diff --git a/lisplib.c b/lisplib.c
index ce59dd1d..a486abe1 100644
--- a/lisplib.c
+++ b/lisplib.c
@@ -544,7 +544,8 @@ static val pmac_instantiate(val set_fun)
static val error_set_entries(val dlt, val fun)
{
val sys_name[] = {
- lit("bind-mac-error"),
+ lit("bind-mac-error"), lit("lambda-too-many-args"),
+ lit("lambda-too-few-args"), lit("lambda-short-apply-list"),
nil
};
val name[] = {
diff --git a/share/txr/stdlib/compiler.tl b/share/txr/stdlib/compiler.tl
index d4609e01..4d37b9b5 100644
--- a/share/txr/stdlib/compiler.tl
+++ b/share/txr/stdlib/compiler.tl
@@ -882,12 +882,21 @@
(let ((gopcode [%gcall-op% sym])
(opcode [%call-op% sym]))
(tree-case (car args)
- ((op arg) (if (and (eq op 'fun) (bindable arg))
- (let ((fbind env.(lookup-fun arg)))
- me.(comp-call-impl oreg env (if fbind opcode gopcode)
- (if fbind fbind.loc me.(get-fidx arg))
- (cdr args)))
- :))
+ ((op arg . more)
+ (caseq op
+ (fun (cond
+ (more (compile-error form "excess args in fun form"))
+ ((bindable arg)
+ (let ((fbind env.(lookup-fun arg)))
+ me.(comp-call-impl oreg env (if fbind opcode gopcode)
+ (if fbind fbind.loc me.(get-fidx arg))
+ (cdr args))))
+ ((and (consp arg) (eq (car arg) 'lambda))
+ me.(comp-fun-form oreg env ^(sym ,arg ,*(cdr args))))
+ (t :)))
+ (lambda me.(comp-inline-lambda oreg env opcode
+ (car args) (cdr args)))
+ (t :)))
(arg me.(comp-call oreg env
(if (eq sym 'usr:apply) 'apply sym) args)))))
(ift me.(comp-ift oreg env form))
@@ -924,6 +933,17 @@
[reduce-left uni afrags nil .fvars]
[reduce-left uni afrags nil .ffuns]))))
+(defmeth compiler comp-inline-lambda (me oreg env opcode lambda args)
+ (let ((reg-args args) apply-list-arg)
+ (when (eql opcode 'apply)
+ (unless args
+ (compile-error lambda "apply requires arguments"))
+ (set reg-args (butlast args)
+ apply-list-arg (car (last args))))
+ me.(compile oreg env (expand (lambda-apply-transform lambda
+ reg-args
+ apply-list-arg)))))
+
(defmeth compiler comp-for (me oreg env form)
(mac-param-bind form (op inits (: test . rets) incs . body) form
(let* ((treg me.(alloc-treg))
@@ -1308,6 +1328,50 @@
(mac-param-bind form (op name def) form
^(sys:rt-defsymacro ',name ',def)))
+(defun lambda-apply-transform (lm-expr fix-arg-exprs apply-list-expr)
+ (mac-param-bind lm-expr (lambda lm-args . lm-body) lm-expr
+ (let* ((pars (new (fun-param-parser lm-args lm-expr)))
+ (ign-sym (gensym))
+ (al-val (gensym)))
+ ^(let* ,(build
+ (while (and fix-arg-exprs pars.req)
+ (add ^(,(pop pars.req) ,(pop fix-arg-exprs))))
+ (while (and fix-arg-exprs pars.opt)
+ (add ^(,(car (pop pars.opt)) ,(pop fix-arg-exprs))))
+ (cond
+ ((and (null fix-arg-exprs)
+ (null pars.req)
+ (null pars.opt))
+ (when (or pars.rest apply-list-expr)
+ (add ^(,(or pars.rest ign-sym) ,apply-list-expr))))
+ (fix-arg-exprs
+ (lambda-too-many-args lm-expr))
+ (apply-list-expr
+ (add ^(,al-val ,apply-list-expr))
+ (when pars.req
+ (add ^(,ign-sym (if (< (len ,al-val) ,(len pars.req))
+ (lambda-short-apply-list)))))
+ (while pars.req
+ (add ^(,(pop pars.req) (pop ,al-val))))
+ (while pars.opt
+ (add ^(,(caar pars.opt)
+ (if ,al-val
+ (pop ,al-val)
+ ,(cadar pars.opt))))
+ (pop pars.opt))
+ (when pars.rest
+ (add ^(,pars.rest ,al-val))))
+ (pars.req
+ (lambda-too-few-args lm-expr))
+ (pars.opt
+ (while pars.opt
+ (add ^(,(caar pars.opt)
+ ,(cadar pars.opt)))
+ (pop pars.opt))
+ (when pars.rest
+ (add ^(,pars.rest))))))
+ ,*lm-body))))
+
(defun usr:compile-toplevel (exp)
(let ((co (new compiler))
(as (new assembler)))
diff --git a/share/txr/stdlib/error.tl b/share/txr/stdlib/error.tl
index b58c93f9..b632fd64 100644
--- a/share/txr/stdlib/error.tl
+++ b/share/txr/stdlib/error.tl
@@ -54,3 +54,12 @@
obj params)
(compile-error ctx-form "object ~s too ~a for params ~s"
obj (if too-few-p "short" "long") params)))
+
+(defun lambda-too-many-args (form)
+ (compile-error form "excess arguments given"))
+
+(defun lambda-too-few-args (form)
+ (compile-error form "inufficient arguments given"))
+
+(defun lambda-short-apply-list ()
+ (throwf 'eval-error "~s: applied argument list too short" 'lambda))