Next: TypequDepend, Up: RootType
Consider the following Mystery program:
VAR Length: Measurement;
TYPE Measurement = Inches;
TYPE Inches = INTEGER;
BEGIN Length = 3; PRINT Length + 7 END;
This program is correct according to the semantics we have postulated for Mystery (see Overview):
Type appearing on the
right-hand side of a type definition.
Thus both of the type definitions are valid.
The type analysis of each of the two occurrences of Length in the
last line of the program is described by the following specifications
discussed earlier:
SYMBOL ExpIdUse INHERITS TypedUseId, ChkTypedUseId END;
RULE: Expr ::= ExpIdUse
COMPUTE PrimaryContext(Expr,ExpIdUse.Type);
END;
The value of ExpIdUse.Type should be intType, the known
definition table key created for the language-defined integer type.
Recall that intType was associated with the Mystery keyword
INTEGER by the following specification
(see Establishing language-defined types):
RULE: Type ::= 'INTEGER'
COMPUTE Type.Type=intType;
END;
The problem is to make the intType value of the Type.Type
attribute in this context the value of the ExpIdUse.Type attribute
in the context quoted above.
A human has no trouble seeing how this problem could be solved:
TypIdDef.Type attribute of the
occurrence of Inches in the third line of the program to
intType.
Inches entity could be set from the
value of the TypIdDef.Type attribute in that context.
TypIdUse.Type attribute of
the occurrence of Inches in the second line of the program.
Type.Type
attribute in that context the value of the TypIdUse.Type attribute.
Type.Type attribute
in the variable definition context of the first line of the program
becoming intType.
Length entity is set in the context of
the first line of the program and used to make intType the value
of the ExpIdUse.Type attributes in the two contexts of the last line.
Unfortunately, this solution is based on the human's ability to see the dependence among the type identifiers and process the lines of the program in an order determined by that dependence. One cannot, for example, blindly process the lines in the order in which they were written.
The dependence among the lines in our example is a result of our use of the
known key intType as the value of a property of the type identifier
entities.
This strategy is actually an example of a premature evaluation:
There is no need to know the key representing the type of
Length until the ExpIdUse.Type attribute is evaluated.
We can avoid the constraint on the order of rule processing by a
“lazy evaluation” strategy in which we use properties of the type
identifier entities to establish a means for determining the value of the
ExpIdUse.Type attribute rather than establishing the value itself.
There are three possible Type contexts in Mystery: a keyword, a
type denotation, and a type identifier.
In the first two, we can set the value of the Type.Type attribute to
the definition table key for the type itself.
In the third, however, the only information that we are guaranteed to have
is the definition table key for the type identifier.
However, this information is sufficient to find the definition table key
for the type once all of the type identifiers have been defined.
Thus we can simply set the value of the Type.Type attribute to the
definition table key for the type identifier itself in this context.
The computation provided by the Typing module for the
TypeDefDefId context sets a property of the type identifier entity
to the value of the TypeDefDefId.Type attribute
(see Defining and using type identifiers).
Effectively, this computation creates a linear list of type identifier
entities ending in a type entity.
In our example, the value of this property of the identifier
Length's definition table key would be the definition table key of
the identifier Measurement.
The value of its property would be the definition table key of the
identifier Inches, whose property would be intType.
When all of the entities corresponding to type identifiers have this
property set, the definition table key for a type should be the last
element of each list.
The Typing module uses an instance of the Defer module
(see Deferred Property Association)
to provide this computation for the TypeDefUseId context.
There is no guarantee, of course, that the last element of the list is actually a type. For example, consider the following incorrect Mystery program:
VAR Length: Measurement;
TYPE Measurement = Inches;
VAR Inches: INTEGER;
BEGIN Length = 3; PRINT Length + 7 END;
Here the last element of the list beginning at Measurement would be
Inches, a variable identifier.
The ChkTypeDefUseId role checks the IsType property
(see Typed Entities)
of the key that is the last element of the list to report errors of this
kind.
The Typing module establishes RootType.GotType
as the post-condition for setting all Type.Type properties and linkages
among type identifiers.