diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2023-07-27 20:24:33 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2023-07-27 20:24:33 -0700 |
commit | 718718b657cc07dab9b3f3e74106b4ba4d0dadaf (patch) | |
tree | b9217e739b0a82fcb82ebaf381eee1720b46b219 | |
parent | 9fd7b65bfbc670dbfb14d7b46061e48d603dd98c (diff) | |
download | txr-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.tl | 2 | ||||
-rw-r--r-- | tests/011/patmatch.tl | 19 | ||||
-rw-r--r-- | txr.1 | 13 |
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) @@ -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 |