/** * Copyright (c) 2005-2012 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the Eclipse Public License (EPL). * Please see the license.txt included with this distribution for details. * Any modifications to this file must keep this entire header intact. */ /* * Created on Dec 21, 2004 * * @author Fabio Zadrozny */ package org.python.pydev.editor.codecompletion.revisited.visitors; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.python.pydev.core.FullRepIterable; import org.python.pydev.core.ICompletionState; import org.python.pydev.core.IPythonNature; import org.python.pydev.core.IToken; import org.python.pydev.editor.codecompletion.revisited.modules.SourceToken; import org.python.pydev.parser.jython.SimpleNode; import org.python.pydev.parser.jython.ast.Import; import org.python.pydev.parser.jython.ast.ImportFrom; import org.python.pydev.parser.jython.ast.NameTok; import org.python.pydev.parser.jython.ast.Str; import org.python.pydev.parser.jython.ast.VisitorBase; import org.python.pydev.parser.jython.ast.aliasType; import org.python.pydev.parser.visitors.NodeUtils; /** * @author Fabio Zadrozny */ public abstract class AbstractVisitor extends VisitorBase { /** * The constants below may be combined for a single request */ public static final int GLOBAL_TOKENS = 1; public static final int WILD_MODULES = 2; public static final int ALIAS_MODULES = 4; public static final int MODULE_DOCSTRING = 8; /** * This constant cannot be combined with any of the others */ public static final int INNER_DEFS = 16; protected final List<IToken> tokens = new ArrayList<IToken>(); /** * Module being visited. */ protected String moduleName; protected final IPythonNature nature; public AbstractVisitor(IPythonNature nature) { this.nature = nature; } /** * Adds a token with a docstring. * * @param node */ protected SourceToken addToken(SimpleNode node) { //add the token SourceToken t = makeToken(node, moduleName, nature); this.tokens.add(t); return t; } public static SourceToken makeToken(SimpleNode node, String moduleName, IPythonNature nature) { return new SourceToken(node, NodeUtils.getRepresentationString(node), NodeUtils.getNodeArgs(node), NodeUtils.getNodeDocString(node), moduleName, nature); } public static SourceToken makeToken(SimpleNode node, String rep, String moduleName, IPythonNature nature) { return new SourceToken(node, rep, NodeUtils.getNodeArgs(node), NodeUtils.getNodeDocString(node), moduleName, nature); } /** * same as make token, but returns the full representation for a token, instead of just a 'partial' name */ public static SourceToken makeFullNameToken(SimpleNode node, String moduleName, IPythonNature nature) { return new SourceToken(node, NodeUtils.getFullRepresentationString(node), NodeUtils.getNodeArgs(node), NodeUtils.getNodeDocString(node), moduleName, nature); } /** * This function creates source tokens from a wild import node. * * @param node the import node * @param tokens OUT used to add the source token * @param moduleName the module name * * @return the tokens list passed in or the created one if it was null */ public static IToken makeWildImportToken(ImportFrom node, List<IToken> tokens, String moduleName, IPythonNature nature) { if (tokens == null) { tokens = new ArrayList<IToken>(); } SourceToken sourceToken = null; if (isWildImport(node)) { sourceToken = new SourceToken(node, ((NameTok) node.module).id, "", "", moduleName, nature); tokens.add(sourceToken); } return sourceToken; } public static List<IToken> makeImportToken(SimpleNode node, List<IToken> tokens, String moduleName, boolean allowForMultiple, IPythonNature nature) { if (node instanceof Import) { return makeImportToken((Import) node, tokens, moduleName, allowForMultiple, nature); } if (node instanceof ImportFrom) { ImportFrom i = (ImportFrom) node; if (isWildImport(i)) { makeWildImportToken(i, tokens, moduleName, nature); return tokens; } return makeImportToken((ImportFrom) node, tokens, moduleName, allowForMultiple, nature); } throw new RuntimeException("Unable to create token for the passed import (" + node + ")"); } /** * This function creates source tokens from an import node. * * @param node the import node * @param moduleName the module name where this token was found * @param tokens OUT used to add the source tokens (may create many from a single import) * @param allowForMultiple is used to indicate if an import in the format import os.path should generate one token for os * and another for os.path or just one for both with os.path * * @return the tokens list passed in or the created one if it was null */ public static List<IToken> makeImportToken(Import node, List<IToken> tokens, String moduleName, boolean allowForMultiple, IPythonNature nature) { aliasType[] names = node.names; return makeImportToken(node, tokens, names, moduleName, "", nature); } /** * The same as above but with ImportFrom */ public static List<IToken> makeImportToken(ImportFrom node, List<IToken> tokens, String moduleName, boolean allowForMultiple, IPythonNature nature) { aliasType[] names = node.names; String importName = ((NameTok) node.module).id; return makeImportToken(node, tokens, names, moduleName, importName, nature); } /** * This class is the same as a regular source token, just used to know that this * is a token that was created to identify a part of an import declaration. * * E.g.: * * import os.path * * Will create an 'os' part -- which is leaked to the namespace (but we must * identify that because we don't want to report import redefinitions nor unused * variables for those). * * See: https://sourceforge.net/tracker/index.php?func=detail&aid=2879058&group_id=85796&atid=577329 * and https://sourceforge.net/tracker/index.php?func=detail&aid=2008026&group_id=85796&atid=577329 */ public static class ImportPartSourceToken extends SourceToken { private static final long serialVersionUID = 1L; public ImportPartSourceToken(SimpleNode node, String rep, String doc, String args, String parentPackage, String originalRep, boolean originalHasRep, IPythonNature nature) { super(node, rep, doc, args, parentPackage, originalRep, originalHasRep, nature); } } /** * The same as above */ private static List<IToken> makeImportToken(SimpleNode node, List<IToken> tokens, aliasType[] names, String module, String initialImportName, IPythonNature nature) { if (tokens == null) { tokens = new ArrayList<IToken>(); } if (initialImportName.length() > 0) { initialImportName = initialImportName + "."; } for (int i = 0; i < names.length; i++) { aliasType aliasType = names[i]; String name = null; String original = ((NameTok) aliasType.name).id; if (aliasType.asname != null) { name = ((NameTok) aliasType.asname).id; } if (name == null) { FullRepIterable iterator = new FullRepIterable(original); Iterator<String> it = iterator.iterator(); while (it.hasNext()) { String rep = it.next(); SourceToken sourceToken; if (it.hasNext()) { sourceToken = new ImportPartSourceToken(node, rep, "", "", module, initialImportName + rep, true, nature); } else { sourceToken = new SourceToken(node, rep, "", "", module, initialImportName + rep, true, nature); } tokens.add(sourceToken); } } else { SourceToken sourceToken = new SourceToken(node, name, "", "", module, initialImportName + original, false, nature); tokens.add(sourceToken); } } return tokens; } public static boolean isString(SimpleNode ast) { if (ast instanceof Str) { return true; } return false; } /** * @param node the node to analyze * @return whether it is a wild import */ public static boolean isWildImport(ImportFrom node) { return node.names.length == 0; } /** * @param node the node to analyze * @return whether it is an alias import */ public static boolean isAliasImport(ImportFrom node) { return node.names.length > 0; } public List<IToken> getTokens() { return this.tokens; } /** * This method transverses the ast and returns a list of found tokens. * * @param ast * @param which * @param state * @param name * @param onlyAllowTokensIn__all__: only used when checking global tokens: if true, if a token named __all__ is available, * only the classes that have strings that match in __all__ are available. * @return * @throws Exception */ public static List<IToken> getTokens(SimpleNode ast, int which, String moduleName, ICompletionState state, boolean onlyAllowTokensIn__all__, IPythonNature nature) { AbstractVisitor modelVisitor; if (which == INNER_DEFS) { modelVisitor = new InnerModelVisitor(moduleName, state, nature); } else { modelVisitor = new GlobalModelVisitor(which, moduleName, onlyAllowTokensIn__all__, nature); } if (ast != null) { try { ast.accept(modelVisitor); } catch (Exception e) { throw new RuntimeException(e); } modelVisitor.finishVisit(); return modelVisitor.tokens; } else { return new ArrayList<IToken>(); } } /** * This method traverses the ast and returns a model visitor that has the list of found tokens (and other related info, such as __all__, etc.) */ public static GlobalModelVisitor getGlobalModuleVisitorWithTokens(SimpleNode ast, int which, String moduleName, ICompletionState state, boolean onlyAllowTokensIn__all__, IPythonNature nature) { if (which == INNER_DEFS) { throw new RuntimeException("Only globals for getting the GlobalModelVisitor"); } GlobalModelVisitor modelVisitor = new GlobalModelVisitor(which, moduleName, onlyAllowTokensIn__all__, nature); if (ast != null) { try { ast.accept(modelVisitor); } catch (Exception e) { throw new RuntimeException(e); } modelVisitor.finishVisit(); return modelVisitor; } else { return modelVisitor; } } /** * This method is available so that subclasses can do some post-processing before the tokens are actually * returned. */ protected void finishVisit() { /**Empty**/ } }