diff options
-rw-r--r-- | autoload.c | 17 | ||||
-rw-r--r-- | stdlib/doc-syms.tl | 1 | ||||
-rw-r--r-- | stdlib/expander-let.tl | 44 | ||||
-rw-r--r-- | txr.1 | 54 |
4 files changed, 116 insertions, 0 deletions
@@ -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)))) @@ -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 *) |