diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2025-05-10 19:48:30 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2025-05-10 19:48:30 -0700 |
commit | 59da72099d08b1b2573cc80bcd1493033b479e0c (patch) | |
tree | ec3d346851e6a0ed5a7bb3f60e2a6db9408c8272 /lib.h | |
parent | f46ff43283a70b77d2c76fd37a415ab506b0f78c (diff) | |
download | txr-59da72099d08b1b2573cc80bcd1493033b479e0c.tar.gz txr-59da72099d08b1b2573cc80bcd1493033b479e0c.tar.bz2 txr-59da72099d08b1b2573cc80bcd1493033b479e0c.zip |
match: make @(require) work over args in lambda-match.
The issue is that in a lambda-match, when we wrap
@(require) around an argument match, it becomes
a single pattern which matches the variadic arguments
as a list. As a result, the function also becomes
variadic, and a list is consed up for the match.
A nested list is worth a thousand words:
Before this change:
1> (expand '(lambda-match
(@(require (@a @b) (= 5 (+ a b))) (cons a b))))
(lambda (. #:rest0014)
(let (#:result0015)
(or (let* (a b) (let ((#:g0017 (list* #:rest0014)))
(if (consp #:g0017)
(let ((#:g0018 (car #:g0017))
(#:g0019 (cdr #:g0017)))
(sys:setq a #:g0018)
(if (consp #:g0019)
(let ((#:g0020 (car #:g0019))
(#:g0021 (cdr #:g0019)))
(sys:setq b #:g0020)
(if (equal #:g0021 '())
(if (and (= 5 (+ a b)))
(progn (sys:setq #:result0015
(cons a b))
t))))))))))
#:result0015))
After this change:
1> (expand '(lambda-match
(@(require (@a @b) (= 5 (+ a b))) (cons a b))))
(lambda (#:arg-00015
#:arg-10016)
(let (#:result0017)
(or (let* (b a) (sys:setq b #:arg-10016)
(sys:setq a #:arg-00015)
(if (and (= 5 (+ a b)))
(progn (sys:setq #:result0017
(cons a b))
t))))
#:result0017))
@(require (@a @b)) now leads to a two-argument function.
The guard condition is applied to the a and b variables
extracted from the arguments rather than a list.
* stdlib/match.tl (when-exprs-match): Macro removed.
(struct lambda-clause): New slot, require-conds.
(parse-lambda-match-clause): Recognize @(require ...)
syntax, destructure it and recurse into the argument
pattern it contains. Because the incoming syntax
includes the clause body, for the recursive call we
synthesize syntax consisting of the pattern
extracted from the @(require), coupled with the
clause body. When the recursive call gives us a
lambda-clause structure, we then add the require
guard expressions to it. So in essence the behavior
is that we parse the (@(require argpat cond ...) body)
as if it were (argpat body), and decorate the object
with the extracted conditions.
(expand-lambda-match): This now takes an env argument
due to the fact that when-exprs-match was removed.
when-exprs-match relied on its :env parameter to get
the environment, needed for compile-match. Now
expand-lambda-match directly calls compile-match,
doing all the work that when-exprs-match helper was
doing. Integrating that into expand-lambda-match
allows us to add logic to detect that the lambda-clause
structure has require conditions, and add the code
as a guard to the compiled match using add-guards-post.
(lambda-match, defun-match, :match): Pass environment
argument to expand-lambda-match.
Diffstat (limited to 'lib.h')
0 files changed, 0 insertions, 0 deletions