Next: TypeProp, Previous: Overloading, Up: Top

Most language definitions allow a user to supply operands of one type
to an operator requiring operands of another under certain circumstances.
For example, it would be reasonable for the extended version of Mystery
(see Overloaded Indications and Procedures)
to allow an addition with one integer and one real operand.
In that case, analysis computation would assume a coercion operator
to convert the value of the integer operand to a real value.
The `rAddOpr`

would then be applied to the result of the coercion and
the original real operand.

The `Expression`

module uses applicable coercions automatically,
provided that one or more coercion operators have been defined.
Like normal operators, the language-defined coercions can be specified in
the file whose name is the `referto`

parameter of the `PreDefOp`

module
(see Language-Defined Operators).

`PreDefCvt(``

opr`',``

sig`')`

, specifies a coercion:

- `
`opr`' - The known definition table key representing the name of the coercion
operator.
- `
`sig`' - The signature of the specified coercion operator (which must have exactly one operand).

`PreDefCvt`

and `PreDefOpr`

(see Relating operators to indications)
invocations with the same ``opr`' values are not allowed.

A coercion from integer to real for the extended Mystery can be specified by:

PreDefCvt(iTor, (intType):realType);

The known key `iTor`

is defined by the module.
No further specification is necessary.

A coercion defines an edge of the coercion graph, a directed graph
whose nodes correspond to types used in the program.
If the coercion graph contains cycles, then it is difficult to describe the
semantics of an expression.
For example, suppose that we defined a coercion from real values to integer
values in addition to `iTor`

, creating a cycle in the coercion graph.
Given that cycle, what is the effect of the following expression?

1.2 + 3

The extended Mystery has only two operators for which `PlusInd`

is the indication: `iAddOp`

and `rAddOp`

.
Should we coerce 1.2 to an integer value and use `iAddOp`

,
or coerce 3 to a real value and use `rAddOp`

?

Of course we could define the language in such a way that this decision is unambiguous, and guarantee the appropriate coercions by defining them with appropriate costs (see Overload resolution), but the definition would be more complex because of the cycle. Thus we recommend that the coercion graph not contain cycles.

A cast context is an expression context in which a specific type is required. For example, consider the extended Mystery program:

VAR i: INTEGER; VAR a: REAL; BEGIN i := 1; i := 2.3; a := 4; a := 5.6 END;

In each assignment, the type of the left-hand side determines the type that must be yielded by the right-hand side (see Values).

`CastContext(``

type`',``

rator`',``

expr`')`

is used to provide the necessary type computations:
If a result of type ``type`' cannot be obtained directly
from the tree rooted in ``expr`',
a cast operator can be selected from those overloading
the indication ``rator`'.
Argument ``type`' is a definition table key, ``rator`' is a grammar
symbol playing the `OperatorSymbol`

role, and ``expr`' is a grammar
symbol playing the `ExpressionSymbol`

role.

Here is the definition of assignment for extended Mystery:

RULE: Stmt ::= Expr ':=' Expr COMPUTE CastContext(Expr[1].Type,,Expr[2]); Indication(castInd); ChkRator; END;

Consider how the type analysis would proceed for each of the assignments in our extended Mystery program:

`i := 1`

- The right-hand side delivers the desired type, so no conversion is
required.
`i := 2.3`

- The right-hand side delivers a real value, which cannot be coerced to the
desired integer type.
Thus an operator identified by the
`castInd`

indication must be available to provide the conversion. `a := 4`

- The right-hand side delivers the desired type, due to a coercion operator.
Thus no additional conversion is required.
`a := 5.6`

- The right-hand side delivers the desired type, so no conversion is required.

The cast operator might be defined by:

PreDefOpr(castInd, rToi, (realType):intType)

Many languages also provide explicit cast contexts, which break the normal type relationship between two adjacent expression nodes (see Values). Here is an example, using C syntax:

RULE: Expr ::= '(' Type ')' Expr COMPUTE PrimaryContext(Expr[1],Type.Type); CastContext(Type.Type,,Expr[2]); Indication(castInd); ChkRator; END;

The type of `Expr[1]`

is known to be of the type `Type`

,
and therefore `Expr[1]`

acts as a leaf of the expression
tree containing it.
`Expr[2]`

, on the other hand, acts as the root of an expression tree:
the type of value it should produce is known.