next up previous
Next: Typed identifiers Up: Types and type identifiers Previous: Class and interface types


Array types

Array types cannot be declared or named; every use of an array type is represented by its denotation. Two array type denotations are equivalent if they have the same element type and the same number of dimensions. This is a restricted form of structural equivalence, which requires that the StructEquiv module be instantiated:

Instantiate required modules[26]:
$/Type/StructEquiv.fw
This macro is defined in definitions 15, 26, 38, and 44.
This macro is invoked in definition 1.

StructEquiv defines a partition on the set of types such that types that could be equivalent on the basis of their construction rule lie in the same block of the partition. After all type denotations have been examined, StructEquiv refines the partition on the basis of the component types of each type. The blocks of the refined partitions are the type equivalence classes.

We therefore use AddTypeToBlock to assign each array denotation to the ArrayTypes block with the element type as a singleton component type list:

Property definitions[27]:
ArrayTypes;
This macro is defined in definitions 18, 24, 27, and 29.
This macro is invoked in definition 3.

Array types[28]:
TREE SYMBOL ArrayType: ElementType: DefTableKey;

TREE SYMBOL ArrayType INHERITS TypeDenotation COMPUTE
  SYNT.GotType=
    AddTypeToBlock(
      THIS.Type,
      ArrayTypes,
      SingleDefTableKeyList(THIS.ElementType));
END;

RULE: ArrayType ::= PrimitiveType '[' ']' COMPUTE
  ArrayType.ElementType=PrimitiveType.Type;
END;

RULE: ArrayType ::= Name $pTypeName '[' ']' COMPUTE
  ArrayType.ElementType=pTypeName.Type;
END;

RULE: ArrayType ::= ArrayType '[' ']' COMPUTE
  ArrayType[1].ElementType=ArrayType[2].Type;
END;
This macro is defined in definitions 28, 30, 31, 32, and 33.
This macro is invoked in definition 14.

Each array type has an associated set of operators that must be added to the operator database. Those operators should only be instantiated once for each unique array type. The Ops property of the final array type is set to indicate that the operators for that array type have been entered into the database.

Property definitions[29]:
Ops: int [Has, KReset];
This macro is defined in definitions 18, 24, 27, and 29.
This macro is invoked in definition 3.

Array types[30]:
TREE SYMBOL ArrayType INHERITS OperatorDefs COMPUTE
  SYNT.GotOper=
    IF(NOT(HasOps(THIS.Type)),
      InstClass1(
        arrayOps,
        KResetOps(FinalType(THIS.Type),1),
        THIS.ElementType));
END;
This macro is defined in definitions 28, 30, 31, 32, and 33.
This macro is invoked in definition 14.

Every array access is also an array type denotation, but with some subscripts specified. The processing of these denotations is basically the same as the processing specified above. The only difference is that there is no direct access to the element type. We therefore use a chain, started in the context of the array access, to carry the element type from one dimension to the next:

Array types[31]:
CHAIN ArrTyp: DefTableKey;

SYMBOL Dimension INHERITS TypeDenotation, OperatorDefs COMPUTE
  SYNT.GotType=
    AddTypeToBlock(THIS.Type,ArrayTypes,SingleDefTableKeyList(THIS.ArrTyp));
  SYNT.GotOper=
    IF(NOT(HasOps(THIS.Type)),
      InstClass1(
        arrayOps,
        KResetOps(FinalType(THIS.Type),1),
        THIS.ArrTyp));
  THIS.ArrTyp=THIS.Type;
END;
This macro is defined in definitions 28, 30, 31, 32, and 33.
This macro is invoked in definition 14.

As discussed in Section 5.3, Java allows identifiers to be declared with trailing dimensions. This requires operations like those above, associated with the particular context in which the trailing dimensions occur. If there is no trailing dimension, do nothing:

Array types[32]:
TREE SYMBOL VariableDeclaratorId INHERITS TypeDenotation, OperatorDefs
COMPUTE
  SYNT.GotType="yes";
  SYNT.GotOper="yes";
END;

RULE: VariableDeclaratorId ::= VariableDeclaratorId '[' ']' COMPUTE
  VariableDeclaratorId[1].GotType=
    AddTypeToBlock(
      VariableDeclaratorId[1].Type,
      ArrayTypes,
      SingleDefTableKeyList(
        INCLUDING (VariableDeclaratorId.Type,TypedDefinition.Type)));
  VariableDeclaratorId[1].GotOper=
    IF(NOT(HasOps(VariableDeclaratorId[1].Type)),
      InstClass1(
        arrayOps,
        KResetOps(FinalType(VariableDeclaratorId[1].Type),1),
        INCLUDING (VariableDeclaratorId.Type,TypedDefinition.Type)));
END;
This macro is defined in definitions 28, 30, 31, 32, and 33.
This macro is invoked in definition 14.

For compatibility with older versions of the Java platform, a declaration form for a method that returns an array is allowed to place (some or all of) the empty bracket pairs that form the declaration of the array type after the parameter list. By now, the operations should be familiar:

Array types[33]:
TREE SYMBOL MethodDeclarator INHERITS TypeDenotation, OperatorDefs
COMPUTE
  SYNT.GotType="yes";
  SYNT.GotOper="yes";
END;

RULE: MethodDeclarator ::= MethodDeclarator '[' ']' COMPUTE
  MethodDeclarator[1].GotType=
    AddTypeToBlock(
      MethodDeclarator[1].Type,
      ArrayTypes,
      SingleDefTableKeyList(
        INCLUDING (MethodDeclarator.Type,MethodHeader.Type)));
  MethodDeclarator[1].GotOper=
    IF(NOT(HasOps(MethodDeclarator[1].Type)),
      InstClass1(
        arrayOps,
        KResetOps(FinalType(MethodDeclarator[1].Type),1),
        INCLUDING (MethodDeclarator.Type,MethodHeader.Type)));
END;
This macro is defined in definitions 28, 30, 31, 32, and 33.
This macro is invoked in definition 14.

See Section 5.4.2 for the context of this computation.


next up previous
Next: Typed identifiers Up: Types and type identifiers Previous: Class and interface types
2008-09-11