/****************************************************************************** * Copyright (C) 2006-2012 IFS Institute for Software 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 * * Original authors: * Dennis Hunziker * Ueli Kistler * Reto Schuettel * Robin Stocker * Contributors: * Fabio Zadrozny <fabiofz@gmail.com> - initial implementation ******************************************************************************/ /* * Copyright (C) 2006, 2007 Dennis Hunziker, Ueli Kistler * Copyright (C) 2007 Reto Schuettel, Robin Stocker * * IFS Institute for Software, HSR Rapperswil, Switzerland * */ package org.python.pydev.parser.jython.ast.factory; import java.util.ArrayList; import org.python.pydev.parser.jython.ISpecialStr; import org.python.pydev.parser.jython.SimpleNode; import org.python.pydev.parser.jython.ast.Assign; import org.python.pydev.parser.jython.ast.Attribute; import org.python.pydev.parser.jython.ast.BoolOp; import org.python.pydev.parser.jython.ast.Call; import org.python.pydev.parser.jython.ast.ClassDef; import org.python.pydev.parser.jython.ast.Comprehension; import org.python.pydev.parser.jython.ast.Dict; import org.python.pydev.parser.jython.ast.For; import org.python.pydev.parser.jython.ast.FunctionDef; import org.python.pydev.parser.jython.ast.If; import org.python.pydev.parser.jython.ast.Import; import org.python.pydev.parser.jython.ast.ImportFrom; import org.python.pydev.parser.jython.ast.Lambda; import org.python.pydev.parser.jython.ast.List; import org.python.pydev.parser.jython.ast.Module; import org.python.pydev.parser.jython.ast.Name; import org.python.pydev.parser.jython.ast.NameTok; import org.python.pydev.parser.jython.ast.Str; import org.python.pydev.parser.jython.ast.TryExcept; import org.python.pydev.parser.jython.ast.TryFinally; import org.python.pydev.parser.jython.ast.Tuple; import org.python.pydev.parser.jython.ast.While; import org.python.pydev.parser.jython.ast.With; import org.python.pydev.parser.jython.ast.argumentsType; import org.python.pydev.parser.jython.ast.decoratorsType; import org.python.pydev.parser.jython.ast.exprType; import org.python.pydev.parser.jython.ast.keywordType; import org.python.pydev.parser.visitors.NodeUtils; public class NodeHelper { private final AdapterPrefs adapterPrefs; public NodeHelper(AdapterPrefs adapterPrefs) { this.adapterPrefs = adapterPrefs; } private static final String KEYWORD_FDEL = "fdel"; private static final String KEYWORD_FSET = "fset"; private static final String KEYWORD_FGET = "fget"; private static final String EMPTY = ""; public static final String KEYWORD_INIT = "__init__"; private static final String KEYWORD_NONE = "None"; private static final String KEYWORD_PROPERTY = "property"; public static final String KEYWORD_SELF = "self"; private static final String PREFIX_PRIVATE = "__"; public static final int ACCESS_PUBLIC = 1; public static final int ACCESS_PSEUDO = 2; public static final int ACCESS_PRIVATE = 3; public String getAccessName(String name, int modifier) { switch (modifier) { case ACCESS_PSEUDO: return getPseudoAttr(name); case ACCESS_PRIVATE: return getPrivateAttr(name); default: return getPublicAttr(name); } } private String getFromName(SimpleNode node) { if (!isName(node)) { return EMPTY; } return ((Name) node).id; } private String getFromNameTok(SimpleNode node) { if (node == null) { return ""; } if (!isNameTok(node)) { return EMPTY; } return ((NameTok) node).id; } private String getFromStr(SimpleNode node) { if (!isStr(node)) { return EMPTY; } return ((Str) node).s; } public int getLineDefinition(SimpleNode node) { while (isAttribute(node)) { exprType expr = ((Attribute) node).value; if (!(isCall(expr))) { node = expr; } else { break; } } if (isFunctionDef(node)) { return ((FunctionDef) node).name.beginLine; } return node.beginLine; } public int getLineEnd(SimpleNode node) { if (node == null) { return 0; } if (isStr(node)) { String s = ((Str) node).s; int found = 0; for (int i = 0; i < s.length(); i++) { if (s.charAt(i) == '\n') { found += 1; } } return getLineDefinition(node) + found; } return getLineDefinition(node); } public String getName(SimpleNode node) { if (node instanceof NameTok) { return getFromNameTok(node); } else if (node instanceof Name) { return getFromName(node); } else if (node instanceof Str) { return getFromStr(node); } else if (node instanceof ClassDef) { return getName(((ClassDef) node).name); } else if (node instanceof FunctionDef) { return getName(((FunctionDef) node).name); } else if (node instanceof Call) { return getName(((Call) node).func); } else if (node instanceof Attribute) { String attributeName = NodeUtils.getFullRepresentationString(node); int subscriptOffset = attributeName.indexOf("["); if (subscriptOffset > 0) { attributeName = attributeName.substring(0, subscriptOffset - 1); } return attributeName.trim(); } return EMPTY; } public String getPrivateAttr(String attributeName) { String privateAttr = getPublicAttr(attributeName); return "__" + privateAttr; } private int getPropertyMethods(exprType[] args) { if (args == null || args.length == 0) { return 0; } int propertyMethods = args.length; exprType lastExpr = args[args.length - 1]; if (isStr(lastExpr)) { propertyMethods -= 1; } return propertyMethods; } public String getPseudoAttr(String attributeName) { String pseudoAttr = getPublicAttr(attributeName); return "_" + pseudoAttr; } public String getPublicAttr(String attributeName) { String publicAttr = attributeName; while (publicAttr.startsWith("_")) { publicAttr = publicAttr.substring(1); } return publicAttr; } public int getStartLine(SimpleNode n) { return n.beginLine; } public int getStartOffset(SimpleNode n) { return n.beginColumn; } public boolean hasFunctionArgument(SimpleNode node) { return isFunctionDef(node) || isLambda(node); } public boolean isAssign(SimpleNode node) { return node instanceof Assign; } public boolean isAttribute(SimpleNode node) { return node instanceof Attribute; } public boolean isBoolOp(SimpleNode node) { return node instanceof BoolOp; } public boolean isCall(SimpleNode node) { return node instanceof Call; } public boolean isClassDef(SimpleNode node) { return node instanceof ClassDef; } public boolean isComprehension(SimpleNode node) { return node instanceof Comprehension; } public boolean isConstant(String id) { return id.toUpperCase().equals(id); } public boolean isContextNameParentName(String contextName, SimpleNode node) { return contextName.equals(getName(node)); } public boolean isControlStatement(SimpleNode node) { return isForStatement(node) || isWhileStatement(node) || isWithStatement(node) || isTryExceptStatement(node) || isTryFinallyStatement(node) || isIfStatement(node); } public boolean isDict(SimpleNode node) { return node instanceof Dict; } public boolean isEmptyList(SimpleNode[] list) { return (list == null) || (list.length == 0); } public boolean isFDel(keywordType kw) { return isKeywordName(kw, KEYWORD_FDEL) && !(isNone(kw.value)); } public boolean isFGet(keywordType kw) { return isKeywordName(kw, KEYWORD_FGET) && !(isNone(kw.value)); } public boolean isFilledList(SimpleNode[] list) { return !isEmptyList(list); } public boolean isForStatement(SimpleNode node) { return node instanceof For; } public boolean isFSet(keywordType kw) { return isKeywordName(kw, KEYWORD_FSET) && !(isNone(kw.value)); } public boolean isFullyQualified(SimpleNode contextNode, SimpleNode parent) { return isContextNameParentName(getName(contextNode), parent) || isSelf(getName(contextNode)); } public boolean isFunctionArgument(SimpleNode node) { return node instanceof argumentsType; } public boolean isFunctionDef(SimpleNode node) { return node instanceof FunctionDef; } public boolean isFunctionOrClassDef(SimpleNode node) { return isClassDef(node) || isFunctionDef(node); } public boolean isIfStatement(SimpleNode node) { return node instanceof If; } public boolean isInit(SimpleNode node) { return isFunctionDef(node) && getName(node).equals(KEYWORD_INIT); } public boolean isKeyword(SimpleNode node) { return node instanceof keywordType; } private boolean isKeywordName(keywordType kw, String name) { return getName(kw.arg).equals(name) && isName(kw.value); } public boolean isKeywordStr(keywordType kw) { return getName(kw.arg).equals("doc") && isStr(kw.value); } public boolean isLambda(SimpleNode node) { return node instanceof Lambda; } public boolean isList(SimpleNode node) { return node instanceof List; } public boolean isName(SimpleNode node) { return node instanceof Name; } public boolean isNameTok(SimpleNode node) { return node instanceof NameTok; } public boolean isNone(SimpleNode node) { return isName(node) && KEYWORD_NONE.equals(getName(node)); } public boolean isPrivate(SimpleNode node) { return isPrivate(getName(node)); } public boolean isPrivate(String name) { return name.startsWith(PREFIX_PRIVATE); } public boolean isProperty(Call node) { return getName(node).equals(KEYWORD_PROPERTY) && isValidPropertyCall(node); } public boolean isPropertyAssign(Assign node) throws Exception { if (isFilledList(node.targets) && node.targets.length == 1) { if (isName(node.targets[0])) { if (isCall(node.value)) { return isProperty((Call) node.value); } } } return false; } public boolean isPropertyDecorator(decoratorsType dec) { return getName(dec.func).equals(KEYWORD_PROPERTY); } private boolean isPropertyVar(keywordType kw) { return isFGet(kw) || isFSet(kw) || isFDel(kw); } public boolean isSelf(String id) { return KEYWORD_SELF.equals(id); } public boolean isSpecialStr(Object o) { return o instanceof ISpecialStr; } public boolean isStr(SimpleNode node) { return node instanceof Str; } public boolean isTryExceptStatement(SimpleNode node) { return node instanceof TryExcept; } public boolean isTryFinallyStatement(SimpleNode node) { return node instanceof TryFinally; } public boolean isTryStatement(SimpleNode node) { return isTryExceptStatement(node) || isTryFinallyStatement(node); } public boolean isTuple(SimpleNode node) { return node instanceof Tuple; } private boolean isValidPropertyCall(Call node) { exprType[] args = node.args; keywordType[] kws = node.keywords; int len = args.length + kws.length; if (len > 4) { return false; } return validatePropertyArguments(node); } private boolean isValidPropertyKeyword(keywordType[] keywords) { if (keywords != null) { boolean valid = false; for (keywordType kw : keywords) { valid = isKeywordStr(kw) || isPropertyVar(kw); if (!(valid)) { return false; } } return true; } return false; } public boolean isWhileStatement(SimpleNode node) { return node instanceof While; } public boolean isWithStatement(SimpleNode node) { return node instanceof With; } public boolean isImport(SimpleNode node) { return node instanceof ImportFrom || node instanceof Import; } private boolean validatePropertyArguments(Call node) { exprType[] args = node.args; if (isValidPropertyKeyword(node.keywords)) { int propertyMethods = getPropertyMethods(args); if (propertyMethods == 0) { return true; } for (int i = 0; i < propertyMethods; i++) { if (isName(args[i])) { return true; } } } return false; } public java.util.List<String> getBaseClassName(SimpleNode node) { java.util.List<String> bases = new ArrayList<String>(); if (isClassDef(node)) { ClassDef clazz = (ClassDef) node; if (isFilledList(clazz.bases)) { for (exprType base : clazz.bases) { bases.add(getName(base)); } } } return bases; } public boolean hasSelfArgument(exprType[] args) { for (exprType arg : args) { if (isSelf(getName(arg))) { return true; } } return false; } public boolean isModule(SimpleNode node) { return node instanceof Module; } /** * Pretty-print the given AST node to stdout. * * @param node */ public static void prettyPrint(SimpleNode node) { System.out.println(getPrettyPrinted(node)); } /** * Returns a pretty-printed given ast * * @param node top-level node * @return string containing the human-readable ast */ public static String getPrettyPrinted(SimpleNode node) { String str = node.toString(); StringBuffer out = new StringBuffer(); int level = 0; boolean skipSpace = false; for (int i = 0; i < str.length(); i++) { char c = str.charAt(i); if (c == '[') { out.append(""); out.append("\n"); level++; printIdent(out, level); } else if (c == ',') { out.append(c); out.append("\n"); printIdent(out, level); skipSpace = true; } else if (c == ' ' && skipSpace) { skipSpace = false; } else if (c == ']') { level--; out.append("\n"); printIdent(out, level); //out.append("]"); } else if (c == '=') { out.append(" = "); } else { out.append(c); } } return out.toString(); } private static void printIdent(StringBuffer out, int level) { for (int i = 0; i < level; i++) { out.append("| "); } } public AdapterPrefs getAdapterPrefs() { return this.adapterPrefs; } public int getFirstLineConsideringDecorators(SimpleNode node) { decoratorsType[] decs = null; if (node instanceof FunctionDef) { FunctionDef functionDef = (FunctionDef) node; decs = functionDef.decs; } else if (node instanceof ClassDef) { ClassDef classDef = (ClassDef) node; decs = classDef.decs; } if (decs != null && decs.length > 0) { for (decoratorsType dec : decs) { return dec.beginLine; } } return node.beginLine; } }