| /******************************************************************************* |
| * Copyright (c) 2005, 2017 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 |
| * |
| *******************************************************************************/ |
| package org.eclipse.dltk.compiler; |
| |
| import java.util.List; |
| import java.util.Stack; |
| |
| import org.eclipse.dltk.ast.ASTNode; |
| import org.eclipse.dltk.ast.ASTVisitor; |
| import org.eclipse.dltk.ast.declarations.Argument; |
| import org.eclipse.dltk.ast.declarations.MethodDeclaration; |
| import org.eclipse.dltk.ast.declarations.ModuleDeclaration; |
| import org.eclipse.dltk.ast.declarations.TypeDeclaration; |
| import org.eclipse.dltk.ast.expressions.Expression; |
| import org.eclipse.dltk.ast.expressions.Literal; |
| import org.eclipse.dltk.ast.expressions.StringLiteral; |
| import org.eclipse.dltk.ast.statements.Statement; |
| import org.eclipse.dltk.compiler.IElementRequestor.TypeInfo; |
| |
| public class SourceElementRequestVisitor extends ASTVisitor { |
| |
| protected IElementRequestor fRequestor = null; |
| |
| protected boolean fInClass = false; // if we are in class |
| protected boolean fInMethod = false; // if we are in method |
| |
| protected TypeDeclaration fCurrentClass = null; |
| protected MethodDeclaration fCurrentMethod = null; |
| |
| // Used to hold visited nodes in depth |
| protected Stack<ASTNode> fNodes = new Stack<>(); |
| |
| /** |
| * @since 2.0 |
| */ |
| public SourceElementRequestVisitor(IElementRequestor requesor) { |
| this.fRequestor = requesor; |
| } |
| |
| /** |
| * @return method node that encloses current element, or <code>null</code> |
| * if there's no one. |
| */ |
| public MethodDeclaration getCurrentMethod() { |
| return this.fCurrentMethod; |
| } |
| |
| /** |
| * @return class node that encloses current element, or <code>null</code> if |
| * there's no one. |
| */ |
| protected TypeDeclaration getCurrentClass() { |
| return this.fCurrentClass; |
| } |
| |
| protected String makeLanguageDependentValue(ASTNode expr) { |
| return ""; //$NON-NLS-1$ |
| } |
| |
| /** |
| * Called then end of methd are visited. Method are added to model before |
| * this call is done. |
| */ |
| protected void onEndVisitMethod(MethodDeclaration method) { |
| |
| } |
| |
| protected String[] processSuperClasses(TypeDeclaration type) { |
| List names = type.getSuperClassNames(); |
| if (names == null) { |
| return null; |
| } |
| if (names.isEmpty()) { |
| return null; |
| } |
| |
| return (String[]) names.toArray(new String[names.size()]); |
| } |
| |
| /** |
| * Called then end of class are visited. Class are added to model before |
| * this call is done. |
| */ |
| protected void onEndVisitClass(TypeDeclaration type) { |
| } |
| |
| /** |
| * Called before method info is propagated to the source element requestor. |
| * This is a last chance to modify the method info |
| * |
| * @since 2.0 |
| */ |
| protected void modifyMethodInfo(MethodDeclaration methodDeclaration, |
| ISourceElementRequestor.MethodInfo mi) { |
| } |
| |
| /** |
| * Called before method info is propagated to the source element requestor. |
| * This is a last chance to modify the class info |
| * |
| * @since 2.0 |
| */ |
| protected void modifyClassInfo(TypeDeclaration typeDeclaration, |
| TypeInfo ti) { |
| } |
| |
| /** |
| * Creates correct string value from expression. For example for |
| * StringLiteral returns "value". And so on. |
| * |
| * Return "" if it is imposible to make value from expression. |
| * |
| * @param expr |
| * @return |
| */ |
| protected String makeValue(ASTNode stmt) { |
| // if (!(stmt instanceof Expression)) |
| // return null; |
| |
| String value = ""; //$NON-NLS-1$ |
| if (stmt instanceof StringLiteral) { |
| value = "\"" + ((StringLiteral) stmt).getValue() + "\""; //$NON-NLS-1$ //$NON-NLS-2$ |
| } else if (stmt instanceof Literal) { |
| value = ((Literal) stmt).getValue(); |
| } else /* if (stmt instanceof ExtendedVariableReference) */ { |
| // If it is Dot. |
| // Lets make recursive value parsing in this case. |
| value += this.makeLanguageDependentValue(stmt); |
| } |
| |
| return value; |
| } |
| |
| @Override |
| public boolean endvisit(MethodDeclaration method) throws Exception { |
| this.fRequestor.exitMethod(method.sourceEnd()); |
| this.fInMethod = false; |
| this.fCurrentMethod = null; |
| |
| this.onEndVisitMethod(method); |
| |
| this.fNodes.pop(); |
| return true; |
| } |
| |
| @Override |
| public boolean endvisit(TypeDeclaration type) throws Exception { |
| this.fRequestor.exitType(type.sourceEnd()); |
| this.fInClass = false; |
| this.fCurrentClass = null; |
| |
| this.onEndVisitClass(type); |
| |
| this.fNodes.pop(); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(MethodDeclaration method) throws Exception { |
| this.fNodes.push(method); |
| List args = method.getArguments(); |
| |
| String[] parameter = new String[args.size()]; |
| String[] initializers = new String[args.size()]; |
| for (int a = 0; a < args.size(); a++) { |
| Argument arg = (Argument) args.get(a); |
| parameter[a] = arg.getName(); |
| if (arg.getInitialization() != null) { |
| if (arg.getInitialization() instanceof Literal) { |
| Literal scalar = (Literal) arg.getInitialization(); |
| initializers[a] = scalar.getValue(); |
| } |
| } |
| } |
| |
| ISourceElementRequestor.MethodInfo mi = new ISourceElementRequestor.MethodInfo(); |
| mi.parameterNames = parameter; |
| mi.name = method.getName(); |
| mi.modifiers = method.getModifiers(); |
| mi.nameSourceStart = method.getNameStart(); |
| mi.nameSourceEnd = method.getNameEnd() - 1; |
| mi.declarationStart = method.sourceStart(); |
| mi.parameterInitializers = initializers; |
| |
| modifyMethodInfo(method, mi); |
| |
| this.fRequestor.enterMethod(mi); |
| |
| this.fInMethod = true; |
| this.fCurrentMethod = method; |
| return true; |
| } |
| |
| @Override |
| public boolean visit(TypeDeclaration type) throws Exception { |
| this.fNodes.push(type); |
| |
| ISourceElementRequestor.TypeInfo info = new ISourceElementRequestor.TypeInfo(); |
| info.modifiers = type.getModifiers(); |
| info.name = type.getName(); |
| info.nameSourceStart = type.getNameStart(); |
| info.nameSourceEnd = type.getNameEnd() - 1; |
| info.declarationStart = type.sourceStart(); |
| info.superclasses = this.processSuperClasses(type); |
| |
| modifyClassInfo(type, info); |
| |
| this.fRequestor.enterType(info); |
| |
| this.fInClass = true; |
| this.fCurrentClass = type; |
| |
| return true; |
| } |
| |
| @Override |
| public boolean endvisit(ModuleDeclaration declaration) throws Exception { |
| this.fRequestor.exitModule(declaration.sourceEnd()); |
| this.fNodes.pop(); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(ModuleDeclaration declaration) throws Exception { |
| this.fNodes.push(declaration); |
| this.fRequestor.enterModule(); |
| return true; |
| } |
| |
| @Override |
| public boolean endvisit(Expression expression) throws Exception { |
| this.fNodes.pop(); |
| return true; |
| } |
| |
| @Override |
| public boolean endvisit(Statement statement) throws Exception { |
| this.fNodes.pop(); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(Expression expression) throws Exception { |
| this.fNodes.push(expression); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(Statement statement) throws Exception { |
| this.fNodes.push(statement); |
| return true; |
| } |
| } |