MELT / Silver / Language Reference / Declarations / Flow type declarations

Flow type declarations

Quick examples:

flowtype Expr =
  decorate {env, returnType},
  forward {env},
  isLValue {decorate};
  
flowtype pp {} on Expr, Exprs;

Syntax

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...;

Semantics

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};

FAQ

Why can I use the decorate shorthand, but not forward?

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?

In the attribute-oriented syntax, why can’t I vary the inherited set?

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.