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.