blob: 991de02551a43586b3650395b82249c866b61914 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2019 Xored Software Inc and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Xored Software Inc - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.rcptt.core.search.tags;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.MismatchedTokenException;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.TokenStream;
import org.antlr.runtime.tree.CommonTree;
import org.eclipse.rcptt.core.model.IQ7NamedElement;
import org.eclipse.rcptt.core.model.search.Q7SearchCore;
import org.eclipse.rcptt.core.search.tags.parser.TagsLexer;
import org.eclipse.rcptt.core.search.tags.parser.TagsParser;
public class TagsSearch {
private static List<RecognitionException> errors = new ArrayList<RecognitionException>();
/**
* Finds IQ7Elements by tags expression.
*
* E.g.: tag1 OR ("tag 2" AND !tag3)
*
* @param expression
* @return
*/
public static IQ7NamedElement[] findAllByExpression(String expression) {
CommonTree tree = createTree(expression);
if (tree == null) {
return new IQ7NamedElement[0];
}
List<IQ7NamedElement> result = new ArrayList<IQ7NamedElement>();
Map<IQ7NamedElement, List<String>> tagsRefsMap = Q7SearchCore.findAllTagReferences();
for (Map.Entry<IQ7NamedElement, List<String>> entry : tagsRefsMap.entrySet()) {
if (eval(tree, entry.getValue())) {
result.add(entry.getKey());
}
}
return result.toArray(new IQ7NamedElement[result.size()]);
}
/**
* Creates boolean AST.
*
* @param expression
* @return
*/
private static CommonTree createTree(String expression) {
CommonTree ast = null;
errors.clear();
try {
ANTLRStringStream input = new ANTLRStringStream(expression);
TagsLexer lexer = new TagsLexer(input);
TokenStream tokens = new CommonTokenStream(lexer);
TagsParser parser = new TagsParser(tokens);
TagsParser.expression_return ret = parser.expression();
ast = (CommonTree) ret.getTree();
if (lexer.hasErrors())
errors.addAll(lexer.getAllErrors());
if (parser.hasErrors())
errors.addAll(parser.getAllErrors());
} catch (RecognitionException e) {
}
return ast;
}
/**
* @return All errors found during last run.
*/
public static List<RecognitionException> getAllErrors() {
return errors;
}
/**
* Checks if parentheses are not correct during last run.
*
* @return
*/
public static boolean isParenthesesMissed() {
for (RecognitionException e : getAllErrors()) {
if (e instanceof MismatchedTokenException) {
MismatchedTokenException mte = (MismatchedTokenException) e;
if (mte.expecting == TagsParser.LPAREN || mte.expecting == TagsParser.RPAREN) {
return true;
}
}
}
return false;
}
/**
* Evaluates boolean AST.
*
* @param tree
* @param tags
* @return
*/
private static boolean eval(CommonTree tree, List<String> tags) {
if (tree != null) {
if (tree.getType() == TagsParser.NAME) {
if (tags.contains(tree.getText())) {
return true;
} else {
return false;
}
}
if (tree.getType() == TagsParser.NOT && tree.getChildren() != null) {
return !eval((CommonTree) tree.getChild(0), tags);
}
if (tree.getType() == TagsParser.AND && tree.getChildren() != null) {
boolean result = true;
for (Object subtree : tree.getChildren()) {
if (eval((CommonTree) subtree, tags) == false) {
result = false;
break;
}
}
return result;
}
if (tree.getType() == TagsParser.OR && tree.getChildren() != null) {
boolean result = false;
for (Object subtree : tree.getChildren()) {
if (eval((CommonTree) subtree, tags) == true) {
result = true;
break;
}
}
return result;
}
}
return false;
}
/**
* For debug purposes.
*
* @param ast
*/
private static void printTree(CommonTree ast) {
print(ast, 0);
}
/**
* For debug purposes.
*
* @param tree
* @param level
*/
private static void print(CommonTree tree, int level) {
for (int i = 0; i < level; i++)
System.out.print("--");
if (tree == null) {
System.out.println(" null tree");
return ;
}
System.out.println(" " + tree.getType() + " " + tree.getText());
if (tree.getChildren() != null) {
for (Object ie : tree.getChildren()) {
print((CommonTree) ie, level + 1);
}
}
}
}