/* | |
* Licensed to the Apache Software Foundation (ASF) under one | |
* or more contributor license agreements. See the NOTICE file | |
* distributed with this work for additional information | |
* regarding copyright ownership. The ASF licenses this file | |
* to you under the Apache License, Version 2.0 (the | |
* "License"); you may not use this file except in compliance | |
* with the License. You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, | |
* software distributed under the License is distributed on an | |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
* KIND, either express or implied. See the License for the | |
* specific language governing permissions and limitations | |
* under the License. | |
*/ | |
package org.apache.uima.ruta.ide.core.codeassist; | |
import java.io.File; | |
import java.io.IOException; | |
import java.util.ArrayList; | |
import java.util.HashMap; | |
import java.util.HashSet; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.Set; | |
import org.apache.commons.lang3.StringUtils; | |
import org.apache.uima.UIMAFramework; | |
import org.apache.uima.resource.metadata.TypeDescription; | |
import org.apache.uima.resource.metadata.TypeSystemDescription; | |
import org.apache.uima.ruta.engine.RutaEngine; | |
import org.apache.uima.ruta.ide.core.builder.RutaProjectUtils; | |
import org.apache.uima.ruta.ide.core.parser.RutaParseUtils; | |
import org.apache.uima.ruta.ide.parser.ast.RutaActionConstants; | |
import org.apache.uima.ruta.ide.parser.ast.RutaImportStatement; | |
import org.apache.uima.ruta.ide.parser.ast.RutaStatementConstants; | |
import org.apache.uima.util.InvalidXMLException; | |
import org.apache.uima.util.XMLInputSource; | |
import org.eclipse.core.resources.IFile; | |
import org.eclipse.core.resources.IFolder; | |
import org.eclipse.core.runtime.IPath; | |
import org.eclipse.dltk.ast.ASTVisitor; | |
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.references.SimpleReference; | |
import org.eclipse.dltk.ast.references.VariableReference; | |
import org.eclipse.dltk.ast.statements.Statement; | |
import org.eclipse.dltk.codeassist.ScriptSelectionEngine; | |
import org.eclipse.dltk.compiler.env.IModuleSource; | |
import org.eclipse.dltk.core.DLTKCore; | |
import org.eclipse.dltk.core.IDLTKLanguageToolkit; | |
import org.eclipse.dltk.core.IField; | |
import org.eclipse.dltk.core.IMethod; | |
import org.eclipse.dltk.core.IModelElement; | |
import org.eclipse.dltk.core.IModelElementVisitor; | |
import org.eclipse.dltk.core.IOpenable; | |
import org.eclipse.dltk.core.IScriptFolder; | |
import org.eclipse.dltk.core.IScriptProject; | |
import org.eclipse.dltk.core.ModelException; | |
public class RutaSelectionEngine extends ScriptSelectionEngine { | |
private class ModelElementFinder extends ASTVisitor { | |
private int offset; | |
private List results; | |
private Set<String> engines; | |
private Set<String> typesystems; | |
private Map<String, org.eclipse.dltk.core.ISourceModule> scripts; | |
private Map<String, IField> impFields; | |
private String curFileName; | |
public ModelElementFinder(int offset, List results, String curFileName) { | |
super(); | |
this.offset = offset; | |
this.results = results; | |
this.engines = new HashSet<String>(); | |
this.typesystems = new HashSet<String>(); | |
this.scripts = new HashMap<String, org.eclipse.dltk.core.ISourceModule>(); | |
this.impFields = new HashMap<String, IField>(); | |
this.curFileName = curFileName; | |
try { | |
importScript(parseFileName(curFileName)); | |
} catch (Exception e) { | |
} | |
} | |
private String parseFileName(String curFileName2) { | |
int i = curFileName2.indexOf("script"); | |
String s = curFileName2.substring(i + "scripts".length() - 1); | |
s = s.replace('/', '.'); | |
if (s.endsWith(RutaEngine.SCRIPT_FILE_EXTENSION)) { | |
s = s.substring(1, s.length() - 5); | |
} | |
return s; | |
} | |
@Override | |
public boolean visit(Statement s) throws Exception { | |
if (s instanceof RutaImportStatement) { | |
// handle engine imports | |
if (((RutaImportStatement) s).getType() == RutaStatementConstants.S_IMPORT_ENGINE) { | |
SimpleReference sRef = (SimpleReference) ((RutaImportStatement) s).getExpression(); | |
importEngine(sRef.getName()); | |
} | |
if (((RutaImportStatement) s).getType() == RutaStatementConstants.S_IMPORT_ENGINE) { | |
SimpleReference sRef = (SimpleReference) ((RutaImportStatement) s).getExpression(); | |
importEngine(sRef.getName()); | |
} | |
// handle script imports | |
if (((RutaImportStatement) s).getType() == RutaStatementConstants.S_IMPORT_SCRIPT) { | |
importScript(s); | |
} | |
// handle type system imports | |
if (((RutaImportStatement) s).getType() == RutaStatementConstants.S_IMPORT_TYPESYSTEM) { | |
importTypesystem(s); | |
} | |
return false; | |
} | |
return true; | |
} | |
@Override | |
public boolean visit(Expression s) throws Exception { | |
if (s.sourceStart() <= offset && offset <= s.sourceEnd()) { | |
if (s instanceof VariableReference) { | |
VariableReference ref = (VariableReference) s; | |
// TODO refactor: extern declaration always checked, even if | |
// local decl found | |
String name = ((VariableReference) s).getName(); | |
findLocalDeclaration(name, results, IField.class); | |
if (impFields.containsKey(name)) { | |
results.add(impFields.get(name)); | |
} | |
} | |
if (s != null && s.getKind() == RutaActionConstants.A_CALL) { | |
SimpleReference sr = (SimpleReference) s.getChilds().get(0); | |
if (sr != null) { | |
String name = sr.getName(); | |
if (engines.contains(name)) { | |
// referenceEngineCall(name); | |
} else if (scripts.containsKey(name)) { | |
findImportedDeclaration(name, results, IMethod.class); | |
} else { | |
checkInnerBlockRef(name, ""); | |
name = name.substring(name.lastIndexOf('.') + 1); | |
findLocalDeclaration(name, results, IMethod.class); | |
} | |
} | |
} | |
} | |
return super.visit(s); | |
} | |
@Override | |
public boolean visit(MethodDeclaration s) throws Exception { | |
if (s.getNameStart() <= offset && offset <= s.getNameEnd()) { | |
findLocalDeclaration(s.getName(), results, IMethod.class); | |
} | |
return super.visit(s); | |
} | |
@Override | |
public boolean visit(TypeDeclaration s) throws Exception { | |
if (s.getNameStart() <= offset && offset <= s.getNameEnd()) { | |
findLocalDeclaration(s.getName(), results, IField.class); | |
// TODO ?? | |
} | |
return super.visit(s); | |
} | |
private void checkInnerBlockRef(String head, String tail) { | |
int li = head.lastIndexOf('.'); | |
if (li > 0) { | |
String frontPart = head.substring(0, li); | |
if (StringUtils.isEmpty(tail)) { | |
tail = head.substring(li + 1); | |
} | |
if (scripts.containsKey(frontPart)) { | |
findDeclaration(scripts.get(frontPart), tail, results, IMethod.class); | |
} else { | |
checkInnerBlockRef(frontPart, tail); | |
} | |
} | |
} | |
private void importEngine(String name) { | |
engines.add(name); | |
int i = name.lastIndexOf('.'); | |
if (i > 1) { | |
String lastPart = name.substring(i + 1); | |
if (lastPart != null && lastPart.length() != 0) { | |
engines.add(lastPart); | |
} | |
} | |
} | |
public IFile getFile(IFolder folder, String filePath) { | |
int lastDot = filePath.lastIndexOf('.'); | |
int sndLastDot = filePath.lastIndexOf('.', lastDot - 1); | |
String fName = filePath; | |
if (sndLastDot >= 0) { | |
String subFolder = filePath.substring(0, sndLastDot); | |
folder = folder.getFolder(subFolder); | |
fName = filePath.substring(sndLastDot + 1); | |
} | |
return folder.getFile(fName); | |
} | |
/** | |
* @param s | |
* @throws ModelException | |
*/ | |
private void importScript(Statement s) throws ModelException { | |
SimpleReference sRef = (SimpleReference) ((RutaImportStatement) s).getExpression(); | |
String sRefName = sRef.getName(); | |
importScript(sRefName); | |
} | |
private void importTypesystem(Statement s) { | |
SimpleReference sRef = (SimpleReference) ((RutaImportStatement) s).getExpression(); | |
// TODO not working yet | |
// importTypesystem(sRefName); | |
} | |
/** | |
* @param sRefName | |
* @throws ModelException | |
*/ | |
private void importScript(String sRefName) throws ModelException { | |
int lastDot = sRefName.lastIndexOf('.'); | |
String fileNameShort = sRefName.substring(lastDot + 1); | |
String fileName = fileNameShort + RutaEngine.SCRIPT_FILE_EXTENSION; | |
org.eclipse.dltk.core.ISourceModule sm = null; | |
IScriptFolder[] scriptFolders = sourceModule.getScriptProject().getScriptFolders(); | |
for (int i = 0; i < scriptFolders.length; i++) { | |
sm = scriptFolders[i].getSourceModule(fileName); | |
if (sm.exists() && sm.getResource() != null && sm.getResource().exists()) { | |
scripts.put(sRefName, sm); | |
scripts.put(fileNameShort, sm); | |
importFields(sm.getFields()); | |
break; | |
} | |
} | |
} | |
private void importFields(IField[] fields) { | |
if (fields == null) { | |
return; | |
} | |
for (int i = 0; i < fields.length; i++) { | |
if (fields[i] == null) { | |
continue; | |
} | |
IField iField = fields[i]; | |
IPath path = iField.getPath(); | |
String fullyQualifiedName = parseFileName(path.toString()); | |
impFields.put(iField.getElementName(), iField); | |
impFields.put(fullyQualifiedName + "." + iField.getElementName(), iField); | |
} | |
} | |
@SuppressWarnings("unchecked") | |
private void findImportedDeclaration(final String name, final List results, final Class type) { | |
org.eclipse.dltk.core.ISourceModule module = this.scripts.get(name); | |
if (module != null && module.exists()) { | |
results.add(module); | |
// findDeclaration(module, name, results, type); | |
} | |
} | |
@SuppressWarnings("unchecked") | |
private void findDeclaration(org.eclipse.dltk.core.ISourceModule sm, final String name, | |
final List results, final Class type) { | |
try { | |
sm.accept(new IModelElementVisitor() { | |
public boolean visit(IModelElement element) { | |
Class e = element.getClass(); | |
boolean classCheck = type.isAssignableFrom(e); | |
if (element.getElementName().equals(name) && classCheck) { | |
results.add(element); | |
return false; | |
} | |
return true; | |
} | |
}); | |
} catch (ModelException e) { | |
if (DLTKCore.DEBUG) { | |
e.printStackTrace(); | |
} | |
} | |
} | |
@SuppressWarnings("unchecked") | |
private void findLocalDeclaration(final String name, final List results, final Class type) { | |
try { | |
sourceModule.accept(new IModelElementVisitor() { | |
public boolean visit(IModelElement element) { | |
Class e = element.getClass(); | |
boolean classCheck = type.isAssignableFrom(e); | |
if (element.getElementName().equals(name) && classCheck) { | |
results.add(element); | |
} | |
return true; | |
} | |
}); | |
} catch (ModelException e) { | |
if (DLTKCore.DEBUG) { | |
e.printStackTrace(); | |
} | |
} | |
} | |
} | |
public static boolean DEBUG = DLTKCore.DEBUG_SELECTION; | |
protected int actualSelectionStart; | |
protected int actualSelectionEnd; | |
protected List selectionElements = new ArrayList(); | |
protected RutaSelectionParser parser = new RutaSelectionParser(); | |
protected org.eclipse.dltk.core.ISourceModule sourceModule; | |
protected IDLTKLanguageToolkit toolkit; | |
public IModelElement[] select(IModuleSource module, final int offset, int i) { | |
sourceModule = (org.eclipse.dltk.core.ISourceModule) module.getModelElement(); | |
ModuleDeclaration moduleDeclaration = this.parser.parse(module); | |
final List results = new ArrayList(); | |
try { | |
moduleDeclaration.traverse(new ModelElementFinder(offset, results, module.getFileName())); | |
} catch (Exception e) { | |
if (DLTKCore.DEBUG) { | |
e.printStackTrace(); | |
} | |
} | |
return (IModelElement[]) results.toArray(new IModelElement[results.size()]); | |
} | |
protected boolean checkSelection(String source, int selectionSourceStart, int selectionSourceEnd) { | |
boolean cheat = false; | |
if (selectionSourceEnd < selectionSourceStart) { | |
selectionSourceEnd = selectionSourceStart; | |
cheat = true; | |
} | |
int start = RutaParseUtils.startLineOrNoSymbol(selectionSourceStart, source); | |
int end = RutaParseUtils.endLineOrNoSymbol(selectionSourceEnd, source); | |
if (end <= start) { | |
if (cheat) | |
return checkSelection(source, selectionSourceEnd - 1, selectionSourceEnd - 1); | |
return false; | |
} | |
if (start > source.length() || end > source.length()) { | |
if (cheat) | |
return checkSelection(source, selectionSourceEnd - 1, selectionSourceEnd - 1); | |
return false; | |
} | |
String sub = source.substring(start, end); | |
// If contain tabs or spaces, then from start. | |
if ((sub.indexOf(' ') != -1 || sub.indexOf('\t') != -1 || sub.indexOf('\n') != -1)) { | |
if (cheat) | |
return checkSelection(source, selectionSourceEnd - 1, selectionSourceEnd - 1); | |
return false; | |
} | |
this.actualSelectionStart = start; | |
this.actualSelectionEnd = end; | |
return true; | |
} | |
} |