Hi! jcroisant reminded us of a pending patch on the bugtracker (#1770), which apparently was forgotten. I'm not quite sure how this could linger along for such a long time, but once-only-expansion was always a somewhat brittle transformation as the interpreter and compiler handle special forms a bit differently and there often appear undocumented intermediate special forms. Nevertheless, this functionality is useful for debugging and has been requested often enough in the past.
Find attached a slightly modified, signed off version. The use of "expand1" in csi.scm needs to have a hard coded module prefix, which I assume is caused by "expand[1]" being treated specifically by the bootstrapping compiler, so the new addition to the import lib appears not to be visible. There are some unrelated whitespace changes in csi.scm, due to reasons, please ignore them. cheers, felix
From 568b0728aa405177ecea1e0ef293f2e37984c735 Mon Sep 17 00:00:00 2001 From: felix <[email protected]> Date: Fri, 1 Aug 2025 16:14:04 +0200 Subject: [PATCH] Add `expand1` procedure in module (chicken syntax). (original patch by John Croisant, slightly modified to avoid bootstrapping issue) Like `expand` but expands the form only once, instead of repeating until a non-macro form is produced. This is helpful when debugging macros because you can see the intermediate results of the expansion. Also add `,x`, which is like `,x` but uses `expand1` instead of `expand`. The form is expanded only once, then pretty-printed. Signed-off-by: felix <[email protected]> --- chicken.syntax.import.scm | 1 + csi.scm | 28 ++++++++++++++++++++-------- expand.scm | 4 ++++ manual/Module (chicken syntax) | 8 ++++++++ manual/Using the interpreter | 2 ++ 5 files changed, 35 insertions(+), 8 deletions(-) diff --git a/chicken.syntax.import.scm b/chicken.syntax.import.scm index d11a3ffa..81b61eaf 100644 --- a/chicken.syntax.import.scm +++ b/chicken.syntax.import.scm @@ -31,6 +31,7 @@ 'chicken.syntax 'expand '((expand . chicken.syntax#expand) + (expand1 . chicken.syntax#expand1) (get-line-number . chicken.syntax#get-line-number) (read-with-source-info . chicken.syntax#read-with-source-info) (strip-syntax . chicken.syntax#strip-syntax) diff --git a/csi.scm b/csi.scm index 2a4c8477..e3c95d2e 100644 --- a/csi.scm +++ b/csi.scm @@ -424,16 +424,28 @@ EOF (lambda () (let ((name (read))) (cond ((not name) - (##sys#switch-module #f) - (printf "; resetting current module to toplevel~%")) - ((##sys#find-module (##sys#resolve-module-name name #f) #f) => - (lambda (m) - (##sys#switch-module m) - (printf "; switching current module to `~a'~%" name))) - (else - (printf "undefined module `~a'~%" name)))))) + (##sys#switch-module #f) + (printf "; resetting current module to toplevel~%")) + ((##sys#find-module (##sys#resolve-module-name name #f) #f) => + (lambda (m) + (##sys#switch-module m) + (printf "; switching current module to `~a'~%" name))) + (else + (printf "undefined module `~a'~%" name)))))) ",m MODULE switch to module with name `MODULE'") +(toplevel-command + 'x1 + (let ((pretty-print pretty-print)) + (lambda () + (let ([expr (read)]) + ;; avoid bootstrapping issue, as chicken.syntax is not + ;; imported dynamically by bootstrap compiler + ;; this can be replaced by "expand1" later + (pretty-print (strip-syntax (chicken.syntax#expand1 expr))) + (##sys#void)))) + ",x1 EXP Pretty print expand1-ed expression EXP") + ;;; Parse options from string: diff --git a/expand.scm b/expand.scm index a329c4ba..858c9f68 100644 --- a/expand.scm +++ b/expand.scm @@ -36,6 +36,7 @@ (module chicken.syntax (expand + expand1 get-line-number read-with-source-info strip-syntax @@ -305,6 +306,9 @@ (loop exp2) exp2) ) ) ) +(define (expand1 exp #!optional (se (##sys#current-environment)) cs?) + (nth-value 0 (##sys#expand-0 exp se cs?)) ) + ;;; Extended (DSSSL-style) lambda lists ; diff --git a/manual/Module (chicken syntax) b/manual/Module (chicken syntax) index 1f1e44a4..19e550be 100644 --- a/manual/Module (chicken syntax) +++ b/manual/Module (chicken syntax) @@ -301,6 +301,14 @@ comparison {{(compare sym 'abc)}} should be written as {{(compare sym If {{X}} is a macro-form, expand the macro (and repeat expansion until expression is a non-macro form). Returns the resulting expression. +==== expand1 + +<procedure>(expand1 X)</procedure> + +If {{X}} is a macro-form, expand the macro only once. Unlike +{{expand}}, does not repeat expansion when the resulting expression is +itself a macro-form. Returns the resulting expression. + === Macro helper procedures ==== begin-for-syntax diff --git a/manual/Using the interpreter b/manual/Using the interpreter index de1f3097..14cda247 100644 --- a/manual/Using the interpreter +++ b/manual/Using the interpreter @@ -117,6 +117,8 @@ The toplevel loop understands a number of special commands: ; ,x EXP : Pretty-print macroexpanded expression {{EXP}} (the expression is not evaluated). +; ,x1 EXP : Like {{,x}} but {{EXP}} is expanded only one step, using {{expand1}}. + You can define your own toplevel commands using the {{toplevel-command}} procedure (see [[Module (chicken csi)]]). -- 2.44.1
