General Information
Tutorials
Reference Manuals
Libraries
Translation Tasks
Tools
Administration
|
Tutorial on Type AnalysisUnion TypesWe introduce union types to our language in order to demonstrate how subtype relations and their coercions are specified. A union type is described by a sequence of type denotations, which constitute the subtypes of the specified union type. A value of one of the subtypes can be coerced to the union type. A value of a union type can be treated as a value of one of the subtypes using a cast operation or a case statement.
Here is an example program that defines and uses a union
variable named UnionExamp[75]== begin var union int, bool end rv; var int j, bool c; rv = 42; rv = true; j = <int> rv; case rv of int t: j = t; bool t: c = t; end end This macro is attached to a product file.
In the
The following productions describe union types, type casts,
and RULE: TypeDenoter ::= UnionType END; RULE: UnionType ::= 'union' UnitedTypes 'end' END; RULE: UnitedTypes LISTOF UnitedType END; RULE: UnitedType ::= TypeDenoter END; RULE: Expression ::= '<' TypeDenoter '>' Expression END; RULE: Statement ::= CaseStmt END; RULE: CaseStmt ::= 'case' Expression 'of' Cases 'end' END; RULE: Cases LISTOF Case END; RULE: Case ::= ObjDecl ':' Statement END; This macro is invoked in definition 88.
The following computations introduce a type denoter for union types
and associate properties for test output to it:
In order to check whether a type is a union type, as required
for example in a case statement, we introduce a property
IsUnionType: int; This macro is invoked in definition 87. Union type denoter[78]== SYMBOL UnionType INHERITS TypeDenotation END; RULE: UnionType ::= 'union' UnitedTypes 'end' COMPUTE .GotTypeProp = ORDER ( ResetIsUnionType (UnionType.Type, 1), ResetTypeName (UnionType.Type, "union..."), ResetTypeLine (UnionType.Type, LINE)); END; RULE: TypeDenoter ::= UnionType COMPUTE TypeDenoter.Type = UnionType.Type; END; This macro is invoked in definition 88.
For the comparison of union types stuctural equivalence is
specified, such that the fact that it is a union type and
the sequence of subtypes are relevant for type equality.
Union type class[79]== UnionClass; This macro is invoked in definition 87.
The Union type equality computation[80]== RULE: UnionType ::= 'union' UnitedTypes 'end' COMPUTE UnionType.GotType += AddTypeToBlock (UnionType.Type, UnionClass, VResetComponentTypes (UnionType.Type, UnitedTypes.OpndTypeList)) <- .GotTypeProp; END; SYMBOL UnitedTypes INHERITS OpndTypeListRoot END; SYMBOL UnitedType INHERITS OpndTypeListElem END; RULE: UnitedType ::= TypeDenoter COMPUTE UnitedType.Type = TypeDenoter.Type; UnitedType.DefTableKeyElem = UnitedType.Type; END; This macro is invoked in definition 88.
Note, that here the order of the subtypes in the type denoter
is relevant for type equality. If that is not desired,
one could for example sort the list of the component types
in a canonical order before using it as an argument of
For each union type we introduce two groups of conversion operators: A widening coercion from each subtype type to the union type, and a down cast from the union type to each subtype. For the latter an indication has to be introduced: Downcast indication[81]== DownCast; UnionWiden; This macro is invoked in definition 87.
As a pair of operators has to be introduced for each subtype,
the context of the subtype denoter is the right place
to do it.
The coercion operator is not created explicitly;
it is only stated that the subtype is Widening coercion computation[82]== SYMBOL UnitedType INHERITS OperatorDefs COMPUTE SYNT.GotOper += ORDER (Coercible (UnionWiden, THIS.Type, INCLUDING UnionType.Type), MonadicOperator (DownCast, NewKey(), INCLUDING UnionType.Type, THIS.Type)); END; This macro is invoked in definition 88.
The context of the down cast construct imposes a requirement on the type of
the operand expression.
Any conversion operator of the Down cast[83]== RULE: Expression ::= '<' TypeDenoter '>' Expression COMPUTE CastContext (Expression[1], , Expression[2], TypeDenoter.Type); Indication (DownCast); END; This macro is invoked in definition 88.
In a Union case statement[84]== SYMBOL CaseStmt: Type: DefTableKey; RULE: CaseStmt ::= 'case' Expression 'of' Cases 'end' COMPUTE CaseStmt.Type = Expression.Type; IF (NOT (GetIsUnionType (Expression.Type, 0)), message (ERROR, "Case expression must have a union type", 0,COORDREF)) <- INCLUDING Program.TypeIsSet; END; This macro is invoked in definition 88.
Each branch of a SYMBOL Case INHERITS RangeScope END; RULE: Case ::= ObjDecl ':' Statement COMPUTE IF (NOT (IsCoercible (ObjDecl.Type, INCLUDING CaseStmt.Type)), message (ERROR, "Must be a subtype of the case expression", 0, COORDREF)) <- INCLUDING Program.GotType; END; This macro is invoked in definition 88.
In other contexts Union CHAIN workaraound[86]== SYMBOL Cases INHERITS OpndTypeListRoot END; This macro is invoked in definition 88. Union.pdl[87]== Is union type[77] Union type class[79] Downcast indication[81] This macro is attached to a product file. Union.lido[88]== Abstract union syntax[76] Union type denoter[78] Union type equality computation[80] Widening coercion computation[82] Down cast[83] Union case[85] Union case statement[84] Union CHAIN workaraound[86] This macro is attached to a product file. Union.con[89]== Concrete union syntax[144] This macro is attached to a product file.
|