3.5 Code Binding-Space Adjusters
import: scribble/spacer | package: rhombus-scribble-lib |
A spacer is a compile-time function that is used by forms like rhombus to determine how names within a typeset form should be linked to documentation. For example, :: in some contexts should be linked to the :: expression operator, and in other contexts to the :: binding operator. In general, typeset code cannot be executed or expanded to determine those bindings. Instead, links are determined by a combination of meta_label imports and spacer-applied properties. Spacers thus provide an approximate and best-effort attempt to properly link names in documentation.
A spacer can also communicate indirect binding information to support linking of names after .. For example, the length method name in [1, 2, 3].length() should be linked to the documentation of List.length, independent of whatever meta_label binding the identifier length length might have. See Spacers and Indirect Binding for more information.
definition | ||||||||
| ||||||||
| ||||||||
|
The body result should be a syntax object like '$self_id $tail_id', but where space properties are added within self_id and tail_id via functions like set and adjust_term. Take care to preserve syntax locations and properties via Syntax.relocate when reconstructing syntax objects; functions like adjust_term use Syntax.relocate automatically, but can obviously only cover the given syntax object.
The context_id argument will be a keyword, symbol, or list of symbols corresponding to one of the spaces. The spacer’s behavior might depend on that context, but often it’s passed along as-is to functions like set or adjust_group.
The esc_id argument is an identifier or operator syntax object that specifies an escape operator, such as #,. Spacing should general not traverse into escaped forms.
If a ~left argument is declared, then the spacer can be called in either infix or prefix mode. When called in prefix mode, the argument for ~left will be an empty syntax object, ''.
A Context represents one or more spaces for recording as a property or adding further space annotations. When a Context is a list to be recorded in a property, space symbols in the list will be tried first to last to look for link-target bindings within each space.
function | ||||
| ||||
| ||||
function | ||||
| ||||
| ||||
function | ||||
| ||||
| ||||
function | ||||
| ||||
| ||||
function | ||||
| ||||
| ||||
function | ||||
|
The adjust_rest_sequence function supports the possibility of an infix spacer at the start of stx, in which case head is propagated to the spacer as the ~left argument.
3.5.1 Spacers and Indirect Binding
In addition to setting the space of a name, a spacer can add syntax properties that communicate binding and annotation information. Resolving these properties some requires extra context as provided by the documentation of a form, such as the annotation for a function’s result.
For example, to implement the connection that links the length method name in [1, 2, 3].length() to List.length, the spacer for #%brackets adds a #'annot property to the [1, 2, 3] term with the value 'List'; then, the method List.length can be inferred by treating the annotation name as a namespace.
In the case of to_string(1).length(), the term before . is (1), but that term is part of a function call. The #%call infix spacer adds a property to (1) to say that its annotation is effectively the result of calling to_string. The result annotation for to_string is determined to be String via cross-reference information stored by the fun documentation form as used to document to_string.
The following syntax property keys (see Syntax/property) are recognized; take care to add them as preserved properties:
#'spacer_key: used by other syntax objects to refer to the one with the property. References to spaced terms generally make sense only with in a set of syntax objects that are compiled an serialized together, so the value of #'spacer_key can be a gensym created by Symbol.gen.
#'field: on a field identifier to connect it to an annotation-as-namespace that exports the field, typically by referring to another term. A #'field value can have one of several recognized shapes:
#'annot: on a field identifier to connect it to a namespace name that exports the field, typically by referring to another term. A #'annot value can have one of several recognized shapes:
Pair(#'as, key_symbol): refers to another term by it’s #'spacer_key value, where that term should be an identifier that is used as the namespace name.
Pair(#'as_export, id): provides a namespace name directly as id.
Pair(#'result, key_symbol): refers to another term by it’s #'spacer_key value, where that term should be an identifier that is hyperlinked as a function, and the function’s result annotation (as recorded in documentation) is used as the namespace name.
#'bind: on an identifier to indicate that it is a binding. A #'bind value can have one of the following recognized shapes:
Some inference steps may require cross-reference information from documentation, such as the result annotation of a function. That cross-reference information can be provided by a documentation form that is bound by doc.bridge, implemented with doc_meta.transformer, and through an ~extract_spacer_infos function that produces a map with the following recognized keys:
#'result_annotation: an identifier for the result of a documented function, method, or property. The identifier is used as a namespace for the purpose of finding methods and properties within that result.
#'method_fallback: an identifier associated with an annotation that names another annotation/namespace. The other namespace should be consulted when a field cannot be found under the associated annotation. That is, the other annotation is typically a “supertype.”