/******************************************************************************
* Copyright (C) 2006-2013 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.refactoring.ast.visitors;
import java.io.File;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextSelection;
import org.python.pydev.core.IGrammarVersionProvider;
import org.python.pydev.core.IModule;
import org.python.pydev.core.IModulesManager;
import org.python.pydev.core.IPythonNature;
import org.python.pydev.core.ISourceModule;
import org.python.pydev.core.MisconfigurationException;
import org.python.pydev.editor.codecompletion.revisited.modules.SourceModule;
import org.python.pydev.parser.PyParser;
import org.python.pydev.parser.jython.ParseException;
import org.python.pydev.parser.jython.SimpleNode;
import org.python.pydev.parser.jython.TokenMgrError;
import org.python.pydev.parser.jython.ast.Module;
import org.python.pydev.parser.jython.ast.VisitorIF;
import org.python.pydev.parser.jython.ast.exprType;
import org.python.pydev.refactoring.ast.PythonModuleManager;
import org.python.pydev.refactoring.ast.adapters.AbstractNodeAdapter;
import org.python.pydev.refactoring.ast.adapters.AbstractScopeNode;
import org.python.pydev.refactoring.ast.adapters.ModuleAdapter;
import org.python.pydev.refactoring.ast.visitors.context.AbstractContextVisitor;
import org.python.pydev.refactoring.ast.visitors.selection.SelectionException;
import org.python.pydev.refactoring.ast.visitors.selection.SelectionExtenderVisitor;
import org.python.pydev.refactoring.ast.visitors.selection.SelectionValidationVisitor;
import org.python.pydev.shared_core.io.FileUtils;
import org.python.pydev.shared_core.parsing.BaseParser.ParseOutput;
import org.python.pydev.ui.filetypes.FileTypesPreferencesPage;
public final class VisitorFactory {
private VisitorFactory() {
}
public static ITextSelection createSelectionExtension(AbstractScopeNode<?> scope, ITextSelection selection) {
SelectionExtenderVisitor visitor = null;
try {
visitor = new SelectionExtenderVisitor(scope.getModule(), selection);
scope.getASTNode().accept(visitor);
} catch (Exception e) {
throw new RuntimeException(e);
}
return visitor.getSelection();
}
public static void validateSelection(ModuleAdapter scope) throws SelectionException {
SelectionValidationVisitor visitor = null;
try {
visitor = new SelectionValidationVisitor();
scope.getASTNode().accept(visitor);
} catch (SelectionException e) {
throw e;
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
public static <T extends VisitorIF> T createVisitor(Class<T> visitorClass, String source,
IGrammarVersionProvider versionProvider) throws Throwable {
return createVisitor(visitorClass, getRootNodeFromString(source, versionProvider));
}
public static <T extends VisitorIF> T createVisitor(Class<T> visitorClass, SimpleNode root) {
T visitor = null;
try {
visitor = visitorClass.newInstance();
root.accept(visitor);
} catch (Throwable e) {
throw new RuntimeException(e);
}
return visitor;
}
/**
* Unchecked (because if doing Class.cast, it does not work in java 1.4)
*/
@SuppressWarnings("unchecked")
public static <T extends AbstractContextVisitor> T createContextVisitor(Class<T> visitorClass, SimpleNode root,
ModuleAdapter module, AbstractNodeAdapter parent) {
try {
T visitor = (T) visitorClass.getConstructors()[0].newInstance(new Object[] { module, parent });
root.accept(visitor);
return visitor;
} catch (Exception e) {
throw new CannotCreateContextRuntimeException(e);
}
}
public static ModuleAdapter createModuleAdapter(PythonModuleManager pythonModuleManager, File file, IDocument doc,
IPythonNature nature, IGrammarVersionProvider versionProvider) throws Throwable {
if (file != null && file.exists()) {
if (FileTypesPreferencesPage.isCythonFile(file.getName())) {
versionProvider = new IGrammarVersionProvider() {
@Override
public int getGrammarVersion() throws MisconfigurationException {
return IPythonNature.GRAMMAR_PYTHON_VERSION_CYTHON;
}
@Override
public AdditionalGrammarVersionsToCheck getAdditionalGrammarVersions()
throws MisconfigurationException {
return null;
}
};
}
if (pythonModuleManager != null) {
IModulesManager modulesManager = pythonModuleManager.getIModuleManager();
if (modulesManager != null) {
String modName = modulesManager.resolveModule(FileUtils.getFileAbsolutePath(file));
if (modName != null) {
IModule module = modulesManager.getModule(modName, nature, true);
if (module instanceof ISourceModule) {
SourceModule iSourceModule = (SourceModule) module;
if (iSourceModule.parseError != null) {
throw iSourceModule.parseError;
}
return new ModuleAdapter(pythonModuleManager, ((ISourceModule) module), nature, doc);
}
}
}
}
}
return new ModuleAdapter(pythonModuleManager, file, doc, getRootNode(doc, versionProvider), nature);
}
public static SimpleNode getRootNodeFromString(String source, IGrammarVersionProvider versionProvider)
throws ParseException, MisconfigurationException {
return getRootNode(getDocumentFromString(source), versionProvider);
}
private static IDocument getDocumentFromString(String source) {
return new Document(source);
}
public static Module getRootNode(IDocument doc, IGrammarVersionProvider versionProvider) throws ParseException,
MisconfigurationException {
ParseOutput objects = PyParser.reparseDocument(new PyParser.ParserInfo(doc, versionProvider));
Throwable exception = objects.error;
if (exception != null) {
/* We try to get rid of the 'Throwable' exception, if possible */
if (exception instanceof ParseException) {
throw (ParseException) exception;
} else if (exception instanceof TokenMgrError) {
/* Error from Lexer */
throw new ParseException(exception.toString());
} else {
throw new RuntimeException(exception);
}
}
if (objects.error != null) {
throw new RuntimeException(objects.error);
}
return (Module) objects.ast;
}
/**
* Provides a way to find duplicates of a given expression.
*/
public static FindDuplicatesVisitor createDuplicatesVisitor(ITextSelection selection, SimpleNode nodeToVisit,
exprType expression, AbstractScopeNode node, IDocument doc) {
FindDuplicatesVisitor visitor = new FindDuplicatesVisitor(selection, expression, doc);
try {
nodeToVisit.accept(visitor);
visitor.finish();
} catch (Throwable e) {
throw new RuntimeException(e);
}
return visitor;
}
}