}
}
// Now we want to continue with almost the same process as when dealing with a regular switch.
Block switchBlock = new Block();
Object altTag = alt.getFirstAltTag();
// Preserve the behaviour of a switch, i.e. the switch expression will be
// strictly evaluated before falling through to the single default alternate.
// This is really only needed if the switch expression can have a side effect.
boolean isSwitchingOnDC = !alt.isDefaultAlt() && (altTag instanceof DataConstructor);
boolean switchExprEvaluated = false;
Expression.Var switchVar = eSwitch.getSwitchExpr().asVar();
if (switchVar != null) {
switchExprEvaluated = variableContext.isVarPreEvaluated(switchVar.getName());
}
// Only do a local variable if the switch expression is not evaluated or we will
// be extracting member fields from the data constructor resulting from evaluating the switch expression.
LocalVariable caseVar = null;
JavaTypeName caseVarType = (isSwitchingOnDC && alt.hasVars()) ? JavaTypeNames.RTCONS : JavaTypeNames.RTVALUE;
if (!switchExprEvaluated || alt.hasVars()) {
caseVar = new LocalVariable("$case" + nestedCaseLevel, caseVarType);
ExpressionContextPair pair = genS_E(eSwitch.getSwitchExpr(), variableContext);
switchBlock.addStatement(pair.getContextBlock());
JavaExpression caseExpression = pair.getJavaExpression();
if (caseVarType.equals(JavaTypeNames.RTCONS)) {
caseExpression = new CastExpression(JavaTypeNames.RTCONS, caseExpression);
}
LocalVariableDeclaration caseVarDeclaration =
new LocalVariableDeclaration(caseVar, caseExpression);
switchBlock.addStatement(caseVarDeclaration);
}
// Populate the switch statement with case statement groups.
// Create a new let variable scope to handle the alternate and any let variables it contains.
variableContext.pushJavaScope();
Block caseBlock = new Block();
if (isSwitchingOnDC) {
caseBlock.addStatement(new LineComment(((DataConstructor)altTag).getName().getQualifiedName()));
}
// Get this alternative's variables. These have to be added to the active list of scope variables
if (alt.hasVars()) {
caseBlock.addStatement(new LineComment("Decompose data type to access members."));
if (caseVar == null) {
throw new CodeGenerationException ("Null case variable encountered in single alternate switch.");
}
// Must be a data constructor tag, since there are field names (see Expression.Switch.SwitchAlt).
DataConstructor tagDC = (DataConstructor)altTag;
TypeExpr fieldTypes[] = SCJavaDefn.getFieldTypesForDC(tagDC);
// Cast the case var to the appropriate type to call getField0, getField1, etc.
JavaTypeName dcTypeName = CALToJavaNames.createTypeNameFromDC(tagDC, module);
JavaExpression castExpression = new CastExpression(dcTypeName, caseVar);
// There is at least one field to be extracted.
// Declare a local variable that is the casted case var so that we only do the cast once.
JavaExpression castCaseVar = new LocalVariable("$dcCaseVar" + nestedCaseLevel, dcTypeName);
LocalVariableDeclaration localVarStmnt = new LocalVariableDeclaration((LocalVariable)castCaseVar, castExpression);
caseBlock.addStatement (localVarStmnt);
for (final AltVarIndexPair altVarIndexPair : getAltVarIndexList(alt, tagDC)) {
String altVar = altVarIndexPair.getAltVar();
int fieldIndex = altVarIndexPair.getIndex();
String fieldGetterName = "get" + SCJavaDefn.getJavaFieldNameFromDC(tagDC, fieldIndex);
// Build in place representation of this variable mapped to its name
QualifiedName qn = QualifiedName.make(currentModuleName, altVar);
VarInfo.DCMember vi = variableContext.addDCField(qn, fieldTypes[fieldIndex]);
boolean fieldIsStrict =
!LECCMachineConfiguration.IGNORE_STRICTNESS_ANNOTATIONS && tagDC.isArgStrict(fieldIndex);
if (fieldIsStrict) {
vi.setEvaluated(true);
}
if (fieldIsStrict) {
if (SCJavaDefn.canTypeBeUnboxed(fieldTypes[fieldIndex])) {
JavaTypeName strictType = SCJavaDefn.typeExprToTypeName(fieldTypes[fieldIndex]);
JavaExpression unboxedInitializer =
new JavaExpression.MethodInvocation.Instance(castCaseVar,
fieldGetterName + "_As_" + SCJavaDefn.getNameForPrimitive(strictType),
strictType,
JavaExpression.MethodInvocation.InvocationType.VIRTUAL);
vi.updateUnboxedVarDef(unboxedInitializer);
JavaExpression localVar = new LocalVariable(vi.getJavaName()+"$U", vi.getUnboxedType());
vi.updateUnboxedReference(localVar);
JavaExpression boxedDef = SCJavaDefn.boxExpression(vi.getUnboxedType(), localVar);
vi.updateStrictReference(boxedDef);
vi.updateLazyReference(boxedDef);
} else {
JavaExpression initializer = new JavaExpression.MethodInvocation.Instance(castCaseVar, fieldGetterName, JavaTypeNames.RTVALUE, JavaExpression.MethodInvocation.InvocationType.VIRTUAL);
vi.updateStrictVarDef (initializer);
JavaExpression localVar = new LocalVariable(vi.getJavaName(), JavaTypeNames.RTVALUE);
vi.updateStrictReference(localVar);
vi.updateLazyReference(localVar);
}
} else {
JavaExpression initializer = new JavaExpression.MethodInvocation.Instance(castCaseVar, fieldGetterName, JavaTypeNames.RTVALUE, JavaExpression.MethodInvocation.InvocationType.VIRTUAL);
vi.updateLazyVarDef (initializer);
JavaExpression localVar = new LocalVariable(vi.getJavaName(), JavaTypeNames.RTVALUE);
vi.updateLazyReference(localVar);
JavaExpression evaluatedVar = SCJavaDefn.createInvocation(localVar, SCJavaDefn.EVALUATE, SCJavaDefn.EXECUTION_CONTEXT_VAR);
vi.updateStrictReference(evaluatedVar);
if (SCJavaDefn.canTypeBeUnboxed(fieldTypes[fieldIndex])) {
vi.updateUnboxedReference(SCJavaDefn.unboxValue(vi.getUnboxedType(), evaluatedVar));
}
}
}
}
JavaStatement altStatement = genS_R(alt.getAltExpr(), variableContext);
caseBlock.addStatement(variableContext.popJavaScope());
caseBlock.addStatement(altStatement);
switchBlock.addStatement(caseBlock);
return switchBlock;
}