Let’s create a single lexical contour with the syntax
internal-body and compare a top–level binding with a local
binding:
(define A 1)
(internal-body
(define B 2)
(begin-for-syntax
(pretty-print (syntax A))
(pretty-print (syntax B))
(pretty-print (eq-ribs? (syntax A) (syntax B))))
(void))
-| #<syntactic-identifier expr=A mark*=(src)>
-| #<syntactic-identifier expr=B mark*=(src)>
-| #t
we see that the syntactic identifiers created by syntax in the
begin-for-syntax have the same list of marks and the same list
of rib objects.
Let’s see the rib objects:
(define A 1)
(internal-body
(define B 2)
(begin-for-syntax
(let ((ribs (xp::stx-rib* #'A)))
(pretty-print (length ribs))
(pretty-print ribs)))
(void))
-| 2
-| (#<rib name*=(B) mark**=((src)) label*=(lab.B)>
#<rib name*=(A ...) mark**=((src) ...) label*=(lab.A ...)>)
the list of rib objects in the identifier ‘(syntax A)’ has two
items: the first is the rib associated to internal-body; the
second is the top rib. We see the internal rib holds a single
tuple describing the syntactic binding for ‘B’; the syntactic
binding for ‘A’ is in the top rib.
With this layout we can understand what the function id->label
does in the call:
(define A 1)
(internal-body
(begin-for-syntax
(pretty-print (id->label #'A)))
(void))
-| lab.A
it extracts from its argument the symbol source–name ‘A’, the list
of marks ‘(src)’ and the list of rib objects, then it scans the
list of rib objects left–to–right looking for a tuple whose
source–name is eq? to ‘A’ and whose list of marks is
equal? to ‘(src)’; it finds one in the top rib.
This action of looking for a rib’s tuple with the same source–name
and the same marks is the syntactic identifier resolution, and we
say that the tuple captures the identifier.
This is not the whole story: to handle macro expansion we need more than
this; but for lexical contours: building a list of rib objects and
using a single mark is enough.