Next: expander intro lex, Previous: expander intro times, Up: expander intro [Index]
A syntactic binding is an association between an identifier and the result of evaluating an expression; there are different kinds:
Syntactic forms built into the language, they are called primitive core
macros and primitive non–core macros. They are lambda,
define, let and similar, define-syntax,
letrec-syntax, if, and, or and all
the rest.
Associations between identifiers and expressions evaluated at run–time.
They are established by define, let, letrec
and similar.
Associations between identifiers and expressions evaluated at expand–time. The identifiers in this role are called syntactic keywords (not to be confused with keyword objects like ‘#:hello’). Examples of keyword bindings are user–defined macros (also named user–defined syntaxes).
Let’s consider the following syntactic form:
(let ((a 1)) a)
the let syntax defines a variable binding whose name is
‘a’; a variable binding is an association between a name and the
result of evaluating an expression at run–time.
Let’s consider the following form:
(let-syntax ((a (identifier-syntax 1))) a)
let-syntax defines a keyword binding whose name is ‘a’; a
keyword binding is an association between a name and the result of
evaluating an expression at expand–time.
The identifiers ‘a’ in the first argument of let and
let-syntax are in binding position; the identifiers in
the bodies of let and let-syntax are in reference
position. The identifier in reference position is a reference to the
identifier in binding position: we say that the identifier in reference
position is “captured” by the identifier in binding position.
The expansion process proceeds from the outer forms to the inner forms. Given the syntactic form:
(let ((a 1))
(let ((b 2))
(+ a b)))
first the outer let is processed and the syntactic binding for
‘a’ is established; then the inner let is processed and
the syntactic binding for ‘b’ is established; finally the
expression (+ a b) is processed in a lexical context in which the
syntactic bindings exist.
The region of the syntactic binding ‘a’ is the inner let
form; notice that the binding for ‘a’ is not visible in the
right–hand side of its definition. The region of the syntactic binding
‘b’ is the internal expression.
During the expansion process: syntactic bindings are added to an internal data structure that collects the associations, keeping track of nested regions of visibility: the lexical environment. The lexical environment is somewhat handled like a stack: while entering internal expressions, syntactic binding descriptors are pushed on the stack.
Let’s consider the following library:
(library (demo)
(export)
(import (rnrs (6)))
(define var 1)
(define (fun a)
(let ((b 2))
(let-syntax ((c (identifier-syntax 3)))
(display (+ a b c))
(newline))))
(define-syntax syn
(syntax-rules ()
((_ ?obj)
(display ?obj))))
(import (prefix (vicare posix) px.))
(display (px.getenv "PATH"))
(newline)
#| end of library |# )
we introduce the definitions:
The syntactic bindings imported by the import clause of the
library form and by the import syntax in the body of
the library, constitute the initial lexical environment for the
expansion process of the library.
In the example: the initial environment is the set of bindings exported
by the libraries (rnrs (6)) and (vicare posix).
NOTE An
importsyntax that appears in an internal body as in:(lambda () (import (srfi :19)) (do-something))does not add bindings to the initial environment: it adds them to the local lexical environment.
Syntactic bindings defined in the body of the library with
define and define-syntax; the ones defined by
define are variable bindings, the ones defined by
define-syntax are keyword bindings.
Top level bindings are visible in the whole library body: their region
is the whole body. Top level bindings have indefinite extent: their
values are never garbage collected, they exists for the whole life of
the vicare process.
In the example: ‘var’ and ‘fun’ are top level variables; ‘syn’ is a top level keyword.
Every identifier in reference position that is not captured by a
syntactic binding definition in the library itself must be captured by a
binding in the initial environment; otherwise an exception is raised
with condition object of type &undefined.
Syntactic bindings defined by a syntax that limits their region of
visibility to a subform of the library body. Bindings defined by
let and similar syntaxes are local variable bindings, as well
as those defined by define in an internal body. Bindings
defined by let-syntax and similar syntaxes are local keyword
bindings, as well as those defined by define-syntax in an
internal body.
In the example: ‘a’ and ‘b’ are local variable bindings; ‘c’ is a local keyword binding.
Next: expander intro lex, Previous: expander intro times, Up: expander intro [Index]