12.4 Syntax Transformers
procedure
(set!-transformer? v) → boolean?
v : any/c
procedure
(make-set!-transformer proc) → set!-transformer?
proc : (syntax? . -> . syntax?)
Example: | ||||||||||||||
|
procedure
(set!-transformer-procedure transformer)
→ (syntax? . -> . syntax?) transformer : set!-transformer?
The property value must be an exact integer or procedure of one or two arguments. In the former case, the integer designates a field within the structure that should contain a procedure; the integer must be between 0 (inclusive) and the number of non-automatic fields in the structure type (exclusive, not counting supertype fields), and the designated field must also be specified as immutable.
If the property value is a procedure of one argument, then the procedure serves as a syntax transformer and for set! transformations. If the property value is a procedure of two arguments, then the first argument is the structure whose type has prop:set!-transformer property, and the second argument is a syntax object as for a syntax transformer and for set! transformations; set!-transformer-procedure applied to the structure produces a new function that accepts just the syntax object and calls the procedure associated through the property. Finally, if the property value is an integer, the target identifier is extracted from the structure instance; if the field value is not a procedure of one argument, then a procedure that always calls raise-syntax-error is used, instead.
If a value has both the prop:set!-transformer and prop:rename-transformer properties, then the latter takes precedence. If a structure type has the prop:set!-transformer and prop:procedure properties, then the former takes precedence for the purposes of macro expansion.
procedure
(rename-transformer? v) → boolean?
v : any/c
Examples: | ||||
|
procedure
(make-rename-transformer id-stx) → rename-transformer?
id-stx : syntax?
Such a transformer could be written manually, but the one created by make-rename-transformer triggers special cooperation with the parser and other syntactic forms when id is bound to the rename transformer:
The parser installs a free-identifier=? and identifier-binding equivalence between id and id-stx, as long as id-stx does not have a true value for the 'not-free-identifier=? syntax property.
A provide of id provides the binding indicated by id-stx instead of id, as long as id-stx does not have a true value for the 'not-free-identifier=? syntax property and as long as id-stx has a binding.
If provide exports id, it uses a symbol-valued 'nominal-id property of id-stx to specify the “nominal source identifier” of the binding as reported by identifier-binding.
If id-stx has a true value for the 'not-provide-all-defined syntax property, then id (or its target) is not exported by all-defined-out.
The syntax-local-value function recognizes rename-transformer bindings and consult their targets.
Examples: | |||||||
|
Changed in version 6.3 of package base: Removed an optional second argument.
procedure
(rename-transformer-target transformer) → identifier?
transformer : rename-transformer?
Example: | ||
|
The property value must be an exact integer, an identifier syntax object, or a procedure that takes one argument. In the former case, the integer designates a field within the structure that should contain an identifier; the integer must be between 0 (inclusive) and the number of non-automatic fields in the structure type (exclusive, not counting supertype fields), and the designated field must also be specified as immutable.
If the property value is an identifier, the identifier serves as the target for renaming, just like the first argument to make-rename-transformer. If the property value is an integer, the target identifier is extracted from the structure instance; if the field value is not an identifier, then an identifier ? with an empty context is used, instead.
If the property value is a procedure that takes one argument, then the procedure is called to obtain the identifier that the rename transformer will use as a target identifier. If the procedure returns any value that is not an identifier, the exn:fail:contract exception is raised.
Examples: | ||||||||||||||||||||||||||||||||||
|
Changed in version 6.3 of package base: the property now accepts a procedure of one argument.
procedure
(local-expand stx context-v stop-ids [ intdef-ctx]) → syntax? stx : any/c context-v : (or/c 'expression 'top-level 'module 'module-begin list?) stop-ids : (or/c (listof identifier?) #f)
intdef-ctx :
(or/c internal-definition-context? (and/c pair? (listof internal-definition-context?)) #f) = #f
When an identifier in stop-ids is encountered by the expander in a sub-expression, expansions stops for the sub-expression. If stop-ids is a non-empty list and does not contain just module*, then begin, quote, set!, lambda, case-lambda, let-values, letrec-values, if, begin0, with-continuation-mark, letrec-syntaxes+values, #%app, #%expression, #%top, and #%variable-reference are added to stop-ids. If #%app or #%datum appears in stop-ids, then application and literal data expressions without the respective explicit form are not wrapped with the explicit form, and #%top wrappers are never added (even with an empty stop-ids list). If stop-ids is #f instead of a list, then stx is expanded only as long as the outermost form of stx is a macro (i.e., expansion does not proceed to sub-expressions). A fully expanded form can include the bindings listed in Fully Expanded Programs plus the letrec-syntaxes+values form and #%expression in any expression position.
When #%plain-module-begin is not itself in stop-ids and module* is in stop-ids, then the #%plain-module-begin transformer refrains from expanding module* sub-forms. Otherwise, the #%plain-module-begin transformer detects and expands sub-forms (such as define-values) independent of the corresponding identifier’s presence in stop-ids.
When context-v is 'module-begin, and the result of expansion is a #%plain-module-begin form, then a 'submodule syntax property is added to each enclosed module form (but not module* forms) in the same way as by module expansion.
The optional intdef-ctx argument must be either #f, the result of syntax-local-make-definition-context, or a list of such results. In the latter two cases, lexical information for internal definitions is added to stx before it is expanded (in reverse order relative to the list). The lexical information is also added to the expansion result (because the expansion might introduce bindings or references to internal-definition bindings).
For a particular internal-definition context, generate a unique value and put it into a list for context-v. To allow liberal expansion of define forms, the generated value should be an instance of a structure with a true value for prop:liberal-define-context. If the internal-definition context is meant to be self-contained, the list for context-v should contain only the generated value; if the internal-definition context is meant to splice into an immediately enclosing context, then when syntax-local-context produces a list, cons the generated value onto that list.
This procedure must be called during the dynamic extent of a syntax transformer application by the expander or while a module is visited (see syntax-transforming?), otherwise the exn:fail:contract exception is raised.
Examples: | ||||||||||||||||||||||||||||||||
|
Changed in version 6.0.1.3 of package base: Changed treatment of #%top so that it is never introduced as an explicit wrapper.
procedure
(syntax-local-expand-expression stx) →
syntax? syntax? stx : any/c
This procedure must be called during the dynamic extent of a syntax transformer application by the expander or while a module is visited (see syntax-transforming?), otherwise the exn:fail:contract exception is raised.
procedure
(local-transformer-expand stx context-v stop-ids [ intdef-ctx]) → syntax? stx : any/c context-v : (or/c 'expression 'top-level list?) stop-ids : (or/c (listof identifier?) #f) intdef-ctx : (or/c internal-definition-context? #f) = #f
procedure
(local-expand/capture-lifts stx context-v stop-ids [ intdef-ctx lift-ctx]) → syntax? stx : any/c context-v : (or/c 'expression 'top-level 'module 'module-begin list?) stop-ids : (or/c (listof identifier?) #f) intdef-ctx : (or/c internal-definition-context? #f) = #f lift-ctx : any/c = (gensym 'lifts)
If context-v is 'top-level or 'module, then module forms can appear in the result as added via syntax-local-lift-module. If context-v is 'module, then module* forms can appear, too.
procedure
(local-transformer-expand/capture-lifts stx context-v stop-ids [ intdef-ctx lift-ctx]) → syntax? stx : any/c context-v : (or/c 'expression 'top-level list?) stop-ids : (or/c (listof identifier?) #f) intdef-ctx : (or/c internal-definition-context? #f) = #f lift-ctx : any/c = (gensym 'lifts)
procedure
v : any/c
procedure
(syntax-local-make-definition-context [ intdef-ctx add-scope?]) → internal-definition-context? intdef-ctx : (or/c internal-definition-context? #f) = #f add-scope? : any/c = #f
An internal-definition context internally creates a scope to represent the context. Unless add-scope? is #f, the scope is added to any form that is expanded within the context or that appears as the result of a (partial) expansion within the context.
If intdef-ctx is not #f, then the new internal-definition context extends the given one. An extending definition context adds all scopes that are added by intdef-ctx, and expanding in the new internal-definition context can use bindings previously introduced into intdef-ctx.
This procedure must be called during the dynamic extent of a syntax transformer application by the expander or while a module is visited (see syntax-transforming?), otherwise the exn:fail:contract exception is raised.
Changed in version 6.3 of package base: Added the add-scope? argument, and made calling internal-definition-context-seal no longer necessary.
procedure
(syntax-local-bind-syntaxes id-list expr intdef-ctx) → void? id-list : (listof identifier?) expr : (or/c syntax? #f) intdef-ctx : internal-definition-context?
This procedure must be called during the dynamic extent of a syntax transformer application by the expander or while a module is visited (see syntax-transforming?), otherwise the exn:fail:contract exception is raised.
procedure
(internal-definition-context-introduce intdef-ctx stx [ mode]) → syntax? intdef-ctx : internal-definition-context? stx : syntax? mode : (or/c 'flip 'add 'remove) = 'flip
Added in version 6.3 of package base.
procedure
(internal-definition-context-seal intdef-ctx) → void?
intdef-ctx : internal-definition-context?
procedure
(identifier-remove-from-definition-context id-stx intdef-ctx) → identifier? id-stx : identifier?
intdef-ctx :
(or/c internal-definition-context? (listof internal-definition-context?))
The identifier-remove-from-definition-context function is provided for backward compatibility; the more general internal-definition-context-introduce function is preferred.
Changed in version 6.3 of package base: Simplified the operation to scope removal.
In a 'module-begin context, then the use is wrapped in a begin form.
In a 'module, 'top-level, 'internal-definition or context, if 'expression is present in the list, then the use is wrapped in an #%expression form.
Otherwise, a syntax error is reported.
The prop:expansion-contexts property is most useful in combination with prop:rename-transformer, since a general transformer procedure can use syntax-local-context. Furthermore, a prop:expansion-contexts property makes the most sense when a rename transformer’s identifier has the 'not-free-identifier=? property, otherwise a definition of the binding creates a binding alias that effectively routes around the prop:expansion-contexts property.
Added in version 6.2.900.12 of package base.
procedure
(syntax-local-value id-stx [ failure-thunk intdef-ctx]) → any id-stx : syntax? failure-thunk : (or/c (-> any) #f) = #f
intdef-ctx :
(or/c internal-definition-context? #f) = #f
If id-stx is bound to a rename transformer created with make-rename-transformer, syntax-local-value effectively calls itself with the target of the rename and returns that result, instead of the rename transformer.
If id-stx has no transformer binding (via define-syntax, let-syntax, etc.) in that environment, the result is obtained by applying failure-thunk if not #f. If failure-thunk is false, the exn:fail:contract exception is raised.
This procedure must be called during the dynamic extent of a syntax transformer application by the expander or while a module is visited (see syntax-transforming?), otherwise the exn:fail:contract exception is raised.
Examples: | ||||||||||||
|
Examples: | |||||||
|
Examples: | |||||||||||||||
|
procedure
(syntax-local-value/immediate id-stx [ failure-thunk intdef-ctx]) → any id-stx : syntax? failure-thunk : (or/c (-> any) #f) = #f
intdef-ctx :
(or/c internal-definition-context? #f) = #f
If id-stx has no transformer binding, then failure-thunk is called (and it can return any number of values), or an exception is raised if failure-thunk is #f.
procedure
stx : syntax?
A run-time expression within a module is lifted to the module’s top level, just before the expression whose expansion requests the lift. Similarly, a run-time expression outside of a module is lifted to a top-level definition. A compile-time expression in a letrec-syntaxes+values or define-syntaxes binding is lifted to a let wrapper around the corresponding right-hand side of the binding. A compile-time expression within begin-for-syntax is lifted to a define declaration just before the requesting expression within the begin-for-syntax.
Other syntactic forms can capture lifts by using local-expand/capture-lifts or local-transformer-expand/capture-lifts.
This procedure must be called during the dynamic extent of a syntax transformer application by the expander or while a module is visited (see syntax-transforming?), otherwise the exn:fail:contract exception is raised.
procedure
→ (listof identifier?) n : exact-nonnegative-integer? stx : syntax?
This procedure must be called during the dynamic extent of a syntax transformer application by the expander or while a module is visited (see syntax-transforming?), otherwise the exn:fail:contract exception is raised.
procedure
This procedure must be called during the dynamic extent of a syntax transformer application by the expander or while a module is visited (see syntax-transforming?), otherwise the exn:fail:contract exception is raised.
procedure
(syntax-local-lift-module stx) → void?
stx : syntax?
The module is not immediately declared when syntax-local-lift-module returns. Instead, the module declaration is recorded for processing when expansion returns to the enclosing module body or top-level sequence.
Added in version 6.2.900.10 of package base.
procedure
stx : syntax?
procedure
(syntax-local-lift-require raw-require-spec stx) → syntax? raw-require-spec : any/c stx : syntax?
The resulting syntax object is the same as stx, except that a fresh scope is added. The same scope is added to the lifted #%require form, so that the #%require form can bind uses of imported identifiers in the resulting syntax object (assuming that the lexical information of stx includes the binding environment into which the #%require is lifted).
If raw-require-spec and stx are part of the input to a transformer, then typically syntax-local-introduce should be applied to each before passing them to syntax-local-lift-require, and then syntax-local-introduce should be applied to the result of syntax-local-lift-require. Otherwise, marks added by the macro expander can prevent access to the new imports.
This procedure must be called during the dynamic extent of a syntax transformer application by the expander or while a module is visited (see syntax-transforming?), otherwise the exn:fail:contract exception is raised.
procedure
(syntax-local-lift-provide raw-provide-spec-stx) → void?
raw-provide-spec-stx : syntax?
procedure
This procedure must be called during the dynamic extent of a syntax transformer application by the expander or while a module is visited (see syntax-transforming?), otherwise the exn:fail:contract exception is raised.
The symbol results indicate that the expression is being expanded for an expression context, a top-level context, a module context, or a module-begin context.
A list result indicates expansion in an internal-definition context. The identity of the list’s first element (i.e., its eq?ness) reflects the identity of the internal-definition context; in particular two transformer expansions receive the same first value if and only if they are invoked for the same internal-definition context. Later values in the list similarly identify internal-definition contexts that are still being expanded, and that required the expansion of nested internal-definition contexts.
This procedure must be called during the dynamic extent of a syntax transformer application by the expander or while a module is visited (see syntax-transforming?), otherwise the exn:fail:contract exception is raised.
procedure
Examples: | ||||||||||||||||||||||||||
|
procedure
(syntax-local-module-exports mod-path)
→ (listof (cons/c (or/c exact-integer? #f) (listof symbol?)))
mod-path :
(or/c module-path? (and/c syntax? (lambda (stx) (module-path? (syntax->datum stx)))))
This procedure must be called during the dynamic extent of a syntax transformer application by the expander or while a module is visited (see syntax-transforming?), otherwise the exn:fail:contract exception is raised.
procedure
This procedure must be called during the dynamic extent of a syntax transformer application by the expander or while a module is visited (see syntax-transforming?), otherwise the exn:fail:contract exception is raised.
procedure
(syntax-local-get-shadower id-stx [ only-generated?]) → identifier? id-stx : identifier? only-generated? : any/c = #f
This function is intended for the implementation of syntax-parameterize and local-require.
This procedure must be called during the dynamic extent of a syntax transformer application by the expander or while a module is visited (see syntax-transforming?), otherwise the exn:fail:contract exception is raised.
Changed in version 6.3 of package base: Simplified to the minimal functionality needed for syntax-parameterize and local-require.
procedure
(syntax-local-make-delta-introducer id-stx) → procedure?
id-stx : identifier?
Changed in version 6.3 of package base: changed to raise exn:fail:supported.
procedure
(syntax-local-certifier [active?])
→
((syntax?) (any/c (or/c procedure? #f)) . ->* . syntax?) active? : boolean? = #f
procedure
procedure
procedure
(syntax-local-identifier-as-binding id-stx) → identifier?
id-stx : identifier?
In a syntax transformer that runs in a non-expression context and forces the expansion of subforms with local-expand, use syntax-local-identifier-as-binding on an identifier from the expansion before moving it into a binding position or comparing with with bound-identifier=?. Otherwise, the results can be inconsistent with the way that define works in the same definition context.
This procedure must be called during the dynamic extent of a syntax transformer application by the expander or while a module is visited (see syntax-transforming?), otherwise the exn:fail:contract exception is raised.
Added in version 6.3 of package base.
procedure
(syntax-local-introduce stx) → syntax?
stx : syntax?
This procedure must be called during the dynamic extent of a syntax transformer application by the expander or while a module is visited (see syntax-transforming?), otherwise the exn:fail:contract exception is raised.
procedure
(make-syntax-introducer [as-use-site?])
→ ((syntax?) ((or/c 'flip 'add 'remove)) . ->* . syntax?) as-use-site? : any/c = #f
The action of the generated procedure can be 'flip (the default) to flip the presence of a scope in each part of a given syntax object, 'add to add the scope to each regardless of whether it is present already, or 'remove to remove the scope when it is currently present in any part.
Multiple applications of the same make-syntax-introducer result procedure use the same scope, and different result procedures use distinct scopes.
Changed in version 6.3 of package base: Added the optional as-use-site? argument, and added the optional operation argument in the result procedure.
procedure
(make-syntax-delta-introducer ext-stx base-stx [ phase-level]) → ((syntax?) ((or/c 'flip 'add 'remove)) . ->* . syntax?) ext-stx : syntax? base-stx : (or/c syntax? #f)
phase-level : (or/c #f exact-integer?) = (syntax-local-phase-level)
This procedure is potentially useful when m-id has a transformer binding that records some orig-id, and a use of m-id introduces a binding of orig-id. In that case, the scopes one the use of m-id added since the binding of m-id should be transferred to the binding instance of orig-id, so that it captures uses with the same lexical context as the use of m-id.
If ext-stx is tainted or armed, then an identifier result from the created procedure is tainted.
procedure
procedure
→ (and/c hash? immutable?)
It returns a hash table mapping a phase-level number (such as 0) to a list of all definitions at that phase level within the module being expanded. This information is used for implementing provide sub-forms like all-defined-out.
Beware that the phase-level keys are absolute relative to the enclosing module, and not relative to the current transformer phase level as reported by syntax-local-phase-level.
procedure
(syntax-local-module-required-identifiers mod-path phase-level)
→
(listof (cons/c (or/c exact-integer? #f) (listof identifier?))) mod-path : (or/c module-path? #f) phase-level : (or/c exact-integer? #f #t)
It returns an association list mapping phase levels to lists of identifiers. Each list of identifiers includes all bindings imported (into the module being expanded) using the module path mod-path, or all modules if mod-path is #f. The association list includes all identifiers imported with a phase-level shift, of all shifts if phase-level is #t.
When an identifier is renamed on import, the result association list includes the identifier by its internal name. Use identifier-binding to obtain more information about the identifier.
Beware that the phase-level keys are absolute relative to the enclosing module, and not relative to the current transformer phase level as reported by syntax-local-phase-level.
value
procedure
v : any/c
The liberal-define-context? predicate returns #t if v is an instance of a structure with a true value for the prop:liberal-define-context property, #f otherwise.
12.4.1 require Transformers
(require racket/require-transform) | package: base |
A transformer binding whose value is a structure with the prop:require-transformer property implements a derived require-spec for require as a require transformer.
A require transformer is called with the syntax object representing its use as a require-spec within a require form, and the result must be two lists: a list of imports and a list of import-sources.
If the derived form contains a sub-form that is a require-spec, then it can call expand-import to transform the sub-require-spec to lists of imports and import sources.
See also define-require-syntax, which supports macro-style require transformers.
procedure
(expand-import stx) →
(listof import?) (listof import-source?) stx : syntax?
procedure
(require-transformer? v) → boolean?
v : any/c
struct
(struct import ( local-id src-sym src-mod-path mode req-mode orig-mode orig-stx) #:extra-constructor-name make-import) local-id : identifier? src-sym : symbol?
src-mod-path :
(or/c module-path? (and/c syntax? (lambda (stx) (module-path? (syntax->datum stx))))) mode : (or/c exact-integer? #f) req-mode : (or/c exact-integer? #f) orig-mode : (or/c exact-integer? #f) orig-stx : syntax?
local-id —
the identifier to be bound within the importing module. src-sym —
the external name of the binding as exported from its source module. src-mod-path —
a module path (relative to the importing module) for the source of the imported binding. orig-stx —
a syntax object for the source of the import, used for error reporting. mode —
the phase level of the binding in the importing module. req-mode —
the phase level shift of the import relative to the exporting module. orig-mode —
the phase level of the binding as exported by the exporting module.
struct
(struct import-source (mod-path-stx mode) #:extra-constructor-name make-import-source)
mod-path-stx :
(and/c syntax? (lambda (x) (module-path? (syntax->datum x)))) mode : (or/c exact-integer? #f)
mod-path-stx —
a module path (relative to the importing module) for the source of the imported binding. mode —
the phase level shift of the import.
parameter
(current-require-module-path) → (or/c #f module-path-index?)
(current-require-module-path module-path) → void? module-path : (or/c #f module-path-index?)
When the value of current-require-module-path is #f, relative module paths are left as-is, which means that the require context determines the resolution of the module path.
The require form parameterizes current-require-module-path as #f while invoking sub-form transformers, while relative-in parameterizes to a given module path.
procedure
(convert-relative-module-path module-path)
→
(or/c module-path? (and/c syntax? (lambda (stx) (module-path? (syntax-e stx)))))
module-path :
(or/c module-path? (and/c syntax? (lambda (stx) (module-path? (syntax-e stx)))))
If module-path is not relative or if the value of current-require-module-path is #f, then module-path is returned. Otherwise, module-path is converted to an absolute module path that is equivalent to module-path relative to the value of current-require-module-path.
12.4.2 provide Transformers
(require racket/provide-transform) | package: base |
A transformer binding whose value is a structure with the prop:provide-transformer property implements a derived provide-spec for provide as a provide transformer. A provide transformer is applied as part of the last phase of a module’s expansion, after all other declarations and expressions within the module are expanded.
A transformer binding whose value is a structure with the prop:provide-pre-transformer property implements a derived provide-spec for provide as a provide pre-transformer. A provide pre-transformer is applied as part of the first phase of a module’s expansion. Since it is used in the first phase, a provide pre-transformer can use functions such as syntax-local-lift-expression to introduce expressions and definitions in the enclosing module.
An identifier can have a transformer binding to a value that acts both as a provide transformer and provide pre-transformer. The result of a provide pre-transformer is not automatically re-expanded, so a provide pre-transformer can usefully expand to itself in that case.
A transformer is called with the syntax object representing its use as a provide-spec within a provide form and a list of symbols representing the export modes specified by enclosing provide-specs. The result of a provide transformer must be a list of exports, while the result of a provide pre-transformer is a syntax object to be used as a provide-spec in the last phase of module expansion.
If a derived form contains a sub-form that is a provide-spec, then it can call expand-export or pre-expand-export to transform the sub-provide-spec sub-form.
See also define-provide-syntax, which supports macro-style provide transformers.
procedure
(expand-export stx modes) → (listof export?)
stx : syntax? modes : (listof (or/c exact-integer? #f))
procedure
(pre-expand-export stx modes) → syntax?
stx : syntax? modes : (listof (or/c exact-integer? #f))
procedure
proc :
(syntax? (listof (or/c exact-integer? #f)) . -> . (listof export?)) (make-provide-transformer proc pre-proc) → (and/c provide-transformer? provide-pre-transformer?)
proc :
(syntax? (listof (or/c exact-integer? #f)) . -> . (listof export?))
pre-proc :
(syntax? (listof (or/c exact-integer? #f)) . -> . syntax?)
procedure
(make-provide-pre-transformer pre-proc)
→ provide-pre-transformer?
pre-proc :
(syntax? (listof (or/c exact-integer? #f)) . -> . syntax?)
procedure
(provide-transformer? v) → boolean?
v : any/c
procedure
v : any/c
struct
(struct export (local-id out-sym mode protect? orig-stx) #:extra-constructor-name make-export) local-id : identifier? out-sym : symbol? mode : (or/c exact-integer? #f) protect? : any/c orig-stx : syntax?
local-id —
the identifier that is bound within the exporting module. out-sym —
the external name of the binding. orig-stx —
a syntax object for the source of the export, used for error reporting. protect? —
indicates whether the identifier should be protected (see Code Inspectors). mode —
the phase level of the binding in the exporting module.
12.4.3 Keyword-Argument Conversion Introspection
(require racket/keyword-transform) | package: base |
procedure
→
(or/c #f (letrec ([val? (recursive-contract (or/c (cons/c identifier? identifier?) (cons/c val? val?)))]) val?)) stx : syntax?
procedure
→
(or/c #f (letrec ([val? (recursive-contract (or/c (cons/c identifier? identifier?) (cons/c val? val?)))]) val?)) stx : syntax?
The property value is normally a pair consisting of the original identifier and an identifier that appears in the expansion. Property-value merging via syntax-track-origin can make the value a pair of such values, and so on.