On this page:
1.2.1 Cataloguing the lexical context
1.2.2 Interpretation
1.2.3 Local bindings
1.2.4 Auxiliary templates
1.2.5 General
Version: 4.2.1

1.2 Lexical Context Analysis

Synopsis: A syntax template implicitly closes over the bindings of its lexical context. Consequently, by reasoning about the context of a syntax template, one can predict the meanings of references in program fragments it produces.

A syntax template’s lexical context records the association of names to the specific binding occurrences of those names in scope where the template occurs in the program. Lexical context analysis is the process of reasoning about the bindings in the context of a syntax template to predict the meanings of references in program fragments it produces.

An important concern when using syntax templates is making sure their lexical context has the right bindings. Generally this means ensuring that the enclosing module either contains the appropriate definitions or imports the appropriate modules. Either way, the bindings must not be shadowed either by local bindings or pattern variable bindings. (DrScheme’s Check Syntax tool helps illustrate this with its “tentative binding” purple arrows.) The bindings must also be in the correct phase, and the correct phase depends on how the enclosing module is imported (ie, normally, for-syntax, etc).

The rest of this section discusses basic lexical context analysis. Unresolved pattern tag: "multi-phase-lexical-context-analysis" extends the analysis to multiple phases and module graphs involving for-syntax and for-template requires. See other pattern sections for applications of the analysis. In particular, see see the Code Generators pattern for an explanation of phases and scoping in the context of macros and their template-containing auxiliary procedures, and see the Templates for eval pattern for an explanation of phases and scoping for syntax evaluated using eval rather than used in a macro transformation.

1.2.1 Cataloguing the lexical context

The simplest part of lexical context analysis is the lexical context catalogue: a listing of the names in scope with their nearest enclosing binding occurrences.

Consider the following code:
  (module a scheme/base
    (define one 1)
    (define two 2)
    (define-syntax-rule (three) (+ one two))
    (define four (* two two)))

This module has one syntax template, consisting of the code (+ one two). Its lexical context contains the following bindings:
  • one bound by the first definition

  • two bound by the second definition

  • three bound by the third definition – don’t forget the enclosing definition itself!

  • four bound by the fourth definition, even though it’s below the template

  • add1 from scheme/base

  • append from scheme/base

  • ...

  • + from scheme/base

Okay, so the point is that the full catalogue is huge, and contains things that we couldn’t possibly care about (in fact, this is not quite true – see Unresolved pattern tag: "unhygienic-indirect-reference" – but it’s true enough for now). In general, one does not actually enumerate the complete catalogue, or even part of it; rather, one just focuses on the identifiers relevant to the template at hand.

Aside: Some of the bindings in the catalogue above are ordinary bindings and some are syntax bindings. We don’t consider them part of the catalogue per se, but of course once we know the relevant binding occurrence of a name we can inspect the binding form for such information and more.

Back to the catalogue. We can prune the catalogue for the example above to the following relevant entries:
  • one bound by the first definition

  • two bound by the second definition

  • + from scheme/base

So far, so good. Now let’s talk about how to interpret this information.

1.2.2 Interpretation

Here is the code again:
  (module a scheme/base
    (define one 1)
    (define two 2)
    (define-syntax-rule (three) (+ one two))
    (define four (* two two)))
and here is the template in question:
  (+ one two)

The template is the right-hand side of a macro definition. Consequently, it represents the result of the macro. So the desired interpretation of the template is the same as the desired interpretation of the macro.

The desired interpretation of the template is an expression that computes the addition of the module variables one and two.

That is, we want + to refer to the standard addition procedure, + from scheme/base, and we want one to be bound to the definition of one within the module, and likewise for two. The catalogue tells us that they are.

Trivial, no?

1.2.3 Local bindings

Catalogues can involve local bindings as well. Here is an example:

  (module c scheme/base
    ((let ([one 1])
       (lambda (two)
         (let-syntax ([three (syntax-rules ()
                               [(three) (+ one two)])])
           (three))))
     2))

Here’s the catalogue:

Note this time that three is not in the catalogue; if we’d bound the macro using letrec-syntax it would be.

The interpretation is the same, except that it refers to the two local variables. The binding of + is the same.

1.2.4 Auxiliary templates

???

Templates with non-expr roles.

(But don’t talk about phases.)

1.2.5 General

In general, lexical context analysis takes the following questions into consideration:
  • What role does the syntax template play?

  • What is the syntax template’s desired interpretation?

  • What are the references? What bindings should they refer to?

For templates that are the immediate right-hand sides of macros, the role is usually “an expression” or “a definition.” Templates involved in computations, either within a macro or in an auxiliary outside of it, can have other roles, such as “cond clause” or “list of method bindings.”