Constraints on operators

Many of the subsections of Section 6.3 of the standard describe constraints
on the types of operands that a given operator can have.
This section formalizes those constraints, defining each C operator by an
`INDICATION`.
The constraints are described by a set of `OPER`ators, each with a
specific type signature.
Each `INDICATION` is associated with a comma-separated list of the
`OPER`ators that satisfy the standard's constraints on that C operator.

INDICATION

Subscript_Indication: Subscript_Op, Array_Subscript_Op, IndexString;

This macro is defined in definitions 19, 20, 21, 22, 23, 24, 25, 26, 27, and 28.

This macro is invoked in definition 4.

This macro is invoked in definition 4.

Distinct subscripting operations are defined for each array type and
each pointer type other than `TypeIs_VoidPointer`.
The second operand is specified to be a `TypeIs_unsigned_long`, although
the standard specifies that it has integral type.
Any integral type can be converted to `TypeIs_unsigned_long` by means of
implicit conversions, so this specification is equivalent to that of the
standard.
The main reason for using `TypeIs_unsigned_long` is that OIL does not
permit sets as operand specifications within a class definition, but a
secondary reason is that this approach reduces the total number of
operators in the compiler's database.

INDICATION

Plus_Plus_Indication: Increment_Op, Ptr_Inc_Op;

Minus_Minus_Indication: Decrement_Op, Ptr_Dec_Op;

OPER

Increment_Op, Decrement_Op(TypeIs_Arithmetic): TypeIs_Arithmetic;

This macro is defined in definitions 19, 20, 21, 22, 23, 24, 25, 26, 27, and 28.

This macro is invoked in definition 4.

This macro is invoked in definition 4.

INDICATION

Star_Indication: Ptr_Deref_Op, DerefString;

Amper_Indication: Ptr_Ref_Op;

This macro is defined in definitions 19, 20, 21, 22, 23, 24, 25, 26, 27, and 28.

This macro is invoked in definition 4.

This macro is invoked in definition 4.

INDICATION

Plus_Indication: Plus_Op;

Minus_Indication: Minus_Op;

Tilde_Indication: Bitwise_Not_Op;

Bang_Indication: Logical_Not_Op;

Sizeof_Indication: Sizeof_op;

Cast_Indication: Cast_Op, Cast_IntegraltoPtr, Cast_VoidPtrtoPtr,

Cast_VoidVoid, CScalartoVoid;

SET TypeIs_CastResult = TypeIs_Scalar;

OPER

Plus_Op, Minus_Op(TypeIs_ArithPromoted): TypeIs_ArithPromoted;

Bitwise_Not_Op (TypeIs_IntegralPromoted): TypeIs_IntegralPromoted;

Logical_Not_Op (TypeIs_Scalar): TypeIs_int;

/* FIXME: sizeof is more constrained than this. Also, it has different

semantics in that the operand is not evaluated. May need another kind

of operator.

*/

Sizeof_op (TypeIs_void): TypeIs_int;

Cast_Op (TypeIs_Scalar): TypeIs_CastResult;

Cast_VoidVoid (TypeIs_void): TypeIs_void;

This macro is invoked in definition 4.

By defining `TypeIs_CastResult` as being equal to `TypeIs_Scalar` and
then using these two set identifiers in defining `Cast_Op`, the
specification defines a cast from every element of `TypeIs_Scalar` to
every other element of `TypeIs_Scalar`.
If `Cast_Op` were defined with the signature `(TypeIs_Scalar):
TypeIs_Scalar` then the operand and result would be constrained to be
identical.

The definition of `Cast_Op` allows any pointer type to be cast
to any integral type:
There is an implicit conversion from any pointer type to
`TypeIs_VoidPointer`, which is an element of `TypeIs_Scalar`, and
every integral type is an element of `TypeIs_CastResult`.

Distinct cast operators are defined for each pointer
type other than `TypeIs_VoidPointer` to handle casts from
arbitrary integers and from `TypeIs_VoidPointer` to that pointer type.
The operand of the former is specified to be a `TypeIs_unsigned_long`,
although the standard specifies that it has integral type.
Any integral type can be converted to `TypeIs_unsigned_long` by means of
implicit conversions, so this specification is equivalent to that of the
standard.
The main reason for using `TypeIs_unsigned_long` is that OIL does not
permit sets as operand specifications within a class definition, but a
secondary reason is that this approach reduces the total number of
operators in the compiler's database.

The implicit conversion from any pointer type to `TypeIs_VoidPointer`,
combined with `Cast_VoidPtrtoPtr`, allows any pointer type to be cast to
any other pointer type.
(This includes pointers to function types.)

INDICATION

Star_Indication: MulOp;

Slash_Indication: DivOp;

Percent_Indication: ModOp;

Plus_Indication: AddOp,

Void_Ptr_Add_Op, Void_Ptr_Rev_Add_Op,

Ptr_Add_Op, Ptr_Rev_Add_Op;

Minus_Indication: SubOp,

Void_Ptr_Sub_Op, Ptr_Sub_Op, Ptr_Ptr_Sub_Op;

OPER

MulOp, DivOp,

AddOp, SubOp (TypeIs_Arithmetic, TypeIs_Arithmetic): TypeIs_Arithmetic;

ModOp (TypeIs_Integral, TypeIs_Integral): TypeIs_Integral;

Void_Ptr_Add_Op,

Void_Ptr_Sub_Op(TypeIs_VoidPointer, TypeIs_unsigned_long): TypeIs_VoidPointer;

Void_Ptr_Rev_Add_Op

(TypeIs_unsigned_long, TypeIs_VoidPointer): TypeIs_VoidPointer;

This macro is invoked in definition 4.

INDICATION

Less_Less_Indication: Bit_Shift_Left_Op;

Greater_Greater_Indication: Bit_Shift_Right_Op;

Less_Indication: LessThan_Op, Ptr_LT_Op;

Greater_Indication: Greater_Op, Ptr_GT_Op;

Less_Equal_Indication: LessThan_Equal_Op, Ptr_LTE_Op;

Greater_Equal_Indication: Greater_Equal_Op, Ptr_GTE_Op;

SET TypeIs_ShiftCount = TypeIs_IntegralPromoted;

OPER

Bit_Shift_Right_Op,

Bit_Shift_Left_Op

(TypeIs_IntegralPromoted, TypeIs_ShiftCount): TypeIs_IntegralPromoted;

Greater_Op, LessThan_Op, Greater_Equal_Op,

LessThan_Equal_Op(TypeIs_Scalar, TypeIs_Scalar): TypeIs_int;

This macro is invoked in definition 4.

INDICATION

Equal_Equal_Indication: Equality_Op, Ptr_Eq_Op;

Bang_Equal_Indication: Not_Equal_Op, Ptr_NEq_Op;

OPER

Equality_Op, Not_Equal_Op(TypeIs_Scalar, TypeIs_Scalar): TypeIs_int;

This macro is invoked in definition 4.

INDICATION

Amper_Indication: Bitwise_And_Op;

Caret_Indication: Bitwise_XOr_Op;

Bar_Indication: Bitwise_Or_Op;

Amper_Amper_Indication: Logical_And_Op;

Bar_Bar_Indication: Logical_Or_Op;

Conditional_Indication: Arith_Cond_Op, Void_Cond_Op, Ptr_Cond_Op;

SET TypeIs_RHS_Scalar = TypeIs_Scalar;

OPER

Bitwise_And_Op, Bitwise_XOr_Op,

Bitwise_Or_Op(TypeIs_Integral, TypeIs_Integral): TypeIs_Integral;

Logical_And_Op,

Logical_Or_Op(TypeIs_Scalar, TypeIs_RHS_Scalar): TypeIs_int;

Arith_Cond_Op(TypeIs_Scalar,TypeIs_Arithmetic,TypeIs_Arithmetic): TypeIs_Arithmetic;

Void_Cond_Op (TypeIs_Scalar,TypeIs_Void,TypeIs_Void): TypeIs_Void;

This macro is invoked in definition 4.

FIXME: The standard allows balancing of two compatible struct or union types. The best way to handle this is probably to have a common type that all such types can be coerced to, followed by more stringent testing.

INDICATION

Equal_Indication:

Assign_Op, Ptr_Assign_Op, Enum_Assign_Op,

Struct_Assign_Op, Union_Assign_Op, Ptr_Void_Assign_Op,

Ptr_Void_Void_Assign_Op;

SET TypeIs_RHS_Arithmetic = TypeIs_Arithmetic;

OPER

Assign_Op(TypeIs_Arithmetic, TypeIs_RHS_Arithmetic): TypeIs_Arithmetic;

Ptr_Void_Void_Assign_Op

(TypeIs_VoidPointer, TypeIs_VoidPointer): TypeIs_VoidPointer;

This macro is invoked in definition 4.

INDICATION

Star_Equal_Indication: Mult_Eq_Op;

Slash_Equal_Indication: Div_Eq_Op;

Percent_Equal_Indication: Mod_Eq_Op;

Plus_Equal_Indication: Plus_Eq_Op, Ptr_Plus_Eq_Op;

Minus_Equal_Indication: Minus_Eq_Op, Ptr_Minus_Eq_Op;

Less_Less_Equal_Indication: Bitwise_Shift_Left_Eq_Op;

Greater_Greater_Equal_Indication: Bitwise_Shift_Right_Eq_Op;

Amper_Equal_Indication: Bitwise_And_Eq_Op;

Caret_Equal_Indication: Bitwise_XOr_Eq_Op;

Bar_Equal_Indication: Bitwise_Or_Eq_Op;

SET TypeIs_RHS_Integral = TypeIs_Integral;

OPER

Mult_Eq_Op, Div_Eq_Op, Plus_Eq_Op,

Minus_Eq_Op( TypeIs_Arithmetic, TypeIs_RHS_Arithmetic ) : TypeIs_Arithmetic;

Mod_Eq_Op, Bitwise_Shift_Left_Eq_Op, Bitwise_Shift_Right_Eq_Op,

Bitwise_And_Eq_Op, Bitwise_XOr_Eq_Op,

Bitwise_Or_Eq_Op( TypeIs_Integral, TypeIs_RHS_Integral ) : TypeIs_Integral;

This macro is invoked in definition 4.