3.2 Representing Static Information
Static information for an expression or binding is represented in key–value form and encoded within syntax objects at expansion time. When static information is associated with a binding, it is propagated to each use of the bound variable, so we can refer to an expression E that has static information without loss of generality.
A macro defined with expr.macro can associate arbitrary key–value static information with its result using statinfo_meta.wrap. More generally, any macro that produces or manipulates an expression can add static information to the expression using statinfo_meta.wrap. A macro can consult static information for an expression using statinfo_meta.lookup and related functions. Predefined Rhombus forms use these operations internally; for example, :: expands to an expression that has static information provided by the annotation after ::.
The statinfo.key forms binds an identifier for use as a static-information key. Rhombus built-in forms use several built-in keys that can be accessed as identifier-valued variables like statinfo_meta.dot_provider_key:
statinfo_meta.dot_provider_key: Names a compile-time function that macro-expands any use of . after E. For example, assuming a class Posn(x, y) declaration, p :: Posn associates statinfo_meta.dot_provider_key with uses of p to expand p.x and p.y to field accesses. An expression is a dot provider when it has static information mapped by statinfo_meta.dot_provider_key.
statinfo_meta.call_result_key: Provides static information to be attached to a function-call expression where the function position is E. (The arguments in the call do not matter.) For example, class Posn(x, y) associates statinfo_meta.call_result_key with Posn itself, and the associated value is static information with statinfo_meta.dot_provider_key. So, Posn(1, 2) gets statinfo_meta.dot_provider_key that makes Posn(1, 2).x select the 1.
statinfo_meta.index_result_key: Provides static information to be attached to a […] indexing reference where E is to the left of the […]. (The index expression inside […] does not matter.) For example ps :: List.of(Posn) associates statinfo_meta.index_result_key to ps, where the associated value is static information with statinfo_meta.dot_provider_key. So, ps[i].x is allowed and selects an x field from the Posn instance produced by ps[i].
statinfo_meta.index_get_key and statinfo_meta.index_set_key: Names a form to use for a […] indexing reference or assignment where E is to the left of the […]. (The index expression inside […] does not matter.) For example, p :: Array associates statinfo_meta.index_get_key to p so that p[i] uses an array-specific referencing operation, and it associates statinfo_meta.index_set_key to p so that p[i] = n uses an array-specific assignment operation.
statinfo_meta.append_key: Names a form to specialize the ++ operator for appending maps, lists, and similar values. For example, p :: Array associates statinfo_meta.append_key to p so that p ++ q uses an array-specific appending operation.
See Static Information for additional predefined keys.
Static information from different sources sometimes needs to be merged, and merging takes one of two forms: and mode or or mode. Most obviously, and mode is used when combining static information from annotations via the && operator, and or mode for combining with ||. For example, satisfying the annotation List.of(Int) || List.of(String) implies the static information of List, at least. Another example of and mode is in def bind = expr, where both bind and expr can supply static information about the binding, and both sets of information will apply to uses of the defined names. Another example of or mode isin if test_expr | then_expr | else_expr, where the overall if form has static information thatis common to both then_expr and else_expr. When a new static-information key is defined with statinfo.key, then compile-time merging functions are provided in ~and and ~or clauses.