• No results found

Computing intermediate flow data

5.5 Flow type inference

5.5.3 Computing intermediate flow data

Now that we have a way of getting vertexes that expressions depend upon, we turn to constructing the static production flow graphs. Recall that there are three pieces

5.5. Flow type inference

FlowDef ::=

(hostProd) | Nonterminal Production (extSyn) | Nonterminal Attribute

(defaultEq) | Nonterminal Attribute [FlowVertex]

(synEq) | Production Attribute [FlowVertex] Suspect (inhEq) | Production ChildName Attribute [FlowVertex] (fwdEq) | Production [FlowVertex] Suspect

(fwdInh) | Production Attribute [FlowVertex]

(localEq) | Production LocalName Type [FlowVertex] (localInh) | Production LocalName Attribute [FlowVertex]

(anonEq) | Production Id Type [FlowVertex] (anonInh) | Production Id Attribute [FlowVertex]

(patternVar) | Production Production VertexType [(ChildName, Type, Id)] Figure 5.12: Definition of the FlowDef data type as a pseudo-grammar.

we need to compute for each production: a set of edges, a set of stitch points, and a set of suspect edges. Instead of directly computing these graphs from Ag trees, however, we will first compute an intermediate representation. This representation is useful because we need to use it not only for constructing static production flow graphs, but also later on to discover missing equations.

Let us begin by defining the intermediate data structure we will be using. In leiu of using some new notation, we present this definition as a grammar in figure 5.12, with the addition of giving names to each of the productions. We can immediately see two broad classes of information: per-nonterminal and per-production. We represent a set of flow vertexes in the data structure as [FlowVertex]. The components are given descriptive names: Nonterminal, Production, Attribute, ChildName, LocalName, and Id (for “anonymous” names.)

The first two per-nonterminal FlowDefs are intended simply as flags. For the first, if hostProd(nt, prod) is in a set of FlowDefs, then prod is a non-forwarding production exported by its nonterminal. Thus, we can discover from a set of FlowDefs

5.5. Flow type inference

the complete set of productions for which equations must exist (or pattern matching expressions must cover.) If extSyn(nt, attr) is present, then attr is a synthesized attribute with an occurrence that is not exported by its nonterminal, and is thus an “extension attribute.” This serves as an indicator of which attributes must have a flow type that is a super set of the forwarding one.

Next, we have a series of FlowDefs corresponding to the different kinds of equa- tions that can appear. The defaultEq is unique in that it associates an attribute and a nonterminal, rather than a specific production, with a set of dependencies. For the rest of the equation FlowDefs, things are fairly straightforward: we associate a production and enough information to construct a source vertex, with the set of flow vertexes it depends upon. There are a couple subtleties, however. The synEq and fwdEq constructors are the only ones that can be marked suspect, indicating all these edges are to be introduced as suspect, rather than normal, edges. (“Suspect” in the pseudo-grammar is simply a boolean flag.) We also associate, exclusive to localEq and anonEq, the type of the nonterminal they construct. This is a bit of an imple- mentation detail: later on when we need types, we’ll have the production’s signature available which gives types for the LHS, children, and forward.

The final FlowDef is simply an indicator of the stitch points that should be intro- duced as a result of pattern matching. We need several pieces of information. First, we need the target production that is being matched against, which is why Production appears twice: the first is the production this FlowDef (and its equation) originated from, the second is the production we’ll be projecting through. Next, we need the vertex type of the scrutinee that we’re matching against. Finally, we need several bits of information about the pattern variables we’re extracting. The ChildName and Type are from the target production signature, and the Id is the information

5.5. Flow type inference

needed to construct the vertex type of the pattern variable. Strictly speaking, we’re wandering a bit into implementation details here. This list could just contain Ids; however, it simplifies the implementation to include the additional information, and it more easily deals with the cases where some children are ignored in the pattern using underscores.

Next, in figure 5.13 we give the computationF (Ag) : [FlowDef]. To simplify the presentation, we often apply this to sets of declarations or equations, likeF (D), the implication being the results are appended together. Some cases are missing, where the implementation is trivial. For declarations and equations, these trivial cases produce no FlowDefs. For expressions, these trivial cases do nothing but descend into subexpressions.

Note that the function applies to nearly all the nonterminals of Ag: declarations and equations, of course, but also expressions, sometimes having additional context parameters for nonterminals other than declarations. For completeness, we also note the cases where orphaned declaration errors would be raised. To do so, we use the previously discussed exports relation, and also using this to indicate the module being analyzed.

5.5. Flo w typ e inference F(attribute a < T > occurs on n < v > ;)=     

(orphaned) if¬exports({n, a}, this) [extSyn(n, a)] if a∈ S and ¬exports(n, this)

[] otherwise F ( production xp xl:: n < T > ::= xr:: T { Q } ) =     

(orphaned) if¬exports(n, this) and fwdEq(xp, ) /∈ R

[hostP rod(n, xp)] ++ R if exports(n, this) and fwdEq(xp, ) /∈ R

R otherwise where R =F(Q, xp, n ) F(aspect xp xl:: n < T > ::= xr:: T { Q } ) =F(Q, xp, n ) F(default xl:: n < v > ::= { Q } ) =F(Q, default, n) F (x . a = E ; , p, n) =               

(orphaned) if¬exports({p, o}, this) where o is occurs for a on x’s type [synEq(p, a,D(E), exports({n, o}, this))] ++ F (E, p) if a ∈ S and x is LHS [inhEq(p, x, a,D(E))] ++ F (E, p) if a∈ I and x is RHS [defaultEq(n, a,D(E))] ++ F (E, p) if p = default

[localInh(p, x, a,D(E))] ++ F (E, p) if a∈ I and x is local F(forwards to E { A } ; , p, n)= [fwdEq(p,D(E), exports(n, this))] ++ F (E, p) ++ F(A, p, fwd)

F (local x :: T = E ; , p, n) = [localEq(p, x, T, D(E))] ++ F (E, p)

F(decorate E with { A }, p)= [anonEq(p, ν, T,D(E))] ++ F (E, p) ++ F(A, p, anon(ν)) where E :: T F(case E of P -> Ep, p ) = R ++F (E, p) ++ F(Ep, p ) where R = { F(P , p, v) ifD(E) = hv, i

F(P , p, ν)++[anonEq(p, ν, T, [])] otherwise (where E :: Decorated T) F (xp(x), p, vs) = [patternV ar(p, xp, vs, x :: T7→ ν)]

F (a = E, p, ty) = F (E, p) ++ {

[fwdInh(p, a,D(E))] if ty = fwd [anonInh(p, x, a,D(E))] if ty = anon(x)

5.5. Flow type inference

For declarations (D), we can see all cases are fairly simple. For attribute occur- rences, we may find an orphaned occurrence, or report an occurrence as being part of an “extension” (and thus have a minimum flow type.) For original production declarations, we may report it as orphaned or as being a legally non-forwarding “host language” production. We otherwise simply descend into the equations.

When checking equations (Q), we include some extra context, which is the produc- tion and LHS nonterminal for that production. (For default productions, we simply report default as a placeholder for the production. We once again see the possibility of orphaned equations, and note that we use o to refer to the module the attribute occurrence appears in. Beyond that, we just determine exactly what kind of equation it is, and report the correct FlowDef. Here, we don’t directly handle certain already erroneous cases. For example, we would have already raised errors for trying to define an inherited attribute for the LHS, or a forward equation in an aspect production.

Notice, for synEq and fwdEq, we finally see our determination for whether these equations should be considered suspect. These rules follow the same logic as orphaned declarations or equations. If a synthesized equation appears in a module exported by the nonterminal or the attribute occurrence, then it is non-suspect. Anyone accessing that attribute must have imported the occurrence and that nonterminal’s module, and so must be aware of this equation’s influence on flow types. Likewise, a forwarding equation is only non-suspect if it is exported by the production’s nonterminal.

Next, we see the only two cases for expressions that contribute FlowDefs (followed by two cases for syntax within these expressions.) As extra context, expressions need only know what production they appear within. Both these expressions potentially make use of anonymous identifiers (once again denoted ν) associated with the node in the tree. Decorate expressions always do so, providing this id to the anonEq and

5.5. Flow type inference

down to the inherited equations list as well. Pattern matching expressions will use the scrutinee’s vertex type, unless there isn’t one, in which case a new anonymous vertex type is created as a proxy. The purpose of this is to simplify how we handle pattern variables, since we can now always assume there is a vertex type for the scrutinee. We do not indicate any dependencies for this new vertex, it’s purpose is only to accumulate dependencies for our later check for completeness.

For patterns, we include not only the production we’re within, but also the vertex type of the scrutinee (vs) as extra context. When reporting the projection stitch point

information, the anonymous identifier (ν) is associated with each pattern variable, not the pattern as a whole (that is, each pattern variable has its own identity.) For inherited equations, we include as context, in addition to the production, what we’re supply inherited equations to. This syntax can appear within decorate expressions or the forwarding equation, and so we emit two different kinds of equations, depending. For the expressions not listed, this function simply proceeds to accumulate the FlowDefs from its subexpressions.