;'<<SPEC'
<!--
Copyright (c) 2012-2024, Chris Pressey, Cat's Eye Technologies.
This file is distributed under a 2-clause BSD license. See LICENSES/ dir.
SPDX-License-Identifier: LicenseRef-BSD-2-Clause-X-Robin
-->
### `unshadow` ###
-> Tests for functionality "Evaluate Robin Expression (with Env)"
`unshadow` is similar to `unbind`, but only removes the latest binding
for the given identifier; previously shadowed bindings, if any exist,
will be visible instead.
| (unshadow yog-sothoth (if #t (literal x) (literal y)))
= x
| (unshadow if (if #t (literal x) (literal y)))
? abort (unbound-identifier if)
| (bind if (literal what)
| (unshadow if (if #t (literal x) (literal y))))
= x
| (bind q 400
| (unshadow q q))
? abort (unbound-identifier q)
| (bind q 200
| (bind q 400
| (unshadow q q)))
= 200
| (bind q 100
| (bind q 200
| (bind q 400
| (unshadow q (unshadow q q)))))
= 100
| (let ((q 100)
| (q 200)
| (q 400))
| (unshadow q (unshadow q q)))
= 100
`unshadow` is something of a gimmick that shows off Robin's ability
to manipulate the evaluation environment. In practice, the bindings
can be determined lexically, and a different identifier could always
be chosen instead.
'<<SPEC'
(define unshadow
(fexpr (args env)
(bind remove-binding-r (fun (self id li)
(if (empty? li)
li
(if (equal? (head (head li)) id)
(tail li)
(prepend (head li) (self self id (tail li))))))
(eval (remove-binding-r remove-binding-r (head args) env)
(head (tail args))))))