private JavaStatement genS_R(Expression e, VariableContext variableContext) throws CodeGenerationException {
// e is a pack constructor?
if (e.asPackCons() != null) {
//This is an error! We should never be at this point with a data constructor expression.
throw new CodeGenerationException ("PackCons expression encountered in R scheme: " + e.asPackCons().getDataConstructor().getName());
}
// R is a literal?
Expression.Literal lit = e.asLiteral();
if (lit != null) {
return generateReturn (getKernelLiteral(lit.getLiteral()).getBoxedReference(), variableContext);
}
// Is e a call to a let variable definition function?
ExpressionContextPair letVarECP = buildLetVarDefCall(e, Scheme.C_SCHEME, variableContext);
if (letVarECP != null) {
return generateReturn(letVarECP, variableContext);
}
// Is e a primitive operation (arithmetic, comparative etc.)?
{
BasicOpTuple bop = BasicOpTuple.isBasicOp(e);
if (!LECCMachineConfiguration.generateDirectPrimOpCalls()) {
// When we are generating call chains we want to force all primitive operations
// to be done as a function call to the generated function.
//When we have function tracing enabled, we want to force all primitive operations to be
//done as function calls. This will have the effect of ensuring that they get traced when called.
if (bop != null && !bop.getName().equals(getQualifiedName())) {
bop = null;
}
}
if (bop != null) {
ExpressionContextPair ecPair = generatePrimitiveOp(e, true, Scheme.R_SCHEME, variableContext);
return generateReturn (ecPair, variableContext);
}
}
// We can potentially optimize an application of not to use the Java ! operator.
// Because we are directly evaluating and circumventing laziness it is only safe
// to do this if there is no chance of a directly/indirectly recursive call.
if (isNot(e) && !ExpressionAnalyzer.dependsOnStronglyConnectedComponent(e, connectedComponents, getModuleName())) {
ExpressionContextPair ecPair = generateNot (e.asAppl(), true, variableContext);
return generateReturn(ecPair, variableContext);
}
// Is e an application of 'and' or 'or'? Test only - don't get tuple
if (BasicOpTuple.isAndOr(e) != null) {
ExpressionContextPair ecPair = generateAndOr(e, true, variableContext);
return generateReturn(ecPair, variableContext);
}
// Is e an application of a saturated constructor?
ConstructorOpTuple constructorOpTuple = ConstructorOpTuple.isConstructorOp(e, false);
if (constructorOpTuple != null) {
if (codeGenerationStats != null) {
codeGenerationStats.incrementFullySaturatedDCInTopLevelContext(constructorOpTuple.getDataConstructor().getName());
}
ExpressionContextPair ecPair = generateDataConstructor(constructorOpTuple, Scheme.R_SCHEME, variableContext);
return generateReturn(ecPair, variableContext);
}
// Is e a tail recursive call?
if (e.asTailRecursiveCall() != null) {
// We don't need to call generateReturn() at this point since a this
// expression will generate a loop continuation, not a 'return'.
return buildTailRecursiveLoopCall(e.asTailRecursiveCall(), variableContext);
}
// R is a variable?
if (e.asVar() != null) {
Expression.Var var = e.asVar();
JavaExpression varExpression = expressionVarToJavaDef(var, Scheme.R_SCHEME, variableContext);
// If the variable is already evaluated we want to call getValue(), which will follow any
// indirection chains and return the final value. However, if we are simply returning
// a strict unboxed function argument this isn't necessary.
if (variableContext.isLocalVariable(var.getName()) &&
variableContext.isVarPreEvaluated(var.getName()) &&
(!variableContext.isFunctionArgument(var.getName()) || !isArgUnboxable(var.getName()))) {
// Variable is already evaluated so simply do a 'getValue()' on it.
varExpression = new MethodInvocation.Instance(varExpression, "getValue", JavaTypeNames.RTVALUE, MethodInvocation.InvocationType.VIRTUAL);
}
return generateReturn(varExpression, variableContext);
}
// Is e a conditional op (if <cond expr> <then expr> <else expr>)?
// Since this is the top level compilation scheme we can generate an actual 'if' statement.
CondTuple conditionExpressions = CondTuple.isCondOp(e);
if (conditionExpressions != null) {
if (codeGenerationStats != null) {
codeGenerationStats.incrementOptimizedIfThenElse();
}
// This is a conditional op. The conditionExpressions tuple holds (kCond, kThen, kElse) expressions
// Generate the code for kThen and kElse, as arguments to a new I_Cond instruction
Expression condExpression = conditionExpressions.getConditionExpression();
ExpressionContextPair pair = generateUnboxedArgument(JavaTypeName.BOOLEAN, condExpression, variableContext);
// Then
variableContext.pushJavaScope();
JavaStatement thenPart = genS_R (conditionExpressions.getThenExpression(), variableContext);
Block thenBlock = variableContext.popJavaScope();
thenBlock.addStatement(thenPart);
// Else
variableContext.pushJavaScope();
JavaStatement elsePart = genS_R (conditionExpressions.getElseExpression(), variableContext);
Block elseBlock = variableContext.popJavaScope();
elseBlock.addStatement(elsePart);
JavaExpression conditionExpression = pair.getJavaExpression();
JavaStatement ite = new IfThenElseStatement(conditionExpression, thenBlock, elseBlock);
Block contextBlock = pair.getContextBlock();
contextBlock.addStatement(ite);
// We don't need to call generateReturn() at this point. Any return statements
// will have been generated in the sub-parts of the if-then-else.
return contextBlock;
}
// Expression is a case/switch?
Expression.Switch eswitch = e.asSwitch();
if (eswitch != null) {
// We don't need to call generateReturn() at this point. Any return statements
// will have been generated in the sub-parts of the switch.
return generateSwitch (eswitch, variableContext);
}
// Expression is a data constructor field selection?
Expression.DataConsSelection eDCSelection = e.asDataConsSelection();
if (eDCSelection != null) {
return generateReturn(generateDCFieldSelection(eDCSelection, Scheme.R_SCHEME, variableContext), variableContext);
}
// e is a let var.
if (e.asLetNonRec() != null) {
return generateReturn (generateLetNonRec(e.asLetNonRec(), Scheme.R_SCHEME, null, variableContext), variableContext);
}
if (e.asLetRec() != null) {
return generateReturn(generateLetRec(e.asLetRec(), Scheme.R_SCHEME, variableContext), variableContext);
}
// e is an application?
Expression.Appl appl = e.asAppl();
if (appl != null) {
JavaStatement topLevelSeq = buildTopLevelSeq (appl, false, variableContext);
if (topLevelSeq != null) {
return topLevelSeq;
}
ExpressionContextPair ecp = buildApplicationChain (appl, Scheme.R_SCHEME, variableContext);
if (ecp != null) {
return generateReturn(ecp, variableContext);
} else {
// This is a general application
ExpressionContextPair target;
if (appl.getE1().asDataConsSelection() != null) {
target = generateDCFieldSelection(appl.getE1().asDataConsSelection(), Scheme.E_SCHEME, variableContext);
} else {
target = genS_C(appl.getE1(), variableContext);
}
ExpressionContextPair arg = genS_C(appl.getE2(), variableContext);
JavaStatement.Block returnBlock = target.getContextBlock();
returnBlock.addStatement(arg.getContextBlock());
MethodInvocation mi = createInvocation(target.getJavaExpression(), APPLY, arg.getJavaExpression());
return generateReturn (new ExpressionContextPair(mi, returnBlock), variableContext);
}
}
//e is a record update
Expression.RecordUpdate recordUpdate = e.asRecordUpdate();
if (recordUpdate != null) {
ExpressionContextPair ecPair = generateStrictRecordUpdate(recordUpdate, variableContext);
return generateReturn(ecPair, variableContext);
}
// e is a record extension
Expression.RecordExtension recordExtension = e.asRecordExtension();
if (recordExtension != null) {
ExpressionContextPair ecPair = generateStrictRecordExtension(recordExtension, variableContext);
return generateReturn(ecPair, variableContext);
}
// e is a record selection
Expression.RecordSelection recordSelection = e.asRecordSelection();
if (recordSelection != null) {
return generateReturn(generateStrictRecordSelection(recordSelection, true, variableContext), variableContext);
}
// e is a record case
Expression.RecordCase recordCase = e.asRecordCase();
if (recordCase != null) {
return generateRecordCase (recordCase, variableContext);
}
// e is a cast
Expression.Cast cast = e.asCast();
if (cast != null) {
Expression.Var varToCast = cast.getVarToCast();
if (!variableContext.isFunctionArgument(varToCast.getName())) {
throw new CodeGenerationException("Expression.Cast is applied to a non-argument variable.");
}
if (!isArgStrict(varToCast.getName()) || !isArgUnboxable(varToCast.getName())) {
throw new CodeGenerationException("Expression.Cast is applied to a non-strict or non-primitive argument.");
}
JavaTypeName castType = JavaTypeName.make (getCastType(cast));
JavaExpression returnVal = boxExpression(castType, new JavaExpression.CastExpression(castType, variableContext.getUnboxedReference(varToCast.getName())));
return generateReturn(returnVal, variableContext);
}
throw new CodeGenerationException("Unrecognized expression: " + e);
}