11.8 Syntax Certificates
Syntax Certificates in Guide: Racket introduces syntax certificates.
A syntax certificate combines a syntax mark (see Transformer Bindings), a module path index or symbol module name (see Compiled Modules and References), an inspector (see Code Inspectors), and an arbitrary key object. A certificate is attached as either an active certificate or an inactive certificate.
The datum->syntax procedure never transfers an active certificate from one syntax object to another. The syntax-recertify procedure can be used to transfer a certificate from one syntax object to another, but only if the certificate’s key is provided, or if a sufficiently powerful inspector is provided. Thus, a certificate’s inspector serves two roles: it determines the certificate’s power to grant access, and also allows the certificate to be moved arbitrarily by anyone with a more powerful inspector.
The expander generates a certificate when it applies a syntax transformer. The syntax mark in the certificate is fresh, the certificate’s module reference corresponds to the module that defined the transformer binding, the inspector is the inspector for the module’s declaration (see Code Inspectors), and the key object is hidden. (Applying the result of syntax-local-certifier can introduce certificates with other keys.) The certificate’s mark is applied to both the input and output of the syntax transformer, so that it identifies every piece of syntax that was introduced by the transformer (see Transformer Bindings). The expander attaches this certificate to parts of the transformer’s result, depending on the shape and properties of the result:
If the result has a 'certify-mode property (see Syntax Object Properties) that is 'opaque, then the certificate is attached to the immediate syntax object.
If the result has a 'certify-mode property that is 'transparent, then the certificate is also propagated recursively to syntax object that corresponds to elements of the syntax object’s datum as a list (or, more precisely, to the cars of the datum as reached by any number of cdrs). This recursive propagation uses syntax properties and shapes, as for the immediate attachment.
If the result has a 'certify-mode property that is 'transparent-binding, then the certificate is attached in a way similar to 'transparent, but further treating the syntax object corresponding to the second list element as having a 'transparent value for the 'certify-mode property if it does not already have a 'certify-mode property value.
If the result has no 'certify-mode property value, but its datum is a pair, and if the syntax object corresponding to the car of the pair is an identifier bound to begin, module, or #%plain-module-begin, then the certificate is propagated as if the syntax object had the 'transparent property value.
If the result has no 'certify-mode property value, but its datum is a pair, and if the syntax object corresponding to the car of the pair is an identifier bound to define-values or define-syntaxes, then the certificate is propagated as if the syntax object had the 'transparent-binding property value.
To avoid accidental transfer for a 'certify-mode property value, the expander always removes any 'certify-mode property on a syntax object that is passed to a syntax transformer.
As the expander attaches a new active certificate to a syntax object, it also removes any inactive certificates attached to any syntax object within the one where the certificate is attached, and it re-attaches the formerly inactive certificates as active certificates along with the new one.
As the expander processes a form, it accumulates active certificates that are attached to enclosing forms as part of the expansion context:
To check access to an unexported identifier, the expander checks each of the identifier’s marks and module bindings; if, for some mark, the identifier’s enclosing expressions include a certificate with the mark, the identifier’s binding module, and with an inspector that controls the module’s invocation (as opposed to the module’s declaration; see again Code Inspectors), then the access is allowed. To check access to a protected identifier, only the certificate’s mark and inspector are used (i.e., the module that bound the transformer is irrelevant, as long as it was evaluated with a sufficiently powerful inspector). The certificate key is not used in checking references.
To check access to a locally bound identifier, the expander checks the marks of the binding and reference identifiers; for every mark that they have in common, if the reference identifier has a certificate for the mark from an enclosing expression, the binding identifier must have a certificate for the mark from an enclosing expression, otherwise the reference is disallowed. (The reference identifier can have additional certificates for marks that are not attached to the binding identifier.) The binding module (if any) and the certificate key are not used for checking a local reference.
When the expander encounters a quote-syntax form, it attaches all accumulated active certificates from the expression’s context to the quoted syntax objects. A certificate for the enclosing module (if any) is also included. The certificates are attached as inactive certificates to the immediate syntax object (i.e., not to any nested syntax objects). In addition, any inactive certificates within the quoted syntax object are lifted to the immediate syntax object.
Finally, for the result of expand or local-expand with an empty stop list, certificates are lifted to the outermost result expression, except to the degree that 'certify-mode property values and bindings like begin direct certificates to sub-expressions.
| ||||||||||||||||||||||||||||
new-stx : syntax? | ||||||||||||||||||||||||||||
old-stx : syntax? | ||||||||||||||||||||||||||||
inspector : inspector? | ||||||||||||||||||||||||||||
key : any/c |