Flow type declarations
Quick examples:
flowtype Expr =
decorate {env, returnType},
forward {env},
isLValue {decorate};
flowtype pp {} on Expr, Exprs;
Nonterminal-oriented (generally preferred syntax):
flowtype Nonterminal = synthesized attribute { inherited attributes... }, ...;
or attribute-oriented (generally used by extensions introducing an attribute on the host language):
flowtype synthesized attribute { inherited attributes... } on Nonterminals...;
A flow type indicates what set of inherited attributes are ultimately usable by a synthesized attribute equation.
This information only has relevance to the modular well-definedness analysis.
This both informs users what inherited attributes they must supply, and also limits attribute equations to using no more than the specified set.
Without a flowtype
declaration, the flow types are simply inferred.
There are two special values that may be used in place of a synthesized attribute in the nonterminal-oriented syntax.
First, you can use forward
to specify a “flow type” for the forwarding equation (meaning essentially the same thing as for a synthesized attribute: what inherited attributes may be used in defining a forwards to
clause on this nonterminal).
This is especially useful in host languages that might not have any forwarding productions to help infer the correct value that will be imposed on extensions.
flowtype Expr = forward {env};
Second, you can use decorate
to specify a special “blessed set” of attributes that are expected to be present/necessary for references (Decorated
nonterminals).
Strictly speaking, this isn’t necessarily a “flow type” but we just use this same syntax, and it mostly has the same meaning.
To take a reference to a decorated tree, this set must be supplied, and when accessing from a reference, this set are the only inherited attributes presumed to be supplied.
flowtype Expr = decorate {env, returnType};
Finally, there is one last special case.
In practice, it is frequently useful to be able to set the decorate
“flow type” and re-use that value for many synthesized attributes.
(This is a result of the “infectious” nature of using references withing a tree.
Once you have a production with a reference as a child, quite a lot of attributes start to have identical flow types to decorate
.)
To support making these easier to write and maintain, we allow decorate
to be used in place of the name of an inherited attribute, _if an explicit flow type is already given for decorate
.
This is illustrated in the example above with isLValue
:
flowtype Expr = decorate {env, returnType}, isLValue {decorate};
We just haven’t encountered the need for it yet.
Usually, it’s the host language that specifies explicit flow types, and extensions generally get away with flow type inference.
It’s extensions that would probably most benefit from forward
. Probably?
The most common case is to use the same flowtype for an attribute on a lot of nonterminals. If you need to vary it, just write several flowtype declarations in sequence. In such situations, you might even want to consider writing a comment explaining why one nonterminal or another deviates from the usual.