// Increment the nested case level. This is used to disambiguate the name of the variable created
// to hold the record value of the case expression.
nestedCaseLevel++;
Expression conditionExpr = recordCaseExpr.getConditionExpr();
ExpressionContextPair conditionExprContextPair = genS_E(conditionExpr, variableContext);
Block recordCaseBlock = new Block();
JavaExpression javaConditionExpr = conditionExprContextPair.getJavaExpression();
recordCaseBlock.addStatement(conditionExprContextPair.getContextBlock());
//the compiler ensures that evaluating conditionExpr will result in a RTRecordValue.
javaConditionExpr = new CastExpression(JavaTypeNames.RTRECORD_VALUE, javaConditionExpr);
LocalVariable conditionVar = new LocalVariable("$recordCase" + nestedCaseLevel, JavaTypeNames.RTRECORD_VALUE);
LocalVariableDeclaration conditionVarDeclaration = new LocalVariableDeclaration(conditionVar, javaConditionExpr);
recordCaseBlock.addStatement(conditionVarDeclaration);
//now encode the extraction of the pattern bound variables from the condition record expr.
// Also need to push a let variable block. This is separate from the variable scope because the two
// do not always coincide. The let variable block is popped by calling i_VariableScope.genS_Vars().
variableContext.pushJavaScope();
//FieldName -> String
SortedMap<FieldName, String> fieldBindingVarMap = recordCaseExpr.getFieldBindingVarMap();
String baseRecordPatternVarName = recordCaseExpr.getBaseRecordPatternVarName();
if (baseRecordPatternVarName != null &&
!baseRecordPatternVarName.equals(Expression.RecordCase.WILDCARD_VAR)) {
QualifiedName qn = QualifiedName.make(currentModuleName, baseRecordPatternVarName);
VarInfo.RecordField varInfo = variableContext.addRecordField(qn, null);
String javaBaseRecordPatternVarName = varInfo.getJavaName();
LocalName lazyRef = new LocalName(varInfo.getJavaName(), JavaTypeNames.RTVALUE);
varInfo.updateLazyReference(lazyRef);
varInfo.updateStrictReference(SCJavaDefn.createInvocation(lazyRef, SCJavaDefn.EVALUATE, SCJavaDefn.EXECUTION_CONTEXT_VAR));
//generate the Java code:
//(in the case of both ordinal and textual field names
//javaBaseRecordPatternVarName = conditionVar.makeMixedRecordRetraction(new int[] {ordinalFieldName1, ..., ordinalFieldNameN},
// new String[] {textualFieldName1, ..., textualFieldNameN}
LocalVariable baseRecordPatternVar = new LocalVariable(javaBaseRecordPatternVarName, JavaTypeNames.RTRECORD_VALUE);
JavaExpression javaExtractBaseRecordExpr;
Expression.RecordCase.FieldData fieldData = recordCaseExpr.getBindingFieldsData();
//todoBI there could be some more optimizations here to handle the cases
//a. where the ordinal names are in tuple form, then only the tuple size needs to be passed.
//b. where only a single ordinal or single textual field is being retracted, then we don't
// need to form the array.
//Note however, that if the record pattern var is not used in the expression on the right hand side
//of the ->, then it will not be created (earlier analysis replaces it by a _), so in fact this
//code is not called that often anyways.
int[] retractedOrdinalFields = fieldData.getOrdinalNames();
String[] retractedTextualFields = fieldData.getTextualNames();
if (retractedOrdinalFields.length > 0) {
if (retractedTextualFields.length > 0) {
if (fieldData.hasTupleOrdinalPart()) {
javaExtractBaseRecordExpr = new MethodInvocation.Instance(
conditionVar,
"makeTupleMixedRecordRetraction",
new JavaExpression[] {
LiteralWrapper.make(Integer.valueOf(retractedOrdinalFields.length)),
createTextualNamesArray(retractedTextualFields)},
new JavaTypeName[] {JavaTypeName.INT, JavaTypeName.STRING_ARRAY},
JavaTypeNames.RTRECORD_VALUE,
InvocationType.VIRTUAL);
} else {
javaExtractBaseRecordExpr = new MethodInvocation.Instance(
conditionVar,
"makeMixedRecordRetraction",
new JavaExpression[] {
createOrdinalNamesArray(retractedOrdinalFields),
createTextualNamesArray(retractedTextualFields)},
new JavaTypeName[] {JavaTypeName.INT_ARRAY, JavaTypeName.STRING_ARRAY},
JavaTypeNames.RTRECORD_VALUE,
InvocationType.VIRTUAL);
}
} else {
if (fieldData.hasTupleOrdinalPart()) {
javaExtractBaseRecordExpr = new MethodInvocation.Instance(
conditionVar,
"makeTupleRecordRetraction",
new JavaExpression[] {
LiteralWrapper.make(Integer.valueOf(retractedOrdinalFields.length))},
new JavaTypeName[] {JavaTypeName.INT},
JavaTypeNames.RTRECORD_VALUE,
InvocationType.VIRTUAL);
} else {
javaExtractBaseRecordExpr = new MethodInvocation.Instance(
conditionVar,
"makeOrdinalRecordRetraction",
new JavaExpression[] {
createOrdinalNamesArray(retractedOrdinalFields)},
new JavaTypeName[] {JavaTypeName.INT_ARRAY},
JavaTypeNames.RTRECORD_VALUE,
InvocationType.VIRTUAL);
}
}
} else if (retractedTextualFields.length > 0) {
javaExtractBaseRecordExpr = new MethodInvocation.Instance(
conditionVar,
"makeTextualRecordRetraction",
new JavaExpression[] {
createTextualNamesArray(retractedTextualFields)},
new JavaTypeName[] {JavaTypeName.STRING_ARRAY},
JavaTypeNames.RTRECORD_VALUE,
InvocationType.VIRTUAL);
} else {
javaExtractBaseRecordExpr = conditionVar;
}
LocalVariableDeclaration extractBaseRecordDeclaration =
new LocalVariableDeclaration(baseRecordPatternVar, javaExtractBaseRecordExpr);
recordCaseBlock.addStatement(extractBaseRecordDeclaration);
}
for (final Map.Entry<FieldName, String> entry : fieldBindingVarMap.entrySet()) {
FieldName fieldName = entry.getKey();
String bindingVarName = entry.getValue();
//ignore anonymous pattern variables. These are guaranteed not to be used
//by the result expression, and so don't need to be extracted from the condition record.
if (!bindingVarName.equals(Expression.RecordCase.WILDCARD_VAR)) {
QualifiedName qn = QualifiedName.make(currentModuleName, bindingVarName);
VarInfo.RecordField varInfo = variableContext.addRecordField(qn, null);
String javaBindingVarName = varInfo.getJavaName();
LocalName lazyRef = new LocalName(varInfo.getJavaName(), JavaTypeNames.RTVALUE);
varInfo.updateLazyReference(lazyRef);
varInfo.updateStrictReference(SCJavaDefn.createInvocation(lazyRef, SCJavaDefn.EVALUATE, SCJavaDefn.EXECUTION_CONTEXT_VAR));
LocalVariable bindingVar = new LocalVariable(javaBindingVarName, JavaTypeNames.RTVALUE);
JavaExpression javaExtractValueExpr;
if (fieldName instanceof FieldName.Textual) {
//javaBindingVarName = $recordCase.getTextualFieldValue(fieldName);
javaExtractValueExpr = new MethodInvocation.Instance(conditionVar, "getTextualFieldValue",
LiteralWrapper.make(fieldName.getCalSourceForm()), JavaTypeName.STRING,
JavaTypeNames.RTVALUE, InvocationType.VIRTUAL);
} else {
int ordinal = ((FieldName.Ordinal)fieldName).getOrdinal();
javaExtractValueExpr = new MethodInvocation.Instance(conditionVar, "getOrdinalFieldValue",
LiteralWrapper.make(Integer.valueOf(ordinal)), JavaTypeName.INT,
JavaTypeNames.RTVALUE, InvocationType.VIRTUAL);
}
LocalVariableDeclaration extractValueDeclaration = new LocalVariableDeclaration(bindingVar, javaExtractValueExpr);
recordCaseBlock.addStatement(extractValueDeclaration);
}
}
//encode the result expression in the context of the extended variable scope.
Expression resultExpr = recordCaseExpr.getResultExpr();
JavaStatement resultJavaStatement = genS_R(resultExpr, variableContext);
// Generate any let variables in this block and add them to the recordCaseBlock.
recordCaseBlock.addStatement(variableContext.popJavaScope());