summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2021-01-22 07:20:44 -0800
committerKaz Kylheku <kaz@kylheku.com>2021-01-22 07:20:44 -0800
commit1e8dc4f05dc5149f682ac16f3d368ec0fc82cf58 (patch)
tree523a98f2a7c79253578ce39295a65644f11f2f32
parent2df5586aebf988091508e5bc8b50a090b153c8e7 (diff)
downloadtxr-1e8dc4f05dc5149f682ac16f3d368ec0fc82cf58.tar.gz
txr-1e8dc4f05dc5149f682ac16f3d368ec0fc82cf58.tar.bz2
txr-1e8dc4f05dc5149f682ac16f3d368ec0fc82cf58.zip
matcher: fix null value ambiguity in hash match.
Hash pattern matching must not assume that if gethash returns nil, the item is not found. That's just a convenience that can be coded in some situations, not in a general mechanism. * share/txr/stdlib/match.tl (compile-hash-match): Allocate a gensym that serves as a unique object. Pass this to gethash as the alt argument, and then check whether gethash has returned this value to indicate failure.
-rw-r--r--share/txr/stdlib/match.tl7
1 files changed, 6 insertions, 1 deletions
diff --git a/share/txr/stdlib/match.tl b/share/txr/stdlib/match.tl
index b6dcd442..32f8b7ca 100644
--- a/share/txr/stdlib/match.tl
+++ b/share/txr/stdlib/match.tl
@@ -314,6 +314,7 @@
(defun compile-hash-match (hash-expr obj-var var-list)
(tree-bind (op . pairs) hash-expr
(let* ((hash-alist-var (gensym "hash-alist-"))
+ (hash-alt-val ^',(gensym "alt"))
(need-alist-p nil)
(hash-matches
(collect-each ((pair pairs))
@@ -338,8 +339,12 @@
(let ((vm (compile-match val (gensym "val") var-list)))
(push
(new match-guard
+ guard-expr ^(neq ,vm.obj-var ,hash-alt-val))
+ vm.guard-chain)
+ (push
+ (new match-guard
vars (list vm.obj-var)
- var-exprs ^((gethash ,obj-var ',key)))
+ var-exprs ^((gethash ,obj-var ',key, hash-alt-val)))
vm.guard-chain)
vm)))))))
(guard (new match-guard