/*******************************************************************************
* Copyright © 2011, 2013 IBM Corporation 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
*
* Contributors:
* IBM Corporation - initial API and implementation
*
*******************************************************************************/
package org.eclipse.edt.compiler.internal.core.validation.statement;
import java.util.Map;
import org.eclipse.edt.compiler.binding.IPartBinding;
import org.eclipse.edt.compiler.binding.ITypeBinding;
import org.eclipse.edt.compiler.core.IEGLConstants;
import org.eclipse.edt.compiler.core.ast.CaseStatement;
import org.eclipse.edt.compiler.core.ast.DefaultASTVisitor;
import org.eclipse.edt.compiler.core.ast.ExitStatement;
import org.eclipse.edt.compiler.core.ast.Expression;
import org.eclipse.edt.compiler.core.ast.ForEachStatement;
import org.eclipse.edt.compiler.core.ast.ForStatement;
import org.eclipse.edt.compiler.core.ast.IfStatement;
import org.eclipse.edt.compiler.core.ast.LabelStatement;
import org.eclipse.edt.compiler.core.ast.NestedFunction;
import org.eclipse.edt.compiler.core.ast.Node;
import org.eclipse.edt.compiler.core.ast.Statement;
import org.eclipse.edt.compiler.core.ast.WhileStatement;
import org.eclipse.edt.compiler.internal.core.builder.IProblemRequestor;
import org.eclipse.edt.compiler.internal.core.lookup.ICompilerOptions;
import org.eclipse.edt.compiler.internal.core.validation.name.EGLNameValidator;
import org.eclipse.edt.mof.egl.FixedPrecisionType;
import org.eclipse.edt.mof.egl.Type;
import org.eclipse.edt.mof.egl.utils.TypeUtils;
public class ExitStatementValidator extends DefaultASTVisitor {
private IProblemRequestor problemRequestor;
private ICompilerOptions compilerOptions;
private IPartBinding enclosingPart;
private Map labeledLoops;
public ExitStatementValidator(IProblemRequestor problemRequestor, Map labeledLoops, IPartBinding enclosingPart, ICompilerOptions compilerOptions) {
this.problemRequestor = problemRequestor;
this.enclosingPart = enclosingPart;
this.compilerOptions = compilerOptions;
this.labeledLoops = labeledLoops;
}
@Override
public boolean visit(final ExitStatement exitStatement) {
if (exitStatement.isExitProgram() || exitStatement.isExitRunUnit()){
validateExitProgramRunUnit(exitStatement);
}
else if (exitStatement.isExitStack()){
validateExitStack(exitStatement);
}
else {
validateExitLoop(exitStatement);
}
if(enclosingPart != null) {
if(exitStatement.isExitProgram() || exitStatement.isExitStack()) {
if(ITypeBinding.PROGRAM_BINDING != enclosingPart.getKind()) {
problemRequestor.acceptProblem(
exitStatement,
IProblemRequestor.EXIT_MODIFIER_ONLY_ALLOWED_IN_PROGRAM,
new String[] {
exitStatement.isExitProgram() ? IEGLConstants.KEYWORD_PROGRAM.toUpperCase() : IEGLConstants.KEYWORD_STACK.toUpperCase()
});
}
}
else if(exitStatement.isExitRunUnit()) {
if(ITypeBinding.SERVICE_BINDING == enclosingPart.getKind()) {
problemRequestor.acceptProblem(
exitStatement,
IProblemRequestor.EXIT_MODIFIER_NOT_ALLOWED_IN_SERVICE,
new String[] {
IEGLConstants.KEYWORD_RUNUNIT.toUpperCase()
});
}
}
}
return false;
}
private void validateExitLoop(final ExitStatement exitStatement) {
Node current = exitStatement.getParent();
String label = exitStatement.getLabel();
ParentASTVisitor visitor = new ParentASTVisitor(isExitNULL(exitStatement), label){
@Override
public boolean visit(NestedFunction anestedFunction) {
bcontinue = false;
if (isnull){
valid = true;
}
return false;
}
@Override
public boolean visit(WhileStatement whileStatement) {
if (exitStatement.isExitWhile() || isnull || hasMatchingLabel(whileStatement, labelText))
valid = true;
return false;
}
@Override
public boolean visit(ForEachStatement forEachStatement) {
if (exitStatement.isExitForEach() || isnull || hasMatchingLabel(forEachStatement, labelText))
valid = true;
return false;
}
@Override
public boolean visit(ForStatement forStatement) {
if (exitStatement.isExitFor()|| isnull || hasMatchingLabel(forStatement, labelText))
valid = true;
return false;
}
@Override
public boolean visit(CaseStatement caseStatement) {
if (exitStatement.isExitCase() || isnull || hasMatchingLabel(caseStatement, labelText))
valid = true;
return false;
}
@Override
public boolean visit(IfStatement caseStatement) {
if (exitStatement.isExitIf() || isnull || hasMatchingLabel(caseStatement, labelText))
valid = true;
return false;
}
};
while ((current != null) && visitor.canContinue() && !visitor.isValid()) {
current.accept(visitor);
current = current.getParent();
}
if (!visitor.isValid()){
if(label != null) {
problemRequestor.acceptProblem(exitStatement, IProblemRequestor.INVALID_CONTINUE_EXIT_LABEL, new String[] {label});
}
else {
String errorIns0 = IEGLConstants.KEYWORD_EXIT; //$NON-NLS-1$
String errorIns1 = ""; //$NON-NLS-1$
String[] errorInserts = null;
if (exitStatement.isExitCase()){
errorIns1 = IEGLConstants.KEYWORD_CASE;
}else if (exitStatement.isExitFor()){
errorIns1 = IEGLConstants.KEYWORD_FOR;
}else if (exitStatement.isExitForEach()){
errorIns1 = IEGLConstants.KEYWORD_FOREACH;
}else if (exitStatement.isExitIf()){
errorIns1 = IEGLConstants.KEYWORD_IF;
}else if (exitStatement.isExitStack()){
errorIns1 = IEGLConstants.KEYWORD_STACK;
}else {
errorIns1 = IEGLConstants.KEYWORD_WHILE;
}
errorInserts = new String[] {errorIns0, errorIns1};
problemRequestor.acceptProblem(exitStatement,
IProblemRequestor.INVALID_CONTINUE_EXIT_MODIFIER,
errorInserts);
}
}
}
protected void validateExitStack(final ExitStatement exitStatement){
String label = exitStatement.getLabel();
if(label != null) {
EGLNameValidator.validate(label, EGLNameValidator.IDENTIFIER, problemRequestor, exitStatement, compilerOptions);
}
}
protected void validateExitProgramRunUnit(ExitStatement exitStatement){
Expression expr = exitStatement.getReturnCode();
if (expr == null){
return;
}
Type binding = expr.resolveType();
if (binding != null) {
boolean valid = TypeUtils.Type_ANY.equals(binding)
|| (TypeUtils.isNumericType(binding) && !binding.equals(TypeUtils.Type_FLOAT) && !binding.equals(TypeUtils.Type_SMALLFLOAT));
if (valid && binding instanceof FixedPrecisionType) {
valid = ((FixedPrecisionType)binding).getDecimals() == 0;
}
if (!valid){
problemRequestor.acceptProblem(expr,
IProblemRequestor.EXIT_PROGRAM_ITEM_NOT_INTEGER,
new String[]{expr.getCanonicalString()});
}
}
}
protected boolean isExitNULL(ExitStatement exitStatement){
return exitStatement.isExitProgram() ||
(!exitStatement.isExitCase() &&
!exitStatement.isExitFor() &&
!exitStatement.isExitForEach() &&
!exitStatement.isExitIf() &&
!exitStatement.isExitStack() &&
!exitStatement.isExitWhile() &&
exitStatement.getLabel() == null);
}
private class ParentASTVisitor extends DefaultASTVisitor {
boolean valid = false;
boolean bcontinue = true;
boolean isnull = false;
NestedFunction nestedFunction = null;
protected String labelText;
public ParentASTVisitor (boolean isnull, String labelText){
this.isnull = isnull;
this.labelText = labelText;
}
public boolean isValid(){
return valid;
}
public boolean canContinue(){
return bcontinue;
}
protected boolean hasMatchingLabel(Statement loopStatement, String labelText) {
LabelStatement label = (LabelStatement) labeledLoops.get(loopStatement);
if(label != null) {
return label.getLabel().equalsIgnoreCase(labelText);
}
return false;
}
}
}