/*******************************************************************************
* 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.lookup;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.edt.compiler.binding.SettingsBlockAnnotationBindingsCompletor;
import org.eclipse.edt.compiler.core.IEGLConstants;
import org.eclipse.edt.compiler.core.ast.CallStatement;
import org.eclipse.edt.compiler.core.ast.CaseStatement;
import org.eclipse.edt.compiler.core.ast.Constructor;
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.FunctionDataDeclaration;
import org.eclipse.edt.compiler.core.ast.FunctionParameter;
import org.eclipse.edt.compiler.core.ast.IfStatement;
import org.eclipse.edt.compiler.core.ast.Name;
import org.eclipse.edt.compiler.core.ast.NestedFunction;
import org.eclipse.edt.compiler.core.ast.Node;
import org.eclipse.edt.compiler.core.ast.OnExceptionBlock;
import org.eclipse.edt.compiler.core.ast.SetValuesExpression;
import org.eclipse.edt.compiler.core.ast.SettingsBlock;
import org.eclipse.edt.compiler.core.ast.Statement;
import org.eclipse.edt.compiler.core.ast.TryStatement;
import org.eclipse.edt.compiler.core.ast.Type;
import org.eclipse.edt.compiler.core.ast.WhenClause;
import org.eclipse.edt.compiler.core.ast.WhileStatement;
import org.eclipse.edt.compiler.internal.core.builder.IMarker;
import org.eclipse.edt.compiler.internal.core.builder.IProblemRequestor;
import org.eclipse.edt.compiler.internal.core.dependency.IDependencyRequestor;
import org.eclipse.edt.mof.egl.Field;
import org.eclipse.edt.mof.egl.FunctionMember;
import org.eclipse.edt.mof.egl.IrFactory;
import org.eclipse.edt.mof.egl.Part;
/**
* @author winghong
*/
public class FunctionBinder extends DefaultBinder {
private FunctionMember functionBinding;
private Part partBinding;
private List<FunctionDataDeclaration> functionDataDecls = new ArrayList<FunctionDataDeclaration>();
private String canonicalFunctionName;
public FunctionBinder(Part partBinding, FunctionMember functionBinding, Scope scope,
IDependencyRequestor dependencyRequestor, IProblemRequestor problemRequestor, ICompilerOptions compilerOptions) {
super(scope, partBinding, dependencyRequestor, problemRequestor, compilerOptions);
this.partBinding = partBinding;
this.functionBinding = functionBinding;
}
@Override
public boolean visit(NestedFunction function) {
canonicalFunctionName = function.getName().getCanonicalName();
FunctionScope functionScope = new FunctionScope((FunctionContainerScope) currentScope, functionBinding);
currentScope = functionScope;
// For nested functions, the functionBinding passed in should already
// have been completed by the FunctionContainerBinder
for (org.eclipse.edt.mof.egl.FunctionParameter parm : functionBinding.getParameters()) {
functionScope.addDeclaredDataName(parm.getName());
}
return true;
}
@Override
public boolean visit(Constructor constructor) {
canonicalFunctionName = IEGLConstants.KEYWORD_CONSTRUCTOR;
FunctionScope functionScope = new FunctionScope((FunctionContainerScope) currentScope, functionBinding);
currentScope = functionScope;
// For constructors, the constructor passed in should already
// have been completed by the FunctionContainerBinder
for (org.eclipse.edt.mof.egl.FunctionParameter parm : functionBinding.getParameters()) {
functionScope.addDeclaredDataName(parm.getName());
}
return true;
}
@Override
public boolean visit(FunctionParameter functionParameter) {
return false;
}
@Override
public boolean visit(FunctionDataDeclaration dataDecl) {
functionDataDecls.add(dataDecl);
processDataDeclaration(dataDecl.getNames(), dataDecl.getType(), dataDecl.isNullable(), dataDecl.getSettingsBlockOpt(), dataDecl.isConstant(), dataDecl.getInitializer());
return true;
}
private void processDataDeclaration(List<Name> names, Type type, boolean isNullable, SettingsBlock settingsBlock, boolean isConstantDeclaration, Expression initializer) {
org.eclipse.edt.mof.egl.Type typeBinding = null;
try {
typeBinding = bindType(type);
} catch (ResolutionException e) {
problemRequestor.acceptProblem(e.getStartOffset(), e.getEndOffset(), IMarker.SEVERITY_ERROR, e.getProblemKind(), e
.getInserts());
if(settingsBlock != null) {
AbstractBinder.setBindAttemptedForNames(settingsBlock);
}
for(Name name : names) {
name.setBindAttempted(true);
}
return; // Do not create the class field bindings if the
// type cannot be resolved
}
for (Name name : names) {
String dataName = name.getIdentifier();
Field field;
if (isConstantDeclaration) {
field = IrFactory.INSTANCE.createConstantField();
}
else {
field = IrFactory.INSTANCE.createField();
}
field.setContainer(functionBinding);
field.setType(typeBinding);
field.setIsNullable(isNullable);
field.setName(name.getCaseSensitiveIdentifier());
if (((ILocalVariableScope) currentScope).hasDeclaredDataName(dataName)) {
problemRequestor.acceptProblem(name, IProblemRequestor.DUPLICATE_NAME_ACROSS_LISTS, new String[] {
name.getCanonicalName(), canonicalFunctionName });
}
else {
((ILocalVariableScope) currentScope).addLocalVariable(field);
((ILocalVariableScope) currentScope).addDeclaredDataName(dataName);
}
name.setMember(field);
name.setType(typeBinding);
if (settingsBlock != null) {
Scope scope = new MemberScope(NullScope.INSTANCE, field);
AnnotationLeftHandScope annotationScope = new AnnotationLeftHandScope(scope, field, typeBinding, field);
settingsBlock.accept(
new SettingsBlockAnnotationBindingsCompletor(currentScope, partBinding, annotationScope,
dependencyRequestor, problemRequestor, compilerOptions));
}
}
}
@Override
public void endVisit(NestedFunction nestedFunction) {
}
@Override
public boolean visit(SetValuesExpression setValuesExpression) {
setValuesExpression.getExpression().accept(this);
final org.eclipse.edt.mof.egl.Type type = setValuesExpression.getExpression().resolveType();
if (type != null) {
TypeScope newScope = new TypeScope(NullScope.INSTANCE, type);
setValuesExpression.getSettingsBlock().accept(
new SetValuesExpressionCompletor(currentScope, (Part)functionBinding.getContainer(), newScope, dependencyRequestor, problemRequestor, compilerOptions));
} else if (setValuesExpression.getExpression().resolveElement() != null) {
setValuesExpression.getSettingsBlock().accept(this);
}
return false;
}
@Override
public boolean visit(CallStatement callStatement) {
bindInvocationTarget(callStatement.getInvocationTarget());
if(callStatement.hasArguments()) {
for(Node node : callStatement.getArguments()) {
node.accept(this);
}
}
if(callStatement.hasSettingsBlock()) {
callStatement.getSettingsBlock().accept(this);
}
if (callStatement.getUsing() != null) {
callStatement.getUsing().accept(this);
}
if (callStatement.getCallSynchronizationValues() != null) {
if (callStatement.getCallSynchronizationValues().getReturns() != null) {
callStatement.getCallSynchronizationValues().getReturns().accept(this);
}
if (callStatement.getCallSynchronizationValues().getReturnTo() != null) {
callStatement.getCallSynchronizationValues().getReturnTo().accept(this);
}
if (callStatement.getCallSynchronizationValues().getOnException() != null) {
callStatement.getCallSynchronizationValues().getOnException().accept(this);
}
}
return false;
}
@Override
public boolean visit(ExitStatement exitStatement) {
if (exitStatement.getExitModifierOpt() != null) {
exitStatement.getExitModifierOpt().accept(this);
}
if(exitStatement.hasSettingsBlock()) {
exitStatement.getSettingsBlock().accept(this);
}
return false;
}
private void visitStatementBlocks(Statement statement) {
for(List<Node> block : statement.getStatementBlocks()) {
currentScope = new StatementBlockScope(currentScope);
for(Node node : block) {
node.accept(this);
}
currentScope = currentScope.getParentScope();
}
}
@Override
public boolean visit(IfStatement ifStatement) {
ifStatement.getCondition().accept(this);
visitStatementBlocks(ifStatement);
return false;
}
@Override
public boolean visit(CaseStatement caseStatement) {
if(caseStatement.hasCriterion()) {
Expression expr = caseStatement.getCriterion();
expr.accept(this);
}
for(WhenClause whenClause : caseStatement.getWhenClauses()) {
for(Expression expr : whenClause.getExpr_plus()) {
expr.accept(this);
}
}
visitStatementBlocks(caseStatement);
return false;
}
@Override
public boolean visit(ForStatement forStatement) {
currentScope = new StatementBlockScope(currentScope);
if(forStatement.hasVariableDeclaration()) {
processDataDeclaration(
Arrays.asList(new Name[] {forStatement.getVariableDeclarationName()}),
forStatement.getVariableDeclarationType(),
forStatement.isNullable(),
null,
false,
null);
}
else {
forStatement.getCounterVariable().accept(this);
}
if(forStatement.hasFromIndex()) {
forStatement.getFromIndex().accept(this);
}
forStatement.getEndIndex().accept(this);
if(forStatement.hasPositiveDelta() || forStatement.hasNegativeDelta()) {
forStatement.getDeltaExpression().accept(this);
}
for(Node node : forStatement.getStmts()) {
node.accept(this);
}
currentScope = currentScope.getParentScope();
return false;
}
@Override
public boolean visit(ForEachStatement forEachStatement) {
currentScope = new StatementBlockScope(currentScope);
if(forEachStatement.hasVariableDeclaration()) {
processDataDeclaration(
Arrays.asList(new Name[] {forEachStatement.getVariableDeclarationName()}),
forEachStatement.getVariableDeclarationType(),
forEachStatement.isNullable(),
null,
false,
null);
}
else {
for (Node n : (List<Node>)forEachStatement.getTargets()) {
n.accept(this);
}
}
forEachStatement.getResultSet().getExpression().accept(this);
for(Node node : forEachStatement.getStmts()) {
node.accept(this);
}
currentScope = currentScope.getParentScope();
return false;
}
@Override
public boolean visit(WhileStatement whileStatement) {
whileStatement.getExpr().accept(this);
visitStatementBlocks(whileStatement);
return false;
}
@Override
public boolean visit(TryStatement tryStatement) {
currentScope = new StatementBlockScope(currentScope);
for(Node node : tryStatement.getStmts()) {
node.accept(this);
}
currentScope = currentScope.getParentScope();
for(Node node : tryStatement.getOnExceptionBlocks()) {
node.accept(this);
}
return false;
}
public boolean visit(OnExceptionBlock onExceptionBlock) {
currentScope = new StatementBlockScope(currentScope);
processDataDeclaration(
Arrays.asList(new Name[] {onExceptionBlock.getExceptionName()}),
onExceptionBlock.getExceptionType(),
onExceptionBlock.isNullable(),
null,
false,
null);
for(Node node : onExceptionBlock.getStmts()) {
node.accept(this);
}
currentScope = currentScope.getParentScope();
return false;
}
}