Type Analysis
A typed entity is a named program component, one of whose properties
is a type.
Variables, formal parameters, and fields are the most common typed
entities; functions are also typed entities in some languages
(see Functions as typed entities).
When an identifier is used to represent a typed entity,
the type specified by a defining occurrence of that identifier
must be made available at each applied occurrence.
This is accomplished through the use of a DefTableKey -valued
property of the definition table key characterizing the typed entity.
The Typing module exports computational roles to
implement the definition and use of typed entities:
TypedDefinition
- The computational role inherited by a grammar symbol that represents
a definition of one or more typed entities having the same type.
TypedDefId
- The computational role inherited by a grammar symbol that represents
a defining occurrence of an identifier for a typed entity.
TypedUseId
- The computational role inherited by a grammar symbol that represents
an applied occurrence of an identifier for a typed entity.
The Typing module is instantiated by
$/Type/Typing.gnrc +referto=`prefix' :inst
`prefix'Key (or simply Key if the referto
parameter is missing) must be the name of an attribute of every
grammar symbol inheriting the TypedDefId or TypedUseId role.
The value of that attribute must be the definition table key bound to the
symbol during name analysis
(see Name analysis according to scope rules of Specification Module Library).
A typical local variable declaration from Java or C specifies a type and a
list of variable names:
int a, b, c;
The entire declaration plays the role of a TypedDefinition ;
each of a , b , and c plays the role of a
TypedDefId .
The value of the TypedDefinition.Type attribute must be set
by a user computation to the definition table key of the type.
No other user computations are needed because
default computations provided by the Typing module in descendant
TypedDefId constructs will access the TypedDefinition.Type
attribute, setting the appropriate property of the definition table key
characterizing the typed entity.
A Java or C compiler might use the following specification to describe a
variable declaration:
SYMBOL VrblDecl INHERITS TypedDefinition END;
SYMBOL VarIdDef INHERITS TypedDefId END;
RULE: VrblDecl ::= Type VarIdDefs ';' COMPUTE
VrblDecl.Type=Type.Type;
END;
RULE: VarIdDefs LISTOF VarIdDef END;
TypedUseId
is an applied occurrence of an identifier representing a typed entity.
A Typing module computation sets the value of the TypedUseId.Type
attribute to the definition table key representing the entity's type.
If ExpIdUse represented an applied occurrence of a variable or
parameter identifier in the abstract syntax tree, the Typing module
will provide a value for ExpIdUse.Type if the following line
appears in the specification:
SYMBOL ExpIdUse INHERITS TypedUseId END;
The Typing module guarantees that every TypedUseId.Type
attribute depends on all of the type analysis computations
(see Dependences for typed entities).
In other words, any computation accessing TypedUseId.Type is
guaranteed to take place after all type analysis computations have been
completed.
This dependence can be used to guarantee the availability of information
characterizing the typed entity that is ancillary to type analysis.
The operation that sets the Type property of the definition table key
characterizing the typed entity depends on the void attribute
TypedDefId.GotProp .
TypedDefId.GotProp is set by an accumulating computation that can
be augmented by an upper-context accumulating computation of the symbol
inheriting TypedDefId or by an accumulating computation in a rule
having the symbol inheriting TypedDefId on the right-hand side.
The Typing module will then guarantee that all such a computations
have been carried out before any access to TypedUseId.Type is allowed.
Any such computations must, however, be independent of all results of type
analysis.
Pascal's distinction between variable and value parameters is a typical
example of information ancillary to type analysis that must be conveyed
from defining to applied occurrences of typed entities:
ATTR IsVarParam: int;
SYMBOL FormalParamSect INHERITS TypedDefinition COMPUTE
SYNT.IsVarParam=0;
END;
RULE: FormalParamSect ::= 'var' Formals ':' Type COMPUTE
FormalParamSect.IsVarParam=1;
END;
SYMBOL FormalIdDef INHERITS TypedIdDef COMPUTE
INH.GotProp+=
ResetIsVarParam(THIS.Key,INCLUDING FormalParamSect.IsVarParam);
END;
SYMBOL ExpIdUse INHERITS TypedUseId COMPUTE
SYNT.IsVarParam=GetIsVarParam(THIS.Key,0) <- THIS.Type;
END;
This computation assumes that an integer-valued property IsVarParam
has been defined.
It is set by a computation in the upper context of FormalIdDef that
augments the default computation of the void attribute
TypedIdDef.GotProp , and queried by a symbol computation in the lower
context of ExpIdUse .
The latter computation depends on ExpIdUse.Type , so the
Typing module guarantees that the property value has been set for
every formal parameter before it is queried.
FormalParamSect.IsVarParam is an integer valued attribute, distinct
from the IsVarParam property, set by a symbol computation in the
lower context of FormalParamSect .
That symbol computation is overridden in the rule representing
a declaration of a variable parameter.
Note that a particular instance of symbol ExpIdUse in the tree does
not necessarily represent an applied occurrence of a formal parameter.
(It might represent an applied occurrence of a variable identifier, for
example.)
Thus the IsVarParam property might not be set; the query will return
the default value 0 in that case.
The overall effect of these computations is therefore to set the value of
ExpIdUse.IsVarParam to 1 if and only if that instance of
ExpIdUse represents an applied occurrence of a variable parameter.
|