melt-umn / silver

An attribute grammar-based programming language for composable language extensions
http://melt.cs.umn.edu/silver/
GNU Lesser General Public License v3.0
58 stars 7 forks source link

Global propagation for non-visible productions #357

Open ericvanwyk opened 4 years ago

ericvanwyk commented 4 years ago

The docs for this global propagation say "we can instead write propagate attr1, attr2, ... on NT1, NT2, ...; This generates an aspect production for all known non-forwarding productions of these nonterminals with propagate attr1, attr2, ...; in the body."

Is this correct? I thought one wrote these propagate attr1... statements in a production body if there wasn't a global propagation declaration.

Also, how does "known ... productions" work with language extensions? Can an extension write propagate attr1 on NT1 if both attr1 and NT are declared in the host language and we want this attribute to be propagated on all extension introduced productions? I think not since in and extension this would "know" about the host language productions as well. But it seems unfortunate that this global propagation can only work on the host language.

I'm not sure about only doing this for non-forwarding productions.

krame505 commented 4 years ago

Sorry, that was poorly worded. The aspect productions that we generate have propagate attr1, attr2, ...; in their bodies.

The desired behavior for global propagate is to only propagate on non-forwarding productions - if you really do want to propagate on a forwarding production, then you should specify this with an explicit propagate on the production. Since the MWDA means all extensions productions on host nonterminals must be forward*, this isn't really an issue.

*except for closed nonterminals and optional modifications, which are rare enough that having to explicitly propagate on their productions isn't too big of a deal (and doing so is probably less confusing anyway.)

ericvanwyk commented 4 years ago

"The desired behavior for global propagate is ..." - why? I understand that one can add propagate attr; in the body. But why do you believe that this is the desired behavior. It may be - what is the justification for this?

What about my other question about "known" productions in an extension?

ericvanwyk commented 4 years ago

It seems that a "include forwarding productions" clause, or "exclude forwarding productions" clause, would be a way to be explicit about the behavior one wants. It is then a question of which one is the default.

krame505 commented 4 years ago

Non-interference dictates that equations on forwarding productions should somehow be equivalent to the value obtained from the forward. Some amount of thought should be given to every case where we wish to define an attribute on a forwarding production; thus is dangerous to make a generalization about the behavior of an attribute on forwarding productions in the same way as for non-forwarding productions. Every such overriding equation should be accompanied by a comment explaining why it is necessary and safe, IMO.

While there may be some cases where the desired behavior is actually identical on all productions regardless of forwarding, this is precisely where reflection is useful. This is the same situation we discuss in the reflection paper with the substituted attribute: tasks where we wish to generally propagate an attribute on all productions (including forwarding ones) are fundamentally unsafe for several reasons and probably shouldn't be done with attributes.

An "include forwarding productions" clause would probably also be confusing, as it would only propagate for the known forwarding productions, and there wouldn't be any flow errors if an extension writer forgot to propagate for the forwarding productions introduced by there extension.

As to your second question, this would be an issue for propagating globally on forwarding productions. Fixing this would require some annoying changes to the environment so we could tell whether an equation already exists without running the flow analysis. But since I don't think global propagate for forwarding equations makes sense, this wouldn't an issue.

Saying "global propagation can only work on the host language" isn't really accurate, either - an extension attribute can be propagated by an extension on the host language.

ericvanwyk commented 4 years ago

I think there two parts to this.

First, I agree with your comments about non-interference and this is a fine reason for doing things as you suggest. But I wouldn't quite count this as a resolved issue. I'm hesitant to tie Silver features too closely to the notion of non-interference since, in theory at least, one can use Silver in a way that isn't so tied to our notions of extensible languages. But for now I'm happy to proceed.

The second issue is related to this issue of "known" productions. What you have now seems to work because of the fact that you don't want to add propagating equations on forwarding productions in an extension. I can imagine splitting a language specification over a few grammars just to keep things neat and tidy and defining non-forwarding productions in each - for example a grammar for integer expressions and one for boolean expressions. One grammar, say the one for boolean expressions, may define the expression nonterminal Expr used on the left hand side of all of these productions. Now one might like to say propagate attr on Expr to globally propagate attr on expression in the grammar for integer expressions too. But with the suggested implementation this is not possible. I think you are saying this in your comment above.

I'm happy enough to leave this as an open issue if we can at least agree on what the desired, or perhaps even, reasonable alternative meaning of the global propagate declaration in the suggested integer expression grammar above should or could mean.

Is this alternative interpretation not a desirable or at least a reasonable one?

krame505 commented 4 years ago

Thanks, I think I understand your point about this "know" production issue. This is essentially the situation we have now in the Silver compiler, with modifications - however these typically only have 1 or 2 non-forwarding host productions each, so a global propagate wouldn't be so useful here in practice.

I agree that some global form of propagate would be useful in "modification" grammars containing a large number of non-forwarding host productions. However just making propagate ignore productions that already have an equation raises some annoying issues (e.g what if someone propagates an attribute twice on the same nonterminal in the same grammar? Is this an error?) and is also hard to implement.

Maybe a better alternative would be to offer an alternate form of global propagate that only propagates on the productions that are exported by the current grammar. I don't think this is a particularly critical problem though, so I'm also happy to leave this be for now.

Btw it seems that Github offers an option to transfer issues between repositories. So I'm going to move these to the Silver repository where they probably belong.