summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2023-07-27 20:24:33 -0700
committerKaz Kylheku <kaz@kylheku.com>2023-07-27 20:24:33 -0700
commit718718b657cc07dab9b3f3e74106b4ba4d0dadaf (patch)
treeb9217e739b0a82fcb82ebaf381eee1720b46b219
parent9fd7b65bfbc670dbfb14d7b46061e48d603dd98c (diff)
downloadtxr-718718b657cc07dab9b3f3e74106b4ba4d0dadaf.tar.gz
txr-718718b657cc07dab9b3f3e74106b4ba4d0dadaf.tar.bz2
txr-718718b657cc07dab9b3f3e74106b4ba4d0dadaf.zip
match: bug: lexical symbol macros neglected
When a pattern variable match like @foo references a global symbol macro, that's treated as an existing expression to match, and not a new binding. However, local symbol macros are not treated this way; they are invisible to variable patterns. That is an unintended inconsistency. * stdlib/match.tl (var-list exists): Use lexical-binding-kind rather than lexical-var-p. This returns true for lexical symbol macros also. * tests/011/patmatch.tl: New test cases. * txr.1: Documentation revised to clarify that both global and local symbol macros are considered to be existing variable bindings by pattern matching.
-rw-r--r--stdlib/match.tl2
-rw-r--r--tests/011/patmatch.tl19
-rw-r--r--txr.113
3 files changed, 28 insertions, 6 deletions
diff --git a/stdlib/match.tl b/stdlib/match.tl
index 149ea71f..65382cc2 100644
--- a/stdlib/match.tl
+++ b/stdlib/match.tl
@@ -121,7 +121,7 @@
menv
(:method exists (me sym) (or (member sym me.vars)
- (lexical-var-p me.menv sym)
+ (lexical-binding-kind me.menv sym)
(boundp sym)))
(:method record (me sym) (push sym me.vars))
(:method merge (me copy) (each ((v copy.vars)) (pushnew v me.vars))))
diff --git a/tests/011/patmatch.tl b/tests/011/patmatch.tl
index 2e05d59f..bb67e32e 100644
--- a/tests/011/patmatch.tl
+++ b/tests/011/patmatch.tl
@@ -583,6 +583,25 @@
(match-cond
(`@x-24` `42-@y`))) "42-24")
+(mtest
+ (symacrolet ((x 3))
+ (match @x 4 x)) :error
+ (symacrolet ((x 3))
+ (match @x 3 x)) 3
+ (let ((x 3))
+ (match @x 4 x)) :error
+ (let ((x 3))
+ (match @x 3 x)) 3)
+
+(defvar dv :dv)
+(defsymacro gs :gs)
+
+(mtest
+ (match @dv 0 dv) :error
+ (match @dv :dv dv) :dv
+ (match @gs 0 gs) :error
+ (match @gs :gs gs) :gs)
+
(compile-only
(eval-only
(with-compile-opts (nil unused)
diff --git a/txr.1 b/txr.1
index 63fece15..f66508ea 100644
--- a/txr.1
+++ b/txr.1
@@ -45388,12 +45388,15 @@ occurring in a pattern may be a fresh variable, or a reference to an existing
one. The difference between these situations is not apparent from the syntax
of the pattern; it depends on the context established by the scope.
-With one exception, if a pattern contains a variable which is already in
-the surrounding scope, including a global variable, then it refers to that
-variable. Otherwise, it freshly binds the variable.
-The exception is that pattern operator
+With one exception, if a pattern contains a variable which is already bound in
+the surrounding scope, then it refers to that binding. Otherwise, it freshly
+binds the variable. The exception is that pattern operator
.code @(as)
-always binds a fresh variable.
+always binds a fresh variable. A variable being already bound includes
+as a lexical or global symbol macro
+.cod2 ( symacrolet
+or
+.codn defsymacro ).
When a pattern variable refers to an existing variable, then each occurrence
of that variable must match an object which is