summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--autoload.c17
-rw-r--r--stdlib/doc-syms.tl1
-rw-r--r--stdlib/expander-let.tl44
-rw-r--r--txr.154
4 files changed, 116 insertions, 0 deletions
diff --git a/autoload.c b/autoload.c
index 0f0f3039..040b04f4 100644
--- a/autoload.c
+++ b/autoload.c
@@ -918,6 +918,22 @@ static val constfun_instantiate(void)
return nil;
}
+static val expander_let_set_entries(val fun)
+{
+ val sys_name[] = {
+ lit("expander-let"),
+ nil
+ };
+ autoload_set(al_fun, sys_name, fun);
+ return nil;
+}
+
+static val expander_let_instantiate(void)
+{
+ load(scat2(stdlib_path, lit("expander-let")));
+ return nil;
+}
+
val autoload_reg(val (*instantiate)(void),
val (*set_entries)(val))
{
@@ -985,6 +1001,7 @@ void autoload_init(void)
autoload_reg(doc_instantiate, doc_set_entries);
autoload_reg(pic_instantiate, pic_set_entries);
autoload_reg(constfun_instantiate, constfun_set_entries);
+ autoload_reg(expander_let_instantiate, expander_let_set_entries);
reg_fun(intern(lit("autoload-try-fun"), system_package), func_n1(autoload_try_fun));
}
diff --git a/stdlib/doc-syms.tl b/stdlib/doc-syms.tl
index 6391695f..a3d5434d 100644
--- a/stdlib/doc-syms.tl
+++ b/stdlib/doc-syms.tl
@@ -673,6 +673,7 @@
("expand-left" "N-00E168FE")
("expand-right" "N-023B6B64")
("expand-with-free-refs" "N-0334827B")
+ ("expander-let" "N-00DBD46D")
("expt" "D-0076")
("exptmod" "D-0036")
("extproc" "N-0072FF5E")
diff --git a/stdlib/expander-let.tl b/stdlib/expander-let.tl
new file mode 100644
index 00000000..72338793
--- /dev/null
+++ b/stdlib/expander-let.tl
@@ -0,0 +1,44 @@
+;; Copyright 2023
+;; Kaz Kylheku <kaz@kylheku.com>
+;; Vancouver, Canada
+;; All rights reserved.
+;;
+;; Redistribution and use in source and binary forms, with or without
+;; modification, are permitted provided that the following conditions are met:
+;;
+;; 1. Redistributions of source code must retain the above copyright notice,
+;; this list of conditions and the following disclaimer.
+;;
+;; 2. Redistributions in binary form must reproduce the above copyright notice,
+;; this list of conditions and the following disclaimer in the documentation
+;; and/or other materials provided with the distribution.
+;;
+;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+;; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+;; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+;; ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+;; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+;; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+;; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+;; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+;; POSSIBILITY OF SUCH DAMAGE.
+
+(defmacro usr:expander-let (:form f :env e vars . body)
+ (let (syms values)
+ (each ((pair vars))
+ (tree-case pair
+ ((sym init)
+ (unless (special-var-p sym)
+ (compile-warning f "~s is required to be a special variable" sym))
+ (push sym syms)
+ (push
+ (if-match (sys:dv-bind @sym @form) init
+ (eval form)
+ (eval init))
+ values))
+ (else
+ (compile-warning f "not a var-init form: ~s" else))))
+ (progv (nreverse syms) (nreverse values)
+ (expand ^(progn ,*body) e))))
diff --git a/txr.1 b/txr.1
index 5fb8ef08..af63b07d 100644
--- a/txr.1
+++ b/txr.1
@@ -41290,6 +41290,60 @@ emanating from the
.code delta
form.
+.coNP Macro @ expander-let
+.synb
+.mets (expander-let >> ({( sym << init-form )}*) << body-form *)
+.syne
+.desc
+The
+.code expander-let
+operator strongly resembles
+.code let*
+but has different semantics, relevant to expansion.
+It also has a stricter syntax in that variables may not
+be symbols without a
+.metn init-form :
+only variable binding specifications of the form
+.mono
+.meti >> (sym << init-form )
+.onom
+are allowed.
+
+Symbols bound using
+.code expander-let
+are expected to be special variables. For every
+.metn sym ,
+the expression
+.mono
+.meti (special-var-p << sym )
+.onom
+should be true. The behavior is unspecified for any
+.meta sym
+which doesn't name a special variable.
+
+The
+.code expander-let
+macro establishes a new dynamic environment which each given
+.meta sym
+has the value of the specified
+.meta init-form
+which is evaluated in the top-level environment.
+Then, the
+.metn body-form s
+are turned into the arguments of a
+.code progn
+form, and that form is then expanded in the new environment in which the
+dynamic bindings are visible.
+
+Thus
+.code expander-let
+may be used to bind special variables which are visible to expansion-time
+computations occurring within
+.metn body-form s.
+A macro may generate an
+.code expander-let
+form in order to communicate values to macros contained in that form.
+
.coNP Macro @ macro-time
.synb
.mets (macro-time << form *)