blob: bfab9d5d5fa5c1f1d4341ce970850eabaaca17a0 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 Institute for Software, HSR Hochschule fuer Technik
* Rapperswil, University of applied sciences and others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import org.eclipse.cdt.core.dom.ast.IValue;
import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation.ConstexprEvaluationContext;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPExecution;
import org.eclipse.cdt.internal.core.dom.parser.cpp.InstantiationContext;
import org.eclipse.core.runtime.CoreException;
public class ExecSwitch implements ICPPExecution {
private final ICPPExecution initStmtExec;
private final ICPPEvaluation controllerExprEval;
private final ExecSimpleDeclaration controllerDeclExec;
private final ICPPExecution[] bodyStmtExecutions;
public ExecSwitch(ICPPExecution initStmtExec, ICPPEvaluation controllerExprEval, ExecSimpleDeclaration controllerDeclExec, ICPPExecution[] bodyStmtExecutions) {
this.initStmtExec = initStmtExec;
this.controllerExprEval = controllerExprEval;
this.controllerDeclExec = controllerDeclExec;
this.bodyStmtExecutions = bodyStmtExecutions;
}
@Override
public ICPPExecution executeForFunctionCall(ActivationRecord record, ConstexprEvaluationContext context) {
EvalUtil.executeStatement(initStmtExec, record, context);
final int caseIndex = getMatchingCaseIndex(record, context);
for (int i = caseIndex; i < bodyStmtExecutions.length; ++i) {
ICPPExecution stmtExec = bodyStmtExecutions[i];
ICPPExecution result = EvalUtil.executeStatement(stmtExec, record, context);
if (result instanceof ExecReturn || result instanceof ExecContinue) {
return result;
} else if (result instanceof ExecBreak) {
break;
}
}
return null;
}
private int getMatchingCaseIndex(ActivationRecord record, ConstexprEvaluationContext context) {
IValue controllerValue = null;
if (controllerExprEval != null) {
controllerValue = EvalUtil.getConditionExprValue(controllerExprEval, record, context);
} else if (controllerDeclExec != null) {
controllerValue = EvalUtil.getConditionDeclValue(controllerDeclExec, record, context);
}
for (int i = 0; i < bodyStmtExecutions.length; ++i) {
if (isSatisfiedCaseStatement(bodyStmtExecutions[i], controllerValue, record, context)) {
return i;
}
}
return bodyStmtExecutions.length;
}
private boolean isSatisfiedCaseStatement(ICPPExecution stmtExec, IValue controllerValue,
ActivationRecord record, ConstexprEvaluationContext context) {
if (stmtExec instanceof ExecCase) {
ExecCase caseStmtExec = (ExecCase) stmtExec;
caseStmtExec = (ExecCase) caseStmtExec.executeForFunctionCall(record, context);
Number caseVal = caseStmtExec.getCaseExpressionEvaluation().getValue().numberValue();
Number controllerVal = controllerValue.numberValue();
return caseVal != null && controllerVal != null && caseVal.equals(controllerVal);
}
return stmtExec instanceof ExecDefault;
}
@Override
public ICPPExecution instantiate(InstantiationContext context, int maxDepth) {
ICPPExecution newInitStmtExec = initStmtExec != null ? initStmtExec.instantiate(context, maxDepth) : null;
ICPPEvaluation newControllerExprEval = controllerExprEval != null ? controllerExprEval.instantiate(context, maxDepth) : null;
ExecSimpleDeclaration newControllerDeclExec = controllerDeclExec != null ? (ExecSimpleDeclaration) controllerDeclExec.instantiate(context, maxDepth) : null;
ICPPExecution[] newBodyStmtExecutions = new ICPPExecution[bodyStmtExecutions.length];
boolean executionsDidChange = false;
for (int i = 0; i < bodyStmtExecutions.length; i++) {
ICPPExecution bodyStmtExec = bodyStmtExecutions[i];
ICPPExecution newBodyStmtExec = bodyStmtExec.instantiate(context, maxDepth);
if (newBodyStmtExec != bodyStmtExec) {
executionsDidChange = true;
}
newBodyStmtExecutions[i] = newBodyStmtExec;
}
if (newInitStmtExec == initStmtExec && newControllerExprEval == controllerExprEval && newControllerDeclExec == controllerDeclExec && !executionsDidChange) {
return this;
}
return new ExecSwitch(newInitStmtExec, newControllerExprEval, newControllerDeclExec, newBodyStmtExecutions);
}
@Override
public void marshal(ITypeMarshalBuffer buffer, boolean includeValue) throws CoreException {
buffer.putShort(ITypeMarshalBuffer.EXEC_SWITCH);
buffer.marshalExecution(initStmtExec, includeValue);
buffer.marshalEvaluation(controllerExprEval, includeValue);
buffer.marshalExecution(controllerDeclExec, includeValue);
buffer.putInt(bodyStmtExecutions.length);
for (ICPPExecution execution : bodyStmtExecutions) {
buffer.marshalExecution(execution, includeValue);
}
}
public static ICPPExecution unmarshal(short firstBytes, ITypeMarshalBuffer buffer) throws CoreException {
ICPPExecution initStmtExec = buffer.unmarshalExecution();
ICPPEvaluation controllerExprEval = buffer.unmarshalEvaluation();
ExecSimpleDeclaration controllerDeclExec = (ExecSimpleDeclaration) buffer.unmarshalExecution();
int len = buffer.getInt();
ICPPExecution[] bodyStmtExecutions = new ICPPExecution[len];
for (int i = 0; i < bodyStmtExecutions.length; i++) {
bodyStmtExecutions[i] = buffer.unmarshalExecution();
}
return new ExecSwitch(initStmtExec, controllerExprEval, controllerDeclExec, bodyStmtExecutions);
}
}