[Racket] Language Model(二):Syntax Model

The syntax of a Racket program is defined by

Racket 程序的语法是这样定义的,

a read pass that processes a character stream into a syntax object; and
an expand pass that processes a syntax object to produce one that is fully parsed.

读取阶段,将字符流转换成语法对象。
宏展开阶段,将语法对象转换解析完毕状态。

Source code is normally read in read-syntax mode, which produces a syntax object.

源代码通常使用 read-syntax 读入,最后生成一个语法对象。

The expand pass recursively processes a syntax object to produce a complete parse of the program. Binding information in a syntax object drives the expansion process, and when the expansion process encounters a binding form, it extends syntax objects for sub-expression with new binding information.

宏展开阶段,会递归的处理语法对象,最后得到一个完全解析的程序。
语法对象中包含的绑定信息驱动了展开过程,
展开过程中,遇到新的绑定时,会对语法对象中的绑定信息进行扩展。

1. 标识符,绑定和作用域(Identifiers, Binding, and Scopes)

An identifier is a source-program entity. Parsing (i.e., expanding) a Racket program reveals that some identifiers correspond to variables, some refer to syntactic forms (such as lambda, which is the syntactic form for functions), some refer to transformers for macro expansion, and some are quoted to produce symbols or syntax objects. An identifier binds another (i.e., it is a binding) when the former is parsed as a variable or syntactic form and the latter is parsed as a reference to the former; the latter is bound.

标识符是与源代码相关的概念。
程序的解析(即,宏展开)过程中,会看到某些标识符是变量,另一些是句法形式(syntactic forms)(例如,lambda 是函数的句法形式),
还有一些标识符表示了用于宏展开的语法变换,或者是被引用的标识符,表示符号或语法对象。

我们说标识符有了一个绑定,指的是标识符被解析成变量或句法形式,标识符引用了它们。

For example, as a fragment of source, the text

例如,以下代码片段,

(let ([x 5]) x)

includes two identifiers: let and x (which appears twice). When this source is parsed in a context where let has its usual meaning, the first x binds the second x.

包含两个标识符,letxx 出现了两次)。
let 就是通常意义下的含义,创建了 x 的一个绑定。

Bindings and references are determined through scope sets. A scope corresponds to a region of the program that is either in part of the source or synthesized through elaboration of the source. Nested binding contexts (such as nested functions) create nested scopes, while macro expansion creates scopes that overlap in more complex ways. Conceptually, each scope is represented by a unique token, but the token is not directly accessible. Instead, each scope is represented by a value that is internal to the representation of a program.

绑定和引用是由作用域决定的,作用域指的是程序的一片区域,它或者是源代码的一部分,或者包含了从源代码中推算出来的信息。
嵌套的绑定上下文(例如,嵌套函数)会创建嵌套的作用域,宏展开时会创建更复杂的作用域。

理论上,每一个作用域会被唯一标识,作用域标识无法直接访问。
每个作用域被表示为一个语言实现相关的内部值。

A form is a fragment of a program, such as an identifier or a function call. A form is represented as a syntax object, and each syntax object has an associated set of scopes (i.e., a scope set). In the above example, the representations of the xs include the scope that corresponds to the let form.

句型(form)指的是程序片段,例如,一个标识符,或者一个函数调用。
每个句型是由语法对象表示的,被关联了一组作用域。

上述例子中,x 对应的语法对象中包含了 let 句型提供的作用域。

When a form parses as the binding of a particular identifier, parsing updates a global table that maps a combination of an identifier’s symbol and scope set to its meaning: a variable, a syntactic form, or a transformer. An identifier refers to a particular binding when the reference’s symbol and the identifier’s symbol are the same, and when the reference’s scope set is a superset of the binding’s scope set. For a given identifier, multiple bindings may have scope sets that are subsets of the identifier’s; in that case, the identifier refers to the binding whose set is a superset of all others; if no such binding exists, the reference is ambiguous (and triggers a syntax error if it is parsed as an expression). A binding shadows any binding (i.e., it is shadowing any binding) that the same symbol but a subset of scopes.

当一个句型被解析为标识符的绑定时,解析器会更新一个全局表,
这个表中保存了标识符符号,以及相关的作用域,到标识符含义(变量,句法形式,语法变换)的映射关系。

标识符的符号名,以及标识符的作用域,唯一确定了它的绑定。
某个标识符,可能在它相关的一组作用域中有不同的绑定,标识符指向了包含作用域最多(超集)的那个绑定。
如果绑定不存在,那么该引用就是有歧义的(解析表达式的时候,会产生语法错误)。

同一个作用域中的绑定,由最小作用域中的绑定覆盖。

For example, in

例如,

(let ([x 5]) x)

in a context where let corresponds to the usual syntactic form, the parsing of let introduces a new scope for the binding of x. Since the second x receives that scope as part of the let body, the first x binds the second x. In the more complex case

let 表示通常意义下句法形式,它会引入一个新的作用域,其中设置了 x 的绑定。
由于第二个 x 是在 let 内部获取作用域的,因此,第一个 x 设置了第二个 x 的绑定。

我们再看一个更复杂的例子,

(let ([x 5])
  (let ([x 6])
    x))

the inner let creates a second scope for the second xs, so its scope set is a superset of the first x’s scope set—which means that the binding for the second x shadows the one for the first x, and the third x refers to the binding created by the second one.

里面那个 let 为第二个 x 创建了另一个作用域,
所以第二个 x 的作用域集,比第一个 x 多一个(超集),
这意味着,对 x 的第二次绑定覆盖了先前对 x 的第一次绑定。
因此,第三个 x 指的是 x 的第二次绑定。

A top-level binding is a binding from a definition at the top-level; a module binding is a binding from a definition in a module; all other bindings are local bindings. Within a module, references to top-level bindings are disallowed. An identifier without a binding is unbound.

顶层绑定,指的是位于顶层定义的绑定。
模块绑定,指的是在模块中定义的绑定。
其他所有的绑定都是局部绑定。

在模块中无法引用顶层绑定,没有绑定的标识符,称为未绑定的。

Throughout the documentation, identifiers are typeset to suggest the way that they are parsed. A hyperlinked identifier like lambda indicates a reference to a syntactic form or variable. A plain identifier like x is a variable or a reference to an unspecified top-level variable.

本文档中,标识符的不同排版,表明了它的解析方式,
黑体的标识符,例如 lambda 表示它是一个句型或变量的引用。
普通标识符,例如 x,表示变量,或引用了不确定的顶层变量。

Every binding has a phase level in which it can be referenced, where a phase level normally corresponds to an integer (but the special label phase level does not correspond to an integer). Phase level 0 corresponds to the run time of the enclosing module (or the run time of top-level expressions). Bindings in phase level 0 constitute the base environment. Phase level 1 corresponds to the time during which the enclosing module (or top-level expression) is expanded; bindings in phase level 1 constitute the transformer environment. Phase level -1 corresponds to the run time of a different module for which the enclosing module is imported for use at phase level 1 (relative to the importing module); bindings in phase level -1 constitute the template environment. The label phase level does not correspond to any execution time; it is used to track bindings (e.g., to identifiers within documentation) without implying an execution dependency.

每个绑定都有一个阶段值,只有在特定的阶段才能引用它,阶段值通常是一个整数。
0 阶段指的是包含它的模块处于运行时阶段(或者如果它位于顶层,指的是顶层表达式位于运行时阶段)。
0 阶段的绑定,构成了最基础的环境。

1 阶段,意味着包含它的模块(或顶层表达式)正在进行宏展开。
1 阶段的绑定,构成了语法转换环境。

-1 阶段,指的是某一模块的运行时阶段,该模块被另一个模块位于第 1 阶段的模块所导入。
-1 阶段的绑定,构成了模板环境。

运行时用不到阶段值,它只是用来跟踪绑定用的。

An identifier can have different bindings in different phase levels. More precisely, the scope set associated with a form can be different at different phase levels; a top-level or module context implies a distinct scope at every phase level, while scopes from macro expansion or other syntactic forms are added to a form’s scope sets at all phases. The context of each binding and reference determines the phase level whose scope set is relevant.

标识符在不同的阶段,可以有不同的绑定,
更具体的说,句型相关的作用域,在不同阶段可能会不同。
顶层或模块上下文,在每个不同的阶段,会不一样。

宏展开或者其他句法形式相关的作用域,会添加到每个阶段句型的作用域中。
绑定上下文和引用,决定了要用哪一个阶段的作用域。

2. 语法对象(Syntax Objects)

A syntax object combines a simpler Racket value, such as a symbol or pair, with lexical information, source-location information, syntax properties, and tamper status. The lexical information of a syntax object comprises a set of scope sets, one for each phase level. In particular, an identifier is represented as a syntax object containing a symbol, and its lexical information can be combined with the global table of bindings to determine its binding (if any) at each phase level.

Racket 中的一些简单的值,例如符号或点对,连同它们的词法信息,源代码位置,语法属性,修改状态等等,组成了语法对象。
语法对象中的词法信息,包含了由一组作用域,每一个作用域都有特定的阶段有关。

一个用语法对象表示的标识符,包含符号和词法信息,词法信息可以和全局绑定表整合起来,来决定每个阶段的绑定。

For example, a car identifier might have lexical information that designates it as the car from the racket/base language (i.e., the built-in car). Similarly, a lambda identifier’s lexical information may indicate that it represents a procedure form. Some other identifier’s lexical information may indicate that it references a top-level variable.

例如,标识符 car 可能会包含词法信息,这些信息是在内置的 racket/base 指定的。
类似的,lambda 标识符的词法信息中,可能指定了它是一个函数句型。
另外一个标识符的词法信息,可能指明它是一个顶层变量。

When a syntax object represents a more complex expression than an identifier or simple constant, its internal components can be extracted. Even for extracted identifiers, detailed information about binding is available mostly indirectly; two identifiers can be compared to determine whether they refer to the same binding (i.e., free-identifier=?), or whether the identifiers have the same scope set so that each identifier would bind the other if one were in a binding position and the other in an expression position (i.e., bound-identifier=?).

当语法对象用来表示比标识符或常量,更复杂的表达式时,它内部的元素可以被读取出来。
即使可以读取部分信息,关于绑定的详细信息,大部分也只能间接获取。

两个标识符可以进行对比,来判断出它们是否具有相同的绑定(例如,free-identifier=?)。
或者判断这两个标识符是否具有相同的作用域,因此每个标识符都可以绑定为另一个(例如,bound-identifier=?)。

For example, when the program written as

例如,下面的程序

(let ([x 5]) (+ x 6))

is represented as a syntax object, then two syntax objects can be extracted for the two xs. Both the free-identifier=? and bound-identifier=? predicates will indicate that the xs are the same. In contrast, the let identifier is not free-identifier=? or bound-identifier=? to either x.

可以被表示为语法对象,则每个 x 都会对应一个语法对象。
free-identifier=?bound-identifier=? 都会表明这两个 x 是相同的。
let 与这两个 x 都不相同。

The lexical information in a syntax object is independent of the rest of the syntax object, and it can be copied to a new syntax object in combination with an arbitrary other Racket value. Thus, identifier-binding information in a syntax object is predicated on the symbolic name of the identifier as well as the identifier’s lexical information; the same question with the same lexical information but different base value can produce a different answer.

语法对象中的词法信息,与后面的语法对象是不同的。
但是,这些词法信息可以被复制出去,然后与 Racket 任意一个值的语法对象进行合并。
因此,语法对象中存的标识符的绑定信息,指的是符号和标识符的词法信息。
类似的情况,相同的词法信息,但是不同的基础值,则会产生不同的结果。

For example, combining the lexical information from let in the program above to 'x would not produce an identifier that is free-identifier=? to either x, since it does not appear in the scope of the x binding. Combining the lexical context of the 6 with 'x, in contrast, would produce an identifier that is bound-identifier=? to both xs.

例如,合并 let 中的词法信息到 'x 中,产生的新标识符,与任何 x 都不 free-identifier=?
因为它并没有在 x 的绑定中出现。

合并 6 的词法上下文给 'x,则会产生一个与两个 xbound-identifier=? 的标识符。

The quote-syntax form bridges the evaluation of a program and the representation of a program. Specifically, (quote-syntax datum #:local) produces a syntax object that preserves all of the lexical information that datum had when it was parsed as part of the quote-syntax form. Note that (quote-syntax datum) form is similar, but it removes certain scopes from the datum’s scope sets.

quote-syntax 句型建立了对程序进行求值,与表示一段代码之间的桥梁。
更确切的说,(quote-syntax datum #:local) 会创建一个语法对象,并保留 datum 被解析为 quote-syntax 句型时的所有的词法信息。
注意到,它与 (quote-syntax datum) 很相似,不过后者会从 datum 的作用域集中,移除某些作用域。

3. 宏展开(Expansion (Parsing))

Expansion recursively processes a syntax object in a particular phase level, starting with phase level 0. Bindings from the syntax object’s lexical information drive the expansion process, and cause new bindings to be introduced for the lexical information of sub-expressions. In some cases, a sub-expression is expanded in a deeper phase than the enclosing expression.

展开是某个阶段中,递归处理语法对象的过程,展开过程一般从第 0 阶段开始。
语法对象词法信息中的绑定关系,驱动了展开过程,子表达式也可能会引入新的绑定。
在某些情况下,子表达式会比父表达式于更靠后的阶段进行展开。

(1)程序的完全展开(Fully Expanded Programs)

A complete expansion produces a syntax object matching the following grammar:

一个完全展开后的程序,指的是符合以下文法的语法对象。

top-level-form = general-top-level-form
               | (#%expression expr) 
               | (module id module-path
                   (#%plain-module-begin
                    module-level-form ...))
               | (begin top-level-form ...)
               | (begin-for-syntax top-level-form ...)

module-level-form = general-top-level-form
                  | (#%provide raw-provide-spec ...)
                  | (begin-for-syntax module-level-form ...) 
                  | submodule-form 
                  | (#%declare declaration-keyword ...)

submodule-form = (module id module-path
                   (#%plain-module-begin 
                    module-level-form ...))
               | (module* id module-path 
                   (#%plain-module-begin 
                    module-level-form ...)) 
               | (module* id #f 
                   (#%plain-module-begin 
                   module-level-form ...))

general-top-level-form = expr
                       | (define-values (id ...) expr) 
                       | (define-syntaxes (id ...) expr) 
                       | (#%require raw-require-spec ...)

expr = id
     | (#%plain-lambda formals expr ...+) 
     | (case-lambda (formals expr ...+) ...) 
     | (if expr expr expr) | (begin expr ...+) 
     | (begin0 expr expr ...)
     | (let-values ([(id ...) expr] ...)
         expr ...+) 
     | (letrec-values ([(id ...) expr] ...)
         expr ...+) 
     | (set! id expr) 
     | (quote datum) 
     | (quote-syntax datum) 
     | (quote-syntax datum #:local) 
     | (with-continuation-mark expr expr expr) 
     | (#%plain-app expr ...+) 
     | (#%top . id) 
     | (#%variable-reference id) 
     | (#%variable-reference (#%top . id)) 
     | (#%variable-reference)

formals = (id ...)
        | (id ...+ . id) 
        | id

A fully-expanded syntax object corresponds to a parse of a program (i.e., a parsed program), and lexical information on its identifiers indicates the parse.

完全展开后的语法对象,表示解析完毕的程序,词法信息中包含了语法分析的内容。

More specifically, the typesetting of identifiers in the above grammar is significant. For example, the second case for expr is a syntax-object list whose first element is an identifier, where the identifier’s lexical information specifies a binding to the #%plain-lambda of the racket/base language (i.e., the identifier is free-identifier=? to one whose binding is #%plain-lambda). In all cases, identifiers above typeset as syntactic-form names refer to the bindings defined in §3 “Syntactic Forms”.

例如,expr 的第二种情况,是一个语法对象列表,第一个元素的一个标识符,
该标识符的词法信息中,将它绑定到了 #%plain-lambda 上。(即,该标识符与其他绑定为 #%plain-lambda 的标识符是 free-identifier=? 的)。

In a fully expanded program for a namespace whose base phase is 0, the relevant phase level for a binding in the program is N if the bindings has N surrounding begin-for-syntax and define-syntaxes forms —— not counting any begin-for-syntax forms that wrap a module or module* form for the body of the module or module*, unless a module* form has #f in place of a module-path after the id. The datum in a quote-syntax form preserves its information for all phase levels.

完全展开后的程序中包含的第 0 阶段的名字空间,如果它的外层包含 Nbegin-for-syntaxdefine-syntaxes,则相关绑定的阶段为 N
不需要计算 modulemodule* 中的 begin-for-syntax,除非是 module*id 后面的 module-path 设置为了 #f

quote-syntax句型中的 datum 为所有阶段保存了词法信息。

A reference to a local binding in a fully expanded program has a scope set that matches its binding identifier exactly. Additional scopes, if any, are removed. As a result, bound-identifier=? can be used to correlate local binding identifiers with reference identifiers, while free-identifier=? must be used to relate references to module bindings or top-level bindings.

完全展开后的程序中的局部绑定,包含了一个标识符相关的作用域集。其他附加的作用域,都会被删除。
因此,bound-identifier=? 只能用于对比局部绑定的标识符和与它有相同引用的标识符。
free-identifier=? 则用于对比模块级绑定或顶层绑定。

In addition to the grammar above, #%expression can appear in a fully local-expanded expression position. For example, #%expression can appear in the result from local-expand when the stop list is empty. Reference-identifier scope sets are reduced in local-expanded expressions only when the local-expand stop list is empty.

除了上面的文法之外,#%expression 可以出现在所有局部完全展开后的表达式位置。
例如,#%expression 可以出现在 local-expand 的结果中(当结果为空时)。

(2)展开步骤(xpansion Steps)

In a recursive expansion, each single step in expanding a syntax object at a particular phase level depends on the immediate shape of the syntax object being expanded:

在递归展开中,每个阶段语法对象的展开方式,与具体语法对象的形式有关。

If it is an identifier (i.e., a syntax-object symbol), then a binding is determined by the identifier’s lexical information. If the identifier has a binding, that binding is used to continue. If the identifier is unbound, a new syntax-object symbol '#%top is created using the lexical information of the identifier; if this #%top identifier has no binding, then parsing fails with an exn:fail:syntax exception. Otherwise, the new identifier is combined with the original identifier in a new syntax-object pair (also using the same lexical information as the original identifier), and the #%top binding is used to continue.

如果是一个标识符(即,一个语法对象符号),则绑定是由该标识符的词法信息决定的。
如果标识符有绑定,则使用这个绑定继续进行下去。

如果标识符是未绑定的,则会创建一个新的语法对象符号 '#%top,并使用该标识符词法信息。
如果这个 #%top 标识符没有绑定,则解析过程会报错,抛出 exn:fail:syntax 异常。
否则,新标识符会与原标识符合并成一个新的语法对象,使用 #%top 这个绑定继续进行。

If it is a syntax-object pair whose first element is an identifier, and if the identifier has a binding other than as a top-level variable, then the identifier’s binding is used to continue.

如果是一对语法对象,第一个元素是一个标识符,而且这个标识符并没有绑定到顶层变量上,
那么使用这个标识符的绑定,继续进行。

If it is a syntax-object pair of any other form, then a new syntax-object symbol '#%app is created using the lexical information of the pair. If the resulting #%app identifier has no binding, parsing fails with an exn:fail:syntax exception. Otherwise, the new identifier is combined with the original pair to form a new syntax-object pair (also using the same lexical information as the original pair), and the #%app binding is used to continue.

如果是其他形式的一对语法对象,则会使用符号 '#%app 创建一个新的语法对象,并使用这对语法对象的词法信息。
如果 #%app 标识符是未绑定的,则解析过程会报错,抛出 exn:fail:syntax 异常。
否则,新标识符与原来的一对语法对象将合并成一个新的语法对象,使用 #%app 这个绑定继续进行。

If it is any other syntax object, then a new syntax-object symbol '#%datum is created using the lexical information of the original syntax object. If the resulting #%datum identifier has no binding, parsing fails with an exn:fail:syntax exception. Otherwise, the new identifier is combined with the original syntax object in a new syntax-object pair (using the same lexical information as the original pair), and the #%datum binding is used to continue.

如果是其他形式的语法对象,则会使用符号 '#%datum 创建一个新的语法对象,并使用原来语法对象的词法信息。
如果 #%datum 标识符是未绑定的,则解析过程会报错,抛出 exn:fail:syntax 异常。
否则,新标识符与原来的一对语法对象将合并成一个新的语法对象,使用 #%datum 这个绑定继续进行。

Thus, the possibilities that do not fail lead to an identifier with a particular binding. This binding refers to one of three things:

因此,如果不报错,就会引入一个新的标识符(和绑定),这个标识符可以做以下三件事,

A transformer, such as introduced by define-syntax or let-syntax. If the associated value is a procedure of one argument, the procedure is called as a syntax transformer (described below), and parsing starts again with the syntax-object result. If the transformer binding is to any other kind of value, parsing fails with an exn:fail:syntax exception. The call to the syntax transformer is parameterized to set current-namespace to a namespace that shares bindings and variables with the namespace being used to expand, except that its base phase is one greater.

转换器,例如通过 define-syntaxlet-syntax 引入的标识符。
如果关联的值是一个单参函数,那么这个函数就称为语法转换器,解析会在语法转换之后继续进行。
如果转换器绑定具有其他形式,解析过程会抛 exn:fail:syntax 异常。

A variable binding, such as introduced by a module-level define or by let. In this case, if the form being parsed is just an identifier, then it is parsed as a reference to the corresponding variable. If the form being parsed is a syntax-object pair, then an #%app is added to the front of the syntax-object pair in the same way as when the first item in the syntax-object pair is not an identifier (third case in the previous enumeration), and parsing continues.

变量绑定,例如通过模块级的 definelet 引入。
在这种情况下,如果被解析的句型只是一个标识符,则它被解析为一个对相应变量的引用。
如果被解析的句型是一对语法对象,那么 #%app 会被添加到这一对语法对象前面,如果这对语法对象的一个元素不是一个标识符的话。

A core syntactic form, which is parsed as described for each form in §3 “Syntactic Forms”. Parsing a core syntactic form typically involves recursive parsing of sub-forms, and may introduce bindings that determine the parsing of sub-forms.

一个核心句法形式,解析一个核心句法形式,通常会涉及递归的解析它的子句法形式,
过程中可能会产生新的绑定,影响以后的解析过程。

(3)展开上下文(Expansion Context)

Each expansion step occurs in a particular context, and transformers and core syntactic forms may expand differently for different contexts. For example, a module form is allowed only in a top-level context, and it fails in other contexts. The possible contexts are as follows:

每个展开步骤,是在一个特定上下文中进行的。
并且转换器或核心句法形式,可能会在不同的上下文中展开为不同的结果。
例如,module 句型只能在顶层上下文中使用,在其他上下文中会报错。

可能的上下文如下,

top-level context : outside of any module, definition, or expression, except that sub-expressions of a top-level begin form are also expanded as top-level forms.

顶层上下文:位于任何模块,定义,或者表达式之外。
顶层 begin 的子表达式也位于顶层上下文中。

module-begin context : inside the body of a module, as the only form within the module.

模块开始处的上下文:模块内部的上下文,是模块内的唯一句型。

module context : in the body of a module (inside the module-begin layer).

模块上下文:位于模块开始上下文里面

internal-definition context : in a nested context that allows both definitions and expressions.

内部定义上下文:在一个嵌套上下文中,允许出现定义和表达式。

expression context : in a context where only expressions are allowed.

表达式上下文:只允许出现表达式

Different core syntactic forms parse sub-forms using different contexts. For example, a let form always parses the right-hand expressions of a binding in an expression context, but it starts parsing the body in an internal-definition context.

不同的核心句法形式,在不同的上下文中解析它们的子句法形式。
例如,let 总是会在表达式上下文中解析它右边的表达式,但是在 let 中则会以内部定义上下文进行解析。

(4)引入绑定(Introducing Bindings)

Bindings are introduced during expansion when certain core syntactic forms are encountered:

某些特定的核心句法形式会引入新的绑定。

When a require form is encountered at the top level or module level, each symbol specified by the form is paired with the scope set of the specification to introduce new bindings. If not otherwise indicated in the require form, bindings are introduced at the phase levels specified by the exporting modules: phase level 0 for each normal provide, phase level 1 for each for-syntax provide, and so on. The for-meta provide form allows exports at an arbitrary phase level (as long as a binding exists within the module at the phase level).

如果在顶层或模块级,遇到了一个 require,该句型中涉及到的每个符号连同作用域一起,会产生一个新绑定。
如果在 require 形式中没有指定的话,绑定阶段会由导出模块给出。
普通的 provide 指定为第 0 阶段,for-syntax provide 指定为第 1 阶段。
for-meta provide 允许导出一个任意阶段的绑定。

A for-syntax sub-form within require imports similarly, but the resulting bindings have a phase level that is one more than the exported phase levels, when exports for the label phase level are still imported at the label phase level. More generally, a for-meta sub-form within require imports with the specified phase level shift; if the specified shift is #f, or if for-label is used to import, then all bindings are imported into the label phase level.

require 中的 for-syntax 的导入方式类似,只是导入的绑定会比导出模块中定义的阶段更高一级。
更一般的,require 中的 for-meta 会按明确的偏移量进行导入,
如果偏移量指定为 #f,或者使用 for-label 导入,那么所有的绑定按标签指定的阶段导入。

When a define, define-values, define-syntax, or define-syntaxes form is encountered at the top level or module level, a binding is added phase level 0 (i.e., the base environment is extended) for each defined identifier.

如果在顶层或模块级,遇到了define define-values define-syntax define-syntaxes
则绑定被设置为第 0 阶段。

When a begin-for-syntax form is encountered at the top level or module level, bindings are introduced as for define-values and define-syntaxes, but at phase level 1 (i.e., the transformer environment is extended). More generally, begin-for-syntax forms can be nested, an each begin-for-syntax shifts its body definition by one phase level.

如果在顶层或模块级发现了 begin-for-syntax,引入的绑定就像 define-values define-syntaxes 一样,不过是位于第 1 阶段。
更一般的,begin-for-syntax 是支持嵌套的,每一层增加一个阶段。

When a let-values form is encountered, the body of the let-values form is extended (by creating new syntax objects) with a fresh scope. The scope is added to the identifiers themselves, so that the identifiers in binding position are bound-identifier=? to uses in the fully expanded form, and so they are not bound-identifier=? to other identifiers. The new bindings are at the phase level at which the let-values form is expanded.

当遇到 let-values 的时候,其内部会用一个新的作用域扩展(通过创造一个新的语法对象)。
作用域会被添加到标识符上,因此,该标识符与其完全展开后是 bound-identifier=? 的,但是与其他标识符不是 bound-identifier=? 的。
新的绑定与 let-values 位于同一个阶段。

When a letrec-values or letrec-syntaxes+values form is encountered, bindings are added as for let-values, except that the right-hand-side expressions are also extended with the new scope.

当遇到 letrec-valuesletrec-syntaxes+values 时,绑定方式与 let-values 类似,
除非它们右侧的表达式,又用一个新作用域进行了扩展。

Definitions in internal-definition contexts introduce new scopes and bindings as described in §1.2.3.8 “Internal Definitions”.

For example, in

例如,

(let-values ([(x) 10]) (+ x y))

the binding introduced for x applies to the x in the body, because a fresh scope is created and added to both the binding x and reference x. The same scope is added to the y, but since it has a different symbol than the binding x, it does not refer to the new binding. Any x outside of this let-values form does not receive the fresh scope and therefore does not refer to the new binding.

对第一个 x 的绑定可以应用于第二个 x,是因为一个新的作用域同时添加到了这两个 x 上。
同样的作用域也被添加到了 y 上,但是因为具有与 x 不同的符号,因此并不指向 x 的绑定。
任何 let-values 外的 x 并没有添加这个新作用域,因此也不会指向这个绑定。

(5)转换器绑定(Transformer Bindings)

In a top-level context or module context, when the expander encounters a define-syntaxes form, the binding that it introduces for the defined identifiers is a transformer binding. The value of the binding exists at expansion time, rather than run time (though the two times can overlap), though the binding itself is introduced with phase level 0 (i.e., in the base environment).

顶层上下文或模块上下文中,如果展开器遇到了一个 define-syntaxes,就会引入一个用于转换器的绑定。
这个绑定会存在于展开期,但是不存在于运行期,即使绑定本身是在第 0 阶段引入的。

The value for the binding is obtained by evaluating the expression in the define-syntaxes form. This expression must be expanded (i.e., parsed) before it can be evaluated, and it is expanded at phase level 1 (i.e., in the transformer environment) instead of phase level 0.

绑定的值是在求值 define-syntaxes 表达式时获得的。
该表达式在求值之前必须先进行展开,因此它位于第 1 阶段进行展开,而不是第 0 阶段。

If the resulting value is a procedure of one argument or the result of make-set!-transformer on a procedure, then it is used as a syntax transformer (a.k.a. macro). The procedure is expected to accept a syntax object and return a syntax object. A use of the binding (at phase level 0) triggers a call of the syntax transformer by the expander.

如果结果值是一个单参函数,或者是 make-set!-transformer 处理一个函数后的结果,那么它就会被用于进行语法转换(宏)。
该函数期望接受一个语法对象,并返回一个语法对象。
位于第 0 阶段,对该绑定的调用,会由展开器出发一个语法转换。

Before the expander passes a syntax object to a transformer, the syntax object is extended with a fresh macro-introduction scope (that applies to all sub-syntax objects) to distinguish syntax objects at the macro’s use site from syntax objects that are introduced by the macro; in the result of the transformer the presence of the scope is flipped, so that introduced syntax objects retain the scope, and use-site syntax objects do not have it. In addition, if the use of a transformer is in the same definition context as its binding, the use-site syntax object is extended with an additional fresh use-site scope that is not flipped in the transformer’s result, so that only use-site syntax objects have the use-site scope.

在展开器将语法对象传给一个转换器之前,语法对象会先用为一个新的宏导入作用域(macro-introduction scope)扩展,
为了将宏使用的语法对象,和宏引入的语法对象。
转换完成后,传入的语法对象的作用域传到了结果语法对象中。

如果转换器与对它的绑定在同一个定义上下文中,则传入的语法对象会用一个工作用的作用域(use-site scope)扩展,并且不会传给结果。

The scope-introduction process for macro expansion helps keep binding in an expanded program consistent with the lexical structure of the source program. For example, the expanded form of the program

宏展开阶段的作用域引入过程,利于在展开过程中使用源代码的词法信息。
例如,以下程序

(define x 12)
(define-syntax m
  (syntax-rules ()
    [(_ id) (let ([x 10]) id)]))
(m x)

is

将展开为,

(define x 12)
(define-syntax m ....)
(let ([x 10]) x)

However, the result of the last expression is 12, not 10. The reason is that the transformer bound to m introduces the binding x, but the referencing x is present in the argument to the transformer. The introduced x is left with one fresh scope, while the reference x has a different fresh scope, so the binding x is not bound-identifier=? to the body x.

然而,最后一个表达式的值应该是 12,不能是 10
这是因为转换器 m 引入了新的绑定 x,但是对 x 的引用又是通过转换器的参数传入的。
x 的新绑定比后面作为引用出现的 x 作用域少一个,后者处于一个不同的新作用域中,因此,它们是不 bound-identifier=? 的。

A use-site scope on a binding identifier is ignored when the definition is in the same context where the use-site scope was introduced. This special treatment of use-site scopes allows a macro to expand to a visible definition. For example, the expanded form of the program

绑定中的工作用作用域(use-site scope)会被忽略掉,如果标识符的定义和引入工作用作用域的位置在同一个上下文中。
这一个特殊处理,可以让宏展开为一个定义。

例如,以下程序,

(define-syntax m
  (syntax-rules ()
    [(_ id) (define id 5)]))
(m x)
x

is

将展开为,

(define-syntax m ....)
(define x 5)
x

where the x in the define form has a use-site scope that is not present on the final x. The final x nevertheless refers to the definition, because the use-site scope is effectively removed before installing the definition’s binding. In contrast, the expansion of

define 中的 x 有一个工作用的作用域,但是最后那个 x 却没有。
最后那个 x 并不会指向上面那个定义,因为工作用的作用域会在展开后删掉。

作为对比,以下程序,

(define-syntax m
  (syntax-rules () 
    [(_ id) (let ([x 4]) 
              (let ([id 5]) x))])) 
(m x)

is

将展开为

(define-syntax m ....)
(let ([x 4])
  (let ([x 5]) 
    x))

where the second x has a use-site scope that prevents it from binding the final x. The use-site scope is not ignored in this case, because the binding is not part of the definition context where (m x) was expanded.

第二个 x 有一个工作用作用域,结果并不绑定到最后那个 x 上。
在这种情况下,工作用作用域并不会被忽略,因为在 (m x) 展开式,绑定并不位于定义上下文中。

The set! form works with the make-set!-transformer and prop:set!-transformer property to support assignment transformers that transform set! expressions. An assignment transformer contains a procedure that is applied by set! in the same way as a normal transformer by the expander.

set! 可以和 make-set!-transformer prop:set!-transformer 一起使用,支持赋值转换器用来转换 set! 表达式。
赋值转换器被用于 set!,就像其他的转换器那样。

The make-rename-transformer procedure or prop:rename-transformer property creates a value that is also handled specially by the expander and by set! as a transformer binding’s value. When id is bound to a rename transformer produced by make-rename-transformer, it is replaced with the target identifier passed to make-rename-transformer. In addition, as long as the target identifier does not have a true value for the 'not-free-identifier=? syntax property, the binding table is extended to indicate that id is an alias for the identifier in the rename transformer. The free-identifier=? function follows aliasing chains to determine equality of bindings, the identifier-binding function similarly follows aliasing chains, and the provide form exports id as the target identifier. Finally, the syntax-local-value function follows rename transformer chains even when binding aliases are not installed.

make-rename-transformer prop:rename-transformer 产生的值被展开器特殊处理了,使用了 set! 作为转换器。
id 通过 make-rename-transformer 绑定到一个重命名转换器(ename transformer)上时,
它会被替换为目标标识符,然后传给 make-rename-transformer,绑定表会被扩展,以表明 id 是该标识符的一个别名。
free-identifier=? 根据别名链来检测绑定的相等性,identifier-binding 在别名链后面,提供了 id 作为目标标识符。

In addition to using scopes to track introduced identifiers, the expander tracks the expansion history of a form through syntax properties such as 'origin.

除了使用作用域来跟踪标识符之外,展开器还会使用语法属性跟踪展开历史,例如 'origin

Finally, the expander uses a tamper status to control the way that unexported and protected module bindings are used. See §12.8 “Syntax Taints” for more information on a tamper status.

扩展器还会使用修改状态,来控制不能使用禁止导出或者受保护的模块绑定。

The expander’s handling of letrec-syntaxes+values is similar to its handling of define-syntaxes. A letrec-syntaxes+values can be expanded in an arbitrary phase level n (not just 0), in which case the expression for the transformer binding is expanded at phase level n+1.

扩展器处理 letrec-syntaxes+values 的过程跟 define-syntaxes 相似,
letrec-syntaxes+values 可以在任意阶段 n 被展开,此时这个阶段的转换器位于第 n+1 阶段。

The expressions in a begin-for-syntax form are expanded and evaluated in the same way as for define-syntaxes. However, any introduced bindings from definition within begin-for-syntax are at phase level 1 (not a transformer binding at phase level 0).

begin-for-syntax 中的表达式被展开和求值的方式与 define-syntaxes 相同,
只不过 begin-for-syntax 中引入的绑定位于第 1 阶段。

(6)Local Binding Context

(7)Partial Expansion

(8)Internal Definitions

(9)Module Expansion, Phases, and Visits

(10)Macro-Introduced Bindings

4. Compilation

5. Namespaces

6. Inferred Value Names

7. Cross-Phase Persistent Module Declarations


参考

The Racket Reference v7.4.0.9

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353